~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/smbd/process_prefork.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "../tdb/include/tdb.h"
 
29
#include "lib/socket/socket.h"
 
30
#include "smbd/process_model.h"
 
31
#include "param/secrets.h"
 
32
#include "system/filesys.h"
 
33
#include "cluster/cluster.h"
 
34
#include "param/param.h"
 
35
 
 
36
#ifdef HAVE_SETPROCTITLE
 
37
#ifdef HAVE_SETPROCTITLE_H
 
38
#include <setproctitle.h>
 
39
#endif
 
40
#else
 
41
#define setproctitle none_setproctitle
 
42
static int none_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
 
43
static int none_setproctitle(const char *fmt, ...)
 
44
{
 
45
        return 0;
 
46
}
 
47
#endif
 
48
 
 
49
/*
 
50
  called when the process model is selected
 
51
*/
 
52
static void prefork_model_init(struct tevent_context *ev)
 
53
{
 
54
        signal(SIGCHLD, SIG_IGN);
 
55
}
 
56
 
 
57
static void prefork_reload_after_fork(void)
 
58
{
 
59
        /* tdb needs special fork handling */
 
60
        if (tdb_reopen_all(1) == -1) {
 
61
                DEBUG(0,("prefork_reload_after_fork: tdb_reopen_all failed.\n"));
 
62
        }
 
63
 
 
64
        /* Ensure that the forked children do not expose identical random streams */
 
65
        set_need_random_reseed();
 
66
}
 
67
 
 
68
/*
 
69
  called when a listening socket becomes readable. 
 
70
*/
 
71
static void prefork_accept_connection(struct tevent_context *ev, 
 
72
                                      struct loadparm_context *lp_ctx,
 
73
                                      struct socket_context *listen_socket,
 
74
                                       void (*new_conn)(struct tevent_context *,
 
75
                                                        struct loadparm_context *, struct socket_context *, 
 
76
                                                        struct server_id , void *), 
 
77
                                       void *private_data)
 
78
{
 
79
        NTSTATUS status;
 
80
        struct socket_context *connected_socket;
 
81
        pid_t pid = getpid();
 
82
 
 
83
        /* accept an incoming connection. */
 
84
        status = socket_accept(listen_socket, &connected_socket);
 
85
        if (!NT_STATUS_IS_OK(status)) {
 
86
                return;
 
87
        }
 
88
 
 
89
        talloc_steal(private_data, connected_socket);
 
90
 
 
91
        new_conn(ev, lp_ctx, connected_socket, cluster_id(pid, socket_get_fd(connected_socket)), private_data);
 
92
}
 
93
 
 
94
/*
 
95
  called to create a new server task
 
96
*/
 
97
static void prefork_new_task(struct tevent_context *ev, 
 
98
                             struct loadparm_context *lp_ctx,
 
99
                             const char *service_name,
 
100
                             void (*new_task_fn)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *), 
 
101
                             void *private_data)
 
102
{
 
103
        pid_t pid;
 
104
        int i, num_children;
 
105
 
 
106
        struct tevent_context *ev2, *ev_parent;
 
107
 
 
108
        pid = fork();
 
109
 
 
110
        if (pid != 0) {
 
111
                /* parent or error code ... go back to the event loop */
 
112
                return;
 
113
        }
 
114
 
 
115
        pid = getpid();
 
116
 
 
117
        /* This is now the child code. We need a completely new event_context to work with */
 
118
        ev2 = s4_event_context_init(NULL);
 
119
 
 
120
        /* the service has given us a private pointer that
 
121
           encapsulates the context it needs for this new connection -
 
122
           everything else will be freed */
 
123
        talloc_steal(ev2, private_data);
 
124
 
 
125
        /* this will free all the listening sockets and all state that
 
126
           is not associated with this new connection */
 
127
        talloc_free(ev);
 
128
 
 
129
        setproctitle("task %s server_id[%d]", service_name, pid);
 
130
 
 
131
        prefork_reload_after_fork();
 
132
 
 
133
        /* setup this new connection: process will bind to it's sockets etc */
 
134
        new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data);
 
135
 
 
136
        num_children = lp_parm_int(lp_ctx, NULL, "prefork children", service_name, 0);
 
137
        if (num_children == 0) {
 
138
 
 
139
                /* We don't want any kids hanging around for this one,
 
140
                 * let the parent do all the work */
 
141
                event_loop_wait(ev2);
 
142
                
 
143
                talloc_free(ev2);
 
144
                exit(0);
 
145
        }
 
146
 
 
147
        /* We are now free to spawn some child proccesses */
 
148
 
 
149
        for (i=0; i < num_children; i++) {
 
150
 
 
151
                pid = fork();
 
152
                if (pid > 0) {
 
153
                        continue;
 
154
                } else if (pid == -1) {
 
155
                        return;
 
156
                } else {
 
157
                        pid = getpid();
 
158
                        setproctitle("task %s server_id[%d]", service_name, pid);
 
159
 
 
160
                        prefork_reload_after_fork();
 
161
 
 
162
                        /* we can't return to the top level here, as that event context is gone,
 
163
                           so we now process events in the new event context until there are no
 
164
                           more to process */      
 
165
                        event_loop_wait(ev2);
 
166
                        
 
167
                        talloc_free(ev2);
 
168
                        exit(0);
 
169
                }
 
170
        }
 
171
 
 
172
        /* Don't listen on the sockets we just gave to the children */
 
173
        talloc_free(ev2);
 
174
        
 
175
        /* But we need a events system to handle reaping children */
 
176
        ev_parent = s4_event_context_init(NULL);
 
177
        
 
178
        /* TODO: Handle some events... */
 
179
        
 
180
        /* we can't return to the top level here, as that event context is gone,
 
181
           so we now process events in the new event context until there are no
 
182
           more to process */      
 
183
        event_loop_wait(ev_parent);
 
184
        
 
185
        talloc_free(ev_parent);
 
186
        exit(0);
 
187
 
 
188
}
 
189
 
 
190
 
 
191
/* called when a task goes down */
 
192
_NORETURN_ static void prefork_terminate(struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *reason) 
 
193
{
 
194
        DEBUG(2,("prefork_terminate: reason[%s]\n",reason));
 
195
}
 
196
 
 
197
/* called to set a title of a task or connection */
 
198
static void prefork_set_title(struct tevent_context *ev, const char *title) 
 
199
{
 
200
        if (title) {
 
201
                setproctitle("%s", title);
 
202
        } else {
 
203
                setproctitle(NULL);
 
204
        }
 
205
}
 
206
 
 
207
static const struct model_ops prefork_ops = {
 
208
        .name                   = "prefork",
 
209
        .model_init             = prefork_model_init,
 
210
        .accept_connection      = prefork_accept_connection,
 
211
        .new_task               = prefork_new_task,
 
212
        .terminate              = prefork_terminate,
 
213
        .set_title              = prefork_set_title,
 
214
};
 
215
 
 
216
/*
 
217
  initialise the prefork process model, registering ourselves with the process model subsystem
 
218
 */
 
219
NTSTATUS process_model_prefork_init(void)
 
220
{
 
221
        return register_process_model(&prefork_ops);
 
222
}