s3: Add some const to find_oplock_types
[kai/samba.git] / source4 / smbd / process_standard.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    process model: standard (1 process per client connection)
5
6    Copyright (C) Andrew Tridgell 1992-2005
7    Copyright (C) James J Myers 2003 <myersjj@samba.org>
8    Copyright (C) Stefan (metze) Metzmacher 2004
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "lib/events/events.h"
26 #include "smbd/process_model.h"
27 #include "system/filesys.h"
28 #include "cluster/cluster.h"
29 #include "param/param.h"
30 #include "ldb_wrap.h"
31
32 #ifdef HAVE_SETPROCTITLE
33 #ifdef HAVE_SETPROCTITLE_H
34 #include <setproctitle.h>
35 #endif
36 #else
37 #define setproctitle none_setproctitle
38 static int none_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
39 static int none_setproctitle(const char *fmt, ...)
40 {
41         return 0;
42 }
43 #endif
44
45 NTSTATUS process_model_standard_init(void);
46
47 /* we hold a pipe open in the parent, and the any child
48    processes wait for EOF on that pipe. This ensures that
49    children die when the parent dies */
50 static int child_pipe[2];
51
52 /*
53   called when the process model is selected
54 */
55 static void standard_model_init(void)
56 {
57         pipe(child_pipe);
58         signal(SIGCHLD, SIG_IGN);
59 }
60
61 /*
62   handle EOF on the child pipe
63 */
64 static void standard_pipe_handler(struct tevent_context *event_ctx, struct tevent_fd *fde, 
65                                   uint16_t flags, void *private_data)
66 {
67         DEBUG(10,("Child %d exiting\n", (int)getpid()));
68         exit(0);
69 }
70
71 /*
72   called when a listening socket becomes readable. 
73 */
74 static void standard_accept_connection(struct tevent_context *ev, 
75                                        struct loadparm_context *lp_ctx,
76                                        struct socket_context *sock, 
77                                        void (*new_conn)(struct tevent_context *,
78                                                         struct loadparm_context *, struct socket_context *, 
79                                                         struct server_id , void *), 
80                                        void *private_data)
81 {
82         NTSTATUS status;
83         struct socket_context *sock2;
84         pid_t pid;
85         struct socket_address *c, *s;
86
87         /* accept an incoming connection. */
88         status = socket_accept(sock, &sock2);
89         if (!NT_STATUS_IS_OK(status)) {
90                 DEBUG(0,("standard_accept_connection: accept: %s\n",
91                          nt_errstr(status)));
92                 /* this looks strange, but is correct. We need to throttle things until
93                    the system clears enough resources to handle this new socket */
94                 sleep(1);
95                 return;
96         }
97
98         pid = fork();
99
100         if (pid != 0) {
101                 /* parent or error code ... */
102                 talloc_free(sock2);
103                 /* go back to the event loop */
104                 return;
105         }
106
107         pid = getpid();
108
109         /* This is now the child code. We need a completely new event_context to work with */
110
111         if (tevent_re_initialise(ev) != 0) {
112                 smb_panic("Failed to re-initialise tevent after fork");
113         }
114
115         /* this will free all the listening sockets and all state that
116            is not associated with this new connection */
117         talloc_free(sock);
118
119         /* we don't care if the dup fails, as its only a select()
120            speed optimisation */
121         socket_dup(sock2);
122                         
123         /* tdb needs special fork handling */
124         ldb_wrap_fork_hook();
125
126         tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ,
127                       standard_pipe_handler, NULL);
128         close(child_pipe[1]);
129
130         /* Ensure that the forked children do not expose identical random streams */
131         set_need_random_reseed();
132
133         /* setup the process title */
134         c = socket_get_peer_addr(sock2, ev);
135         s = socket_get_my_addr(sock2, ev);
136         if (s && c) {
137                 setproctitle("conn c[%s:%u] s[%s:%u] server_id[%d]",
138                              c->addr, c->port, s->addr, s->port, (int)pid);
139         }
140         talloc_free(c);
141         talloc_free(s);
142
143         /* setup this new connection.  Cluster ID is PID based for this process modal */
144         new_conn(ev, lp_ctx, sock2, cluster_id(pid, 0), private_data);
145
146         /* we can't return to the top level here, as that event context is gone,
147            so we now process events in the new event context until there are no
148            more to process */      
149         tevent_loop_wait(ev);
150
151         talloc_free(ev);
152         exit(0);
153 }
154
155 /*
156   called to create a new server task
157 */
158 static void standard_new_task(struct tevent_context *ev, 
159                               struct loadparm_context *lp_ctx,
160                               const char *service_name,
161                               void (*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *),
162                               void *private_data)
163 {
164         pid_t pid;
165
166         pid = fork();
167
168         if (pid != 0) {
169                 /* parent or error code ... go back to the event loop */
170                 return;
171         }
172
173         pid = getpid();
174
175         /* this will free all the listening sockets and all state that
176            is not associated with this new connection */
177         if (tevent_re_initialise(ev) != 0) {
178                 smb_panic("Failed to re-initialise tevent after fork");
179         }
180
181         /* ldb/tdb need special fork handling */
182         ldb_wrap_fork_hook();
183
184         tevent_add_fd(ev, ev, child_pipe[0], TEVENT_FD_READ,
185                       standard_pipe_handler, NULL);
186         close(child_pipe[1]);
187
188         /* Ensure that the forked children do not expose identical random streams */
189         set_need_random_reseed();
190
191         setproctitle("task %s server_id[%d]", service_name, (int)pid);
192
193         /* setup this new task.  Cluster ID is PID based for this process modal */
194         new_task(ev, lp_ctx, cluster_id(pid, 0), private_data);
195
196         /* we can't return to the top level here, as that event context is gone,
197            so we now process events in the new event context until there are no
198            more to process */      
199         tevent_loop_wait(ev);
200
201         talloc_free(ev);
202         exit(0);
203 }
204
205
206 /* called when a task goes down */
207 _NORETURN_ static void standard_terminate(struct tevent_context *ev, struct loadparm_context *lp_ctx,
208                                           const char *reason) 
209 {
210         DEBUG(2,("standard_terminate: reason[%s]\n",reason));
211
212         talloc_free(ev);
213
214         /* this reload_charcnv() has the effect of freeing the iconv context memory,
215            which makes leak checking easier */
216         reload_charcnv(lp_ctx);
217
218         /* terminate this process */
219         exit(0);
220 }
221
222 /* called to set a title of a task or connection */
223 static void standard_set_title(struct tevent_context *ev, const char *title) 
224 {
225         if (title) {
226                 setproctitle("%s", title);
227         } else {
228                 setproctitle(NULL);
229         }
230 }
231
232 static const struct model_ops standard_ops = {
233         .name                   = "standard",
234         .model_init             = standard_model_init,
235         .accept_connection      = standard_accept_connection,
236         .new_task               = standard_new_task,
237         .terminate              = standard_terminate,
238         .set_title              = standard_set_title,
239 };
240
241 /*
242   initialise the standard process model, registering ourselves with the process model subsystem
243  */
244 NTSTATUS process_model_standard_init(void)
245 {
246         return register_process_model(&standard_ops);
247 }