2 Unix SMB/CIFS implementation.
4 process model: standard (1 process per client connection)
6 Copyright (C) Andrew Tridgell 1992-2005
7 Copyright (C) James J Myers 2003 <myersjj@samba.org>
8 Copyright (C) Stefan (metze) Metzmacher 2004
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.
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.
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/>.
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"
32 struct standard_child_state
{
37 struct tevent_fd
*from_child_fde
;
40 NTSTATUS
process_model_standard_init(void);
42 /* we hold a pipe open in the parent, and the any child
43 processes wait for EOF on that pipe. This ensures that
44 children die when the parent dies */
45 static int child_pipe
[2] = { -1, -1 };
48 called when the process model is selected
50 static void standard_model_init(void)
54 rc
= pipe(child_pipe
);
56 smb_panic("Failed to initialze pipe!");
61 handle EOF on the parent-to-all-children pipe in the child
63 static void standard_pipe_handler(struct tevent_context
*event_ctx
, struct tevent_fd
*fde
,
64 uint16_t flags
, void *private_data
)
66 DEBUG(10,("Child %d exiting\n", (int)getpid()));
71 handle EOF on the child pipe in the parent, so we know when a
72 process terminates without using SIGCHLD or waiting on all possible pids.
74 We need to ensure we do not ignore SIGCHLD because we need it to
75 work to get a valid error code from samba_runcmd_*().
77 static void standard_child_pipe_handler(struct tevent_context
*ev
,
78 struct tevent_fd
*fde
,
82 struct standard_child_state
*state
83 = talloc_get_type_abort(private_data
, struct standard_child_state
);
87 /* the child has closed the pipe, assume its dead */
89 pid
= waitpid(state
->pid
, &status
, 0);
91 if (pid
!= state
->pid
) {
92 if (errno
== ECHILD
) {
94 * this happens when the
95 * parent has set SIGCHLD to
96 * SIG_IGN. In that case we
98 * information for the child
99 * via its logging. We should
100 * stop using SIG_IGN on
101 * SIGCHLD in the standard
104 DEBUG(0, ("Error in waitpid() unexpectedly got ECHILD "
105 "for child %d (%s) - %s, someone has set SIGCHLD "
107 (int)state
->pid
, state
->name
,
112 DEBUG(0, ("Error in waitpid() for child %d (%s) - %s \n",
113 (int)state
->pid
, state
->name
, strerror(errno
)));
120 if (WIFEXITED(status
)) {
121 status
= WEXITSTATUS(status
);
122 DEBUG(2, ("Child %d (%s) exited with status %d\n",
123 (int)state
->pid
, state
->name
, status
));
124 } else if (WIFSIGNALED(status
)) {
125 status
= WTERMSIG(status
);
126 DEBUG(0, ("Child %d (%s) terminated with signal %d\n",
127 (int)state
->pid
, state
->name
, status
));
133 static struct standard_child_state
*setup_standard_child_pipe(struct tevent_context
*ev
,
136 struct standard_child_state
*state
;
137 int parent_child_pipe
[2];
141 * Prepare a pipe to allow us to know when the child exits,
142 * because it will trigger a read event on this private
145 * We do all this before the accept and fork(), so we can
146 * clean up if it fails.
148 state
= talloc_zero(ev
, struct standard_child_state
);
157 state
->name
= talloc_strdup(state
, name
);
158 if (state
->name
== NULL
) {
163 ret
= pipe(parent_child_pipe
);
165 DEBUG(0, ("Failed to create parent-child pipe to handle "
166 "SIGCHLD to track new process for socket\n"));
171 smb_set_close_on_exec(parent_child_pipe
[0]);
172 smb_set_close_on_exec(parent_child_pipe
[1]);
174 state
->from_child_fd
= parent_child_pipe
[0];
175 state
->to_parent_fd
= parent_child_pipe
[1];
178 * The basic purpose of calling this handler is to ensure we
179 * call waitpid() and so avoid zombies (now that we no longer
180 * user SIGIGN on for SIGCHLD), but it also allows us to clean
181 * up other resources in the future.
183 state
->from_child_fde
= tevent_add_fd(ev
, state
,
184 state
->from_child_fd
,
186 standard_child_pipe_handler
,
188 if (state
->from_child_fde
== NULL
) {
192 tevent_fd_set_auto_close(state
->from_child_fde
);
198 called when a listening socket becomes readable.
200 static void standard_accept_connection(struct tevent_context
*ev
,
201 struct loadparm_context
*lp_ctx
,
202 struct socket_context
*sock
,
203 void (*new_conn
)(struct tevent_context
*,
204 struct loadparm_context
*, struct socket_context
*,
205 struct server_id
, void *),
209 struct socket_context
*sock2
;
211 struct socket_address
*c
, *s
;
212 struct standard_child_state
*state
;
214 state
= setup_standard_child_pipe(ev
, NULL
);
219 /* accept an incoming connection. */
220 status
= socket_accept(sock
, &sock2
);
221 if (!NT_STATUS_IS_OK(status
)) {
222 DEBUG(0,("standard_accept_connection: accept: %s\n",
224 /* this looks strange, but is correct. We need to throttle things until
225 the system clears enough resources to handle this new socket */
227 close(state
->to_parent_fd
);
228 state
->to_parent_fd
= -1;
236 close(state
->to_parent_fd
);
237 state
->to_parent_fd
= -1;
245 /* parent or error code ... */
247 /* go back to the event loop */
251 /* this leaves state->to_parent_fd open */
256 /* This is now the child code. We need a completely new event_context to work with */
258 if (tevent_re_initialise(ev
) != 0) {
259 smb_panic("Failed to re-initialise tevent after fork");
262 /* this will free all the listening sockets and all state that
263 is not associated with this new connection */
266 /* we don't care if the dup fails, as its only a select()
267 speed optimisation */
270 /* tdb needs special fork handling */
271 ldb_wrap_fork_hook();
273 tevent_add_fd(ev
, ev
, child_pipe
[0], TEVENT_FD_READ
,
274 standard_pipe_handler
, NULL
);
275 if (child_pipe
[1] != -1) {
276 close(child_pipe
[1]);
280 /* Ensure that the forked children do not expose identical random streams */
281 set_need_random_reseed();
283 /* setup the process title */
284 c
= socket_get_peer_addr(sock2
, ev
);
285 s
= socket_get_my_addr(sock2
, ev
);
287 setproctitle("conn c[%s:%u] s[%s:%u] server_id[%d]",
288 c
->addr
, c
->port
, s
->addr
, s
->port
, (int)pid
);
293 /* setup this new connection. Cluster ID is PID based for this process model */
294 new_conn(ev
, lp_ctx
, sock2
, cluster_id(pid
, 0), private_data
);
296 /* we can't return to the top level here, as that event context is gone,
297 so we now process events in the new event context until there are no
299 tevent_loop_wait(ev
);
306 called to create a new server task
308 static void standard_new_task(struct tevent_context
*ev
,
309 struct loadparm_context
*lp_ctx
,
310 const char *service_name
,
311 void (*new_task
)(struct tevent_context
*, struct loadparm_context
*lp_ctx
, struct server_id
, void *),
315 struct standard_child_state
*state
;
317 state
= setup_standard_child_pipe(ev
, service_name
);
325 close(state
->to_parent_fd
);
326 state
->to_parent_fd
= -1;
334 /* parent or error code ... go back to the event loop */
338 /* this leaves state->to_parent_fd open */
343 /* this will free all the listening sockets and all state that
344 is not associated with this new connection */
345 if (tevent_re_initialise(ev
) != 0) {
346 smb_panic("Failed to re-initialise tevent after fork");
349 /* ldb/tdb need special fork handling */
350 ldb_wrap_fork_hook();
352 tevent_add_fd(ev
, ev
, child_pipe
[0], TEVENT_FD_READ
,
353 standard_pipe_handler
, NULL
);
354 if (child_pipe
[1] != -1) {
355 close(child_pipe
[1]);
359 /* Ensure that the forked children do not expose identical random streams */
360 set_need_random_reseed();
362 setproctitle("task %s server_id[%d]", service_name
, (int)pid
);
364 /* setup this new task. Cluster ID is PID based for this process model */
365 new_task(ev
, lp_ctx
, cluster_id(pid
, 0), private_data
);
367 /* we can't return to the top level here, as that event context is gone,
368 so we now process events in the new event context until there are no
370 tevent_loop_wait(ev
);
377 /* called when a task goes down */
378 _NORETURN_
static void standard_terminate(struct tevent_context
*ev
, struct loadparm_context
*lp_ctx
,
381 DEBUG(2,("standard_terminate: reason[%s]\n",reason
));
385 /* this reload_charcnv() has the effect of freeing the iconv context memory,
386 which makes leak checking easier */
387 reload_charcnv(lp_ctx
);
389 /* terminate this process */
393 /* called to set a title of a task or connection */
394 static void standard_set_title(struct tevent_context
*ev
, const char *title
)
397 setproctitle("%s", title
);
403 static const struct model_ops standard_ops
= {
405 .model_init
= standard_model_init
,
406 .accept_connection
= standard_accept_connection
,
407 .new_task
= standard_new_task
,
408 .terminate
= standard_terminate
,
409 .set_title
= standard_set_title
,
413 initialise the standard process model, registering ourselves with the process model subsystem
415 NTSTATUS
process_model_standard_init(void)
417 return register_process_model(&standard_ops
);