source: trunk/server/source4/smbd/process_prefork.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 6.1 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 process model: prefork (n client connections per process)
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 Copyright (C) Andrew Bartlett 2008 <abartlet@samba.org>
10 Copyright (C) David Disseldorp 2008 <ddiss@sgi.com>
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
24*/
25
26#include "includes.h"
27#include "lib/events/events.h"
28#include "lib/socket/socket.h"
29#include "smbd/process_model.h"
30#include "system/filesys.h"
31#include "cluster/cluster.h"
32#include "param/param.h"
33#include "ldb_wrap.h"
34
35#ifdef HAVE_SETPROCTITLE
36#ifdef HAVE_SETPROCTITLE_H
37#include <setproctitle.h>
38#endif
39#else
40#define setproctitle none_setproctitle
41static int none_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
42static int none_setproctitle(const char *fmt, ...)
43{
44 return 0;
45}
46#endif
47
48/*
49 called when the process model is selected
50*/
51static void prefork_model_init(void)
52{
53 signal(SIGCHLD, SIG_IGN);
54}
55
56static void prefork_reload_after_fork(void)
57{
58 ldb_wrap_fork_hook();
59
60 /* Ensure that the forked children do not expose identical random streams */
61 set_need_random_reseed();
62}
63
64/*
65 called when a listening socket becomes readable.
66*/
67static void prefork_accept_connection(struct tevent_context *ev,
68 struct loadparm_context *lp_ctx,
69 struct socket_context *listen_socket,
70 void (*new_conn)(struct tevent_context *,
71 struct loadparm_context *, struct socket_context *,
72 struct server_id , void *),
73 void *private_data)
74{
75 NTSTATUS status;
76 struct socket_context *connected_socket;
77 pid_t pid = getpid();
78
79 /* accept an incoming connection. */
80 status = socket_accept(listen_socket, &connected_socket);
81 if (!NT_STATUS_IS_OK(status)) {
82 return;
83 }
84
85 talloc_steal(private_data, connected_socket);
86
87 new_conn(ev, lp_ctx, connected_socket, cluster_id(pid, socket_get_fd(connected_socket)), private_data);
88}
89
90/*
91 called to create a new server task
92*/
93static void prefork_new_task(struct tevent_context *ev,
94 struct loadparm_context *lp_ctx,
95 const char *service_name,
96 void (*new_task_fn)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *),
97 void *private_data)
98{
99 pid_t pid;
100 int i, num_children;
101
102 struct tevent_context *ev2, *ev_parent;
103
104 pid = fork();
105
106 if (pid != 0) {
107 /* parent or error code ... go back to the event loop */
108 return;
109 }
110
111 pid = getpid();
112
113 /* This is now the child code. We need a completely new event_context to work with */
114 ev2 = s4_event_context_init(NULL);
115
116 /* the service has given us a private pointer that
117 encapsulates the context it needs for this new connection -
118 everything else will be freed */
119 talloc_steal(ev2, private_data);
120
121 /* this will free all the listening sockets and all state that
122 is not associated with this new connection */
123 talloc_free(ev);
124
125 setproctitle("task %s server_id[%d]", service_name, (int)pid);
126
127 prefork_reload_after_fork();
128
129 /* setup this new connection: process will bind to it's sockets etc */
130 new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data);
131
132 num_children = lpcfg_parm_int(lp_ctx, NULL, "prefork children", service_name, 0);
133 if (num_children == 0) {
134
135 /* We don't want any kids hanging around for this one,
136 * let the parent do all the work */
137 event_loop_wait(ev2);
138
139 talloc_free(ev2);
140 exit(0);
141 }
142
143 /* We are now free to spawn some child proccesses */
144
145 for (i=0; i < num_children; i++) {
146
147 pid = fork();
148 if (pid > 0) {
149 continue;
150 } else if (pid == -1) {
151 return;
152 } else {
153 pid = getpid();
154 setproctitle("task %s server_id[%d]", service_name, (int)pid);
155
156 prefork_reload_after_fork();
157
158 /* we can't return to the top level here, as that event context is gone,
159 so we now process events in the new event context until there are no
160 more to process */
161 event_loop_wait(ev2);
162
163 talloc_free(ev2);
164 exit(0);
165 }
166 }
167
168 /* Don't listen on the sockets we just gave to the children */
169 talloc_free(ev2);
170
171 /* But we need a events system to handle reaping children */
172 ev_parent = s4_event_context_init(NULL);
173
174 /* TODO: Handle some events... */
175
176 /* we can't return to the top level here, as that event context is gone,
177 so we now process events in the new event context until there are no
178 more to process */
179 event_loop_wait(ev_parent);
180
181 talloc_free(ev_parent);
182 exit(0);
183
184}
185
186
187/* called when a task goes down */
188static void prefork_terminate(struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *reason)
189{
190 DEBUG(2,("prefork_terminate: reason[%s]\n",reason));
191}
192
193/* called to set a title of a task or connection */
194static void prefork_set_title(struct tevent_context *ev, const char *title)
195{
196 if (title) {
197 setproctitle("%s", title);
198 } else {
199 setproctitle(NULL);
200 }
201}
202
203static const struct model_ops prefork_ops = {
204 .name = "prefork",
205 .model_init = prefork_model_init,
206 .accept_connection = prefork_accept_connection,
207 .new_task = prefork_new_task,
208 .terminate = prefork_terminate,
209 .set_title = prefork_set_title,
210};
211
212/*
213 initialise the prefork process model, registering ourselves with the process model subsystem
214 */
215NTSTATUS process_model_prefork_init(void)
216{
217 return register_process_model(&prefork_ops);
218}
Note: See TracBrowser for help on using the repository browser.