r19604: This is a massive commit, and I appologise in advance for it's size.
[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 2 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, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "lib/events/events.h"
27 #include "lib/tdb/include/tdb.h"
28 #include "lib/socket/socket.h"
29 #include "smbd/process_model.h"
30
31 #include "param/secrets.h"
32
33 #ifdef HAVE_SETPROCTITLE
34 #ifdef HAVE_SETPROCTITLE_H
35 #include <setproctitle.h>
36 #endif
37 #else
38 #define setproctitle none_setproctitle
39 static int none_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
40 static int none_setproctitle(const char *fmt, ...)
41 {
42         return 0;
43 }
44 #endif
45
46 /*
47   called when the process model is selected
48 */
49 static void standard_model_init(struct event_context *ev)
50 {
51         signal(SIGCHLD, SIG_IGN);
52 }
53
54 /*
55   called when a listening socket becomes readable. 
56 */
57 static void standard_accept_connection(struct event_context *ev, 
58                                        struct socket_context *sock, 
59                                        void (*new_conn)(struct event_context *, struct socket_context *, 
60                                                         uint32_t , void *), 
61                                        void *private)
62 {
63         NTSTATUS status;
64         struct socket_context *sock2;
65         pid_t pid;
66         struct event_context *ev2;
67         struct socket_address *c, *s;
68
69         /* accept an incoming connection. */
70         status = socket_accept(sock, &sock2);
71         if (!NT_STATUS_IS_OK(status)) {
72                 DEBUG(0,("standard_accept_connection: accept: %s\n",
73                          nt_errstr(status)));
74                 /* this looks strange, but is correct. We need to throttle things until
75                    the system clears enough resources to handle this new socket */
76                 sleep(1);
77                 return;
78         }
79
80         pid = fork();
81
82         if (pid != 0) {
83                 /* parent or error code ... */
84                 talloc_free(sock2);
85                 /* go back to the event loop */
86                 return;
87         }
88
89         pid = getpid();
90
91         /* This is now the child code. We need a completely new event_context to work with */
92         ev2 = event_context_init(NULL);
93
94         /* the service has given us a private pointer that
95            encapsulates the context it needs for this new connection -
96            everything else will be freed */
97         talloc_steal(ev2, private);
98         talloc_steal(private, sock2);
99
100         /* this will free all the listening sockets and all state that
101            is not associated with this new connection */
102         talloc_free(sock);
103         talloc_free(ev);
104
105         /* we don't care if the dup fails, as its only a select()
106            speed optimisation */
107         socket_dup(sock2);
108                         
109         /* tdb needs special fork handling */
110         if (tdb_reopen_all(1) == -1) {
111                 DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
112         }
113
114         /* Ensure that the forked children do not expose identical random streams */
115         set_need_random_reseed();
116
117         /* setup the process title */
118         c = socket_get_peer_addr(sock2, ev2);
119         s = socket_get_my_addr(sock2, ev2);
120         if (s && c) {
121                 setproctitle("conn c[%s:%u] s[%s:%u] server_id[%d]",
122                              c->addr, c->port, s->addr, s->port, pid);
123         }
124         talloc_free(c);
125         talloc_free(s);
126
127         /* setup this new connection */
128         new_conn(ev2, sock2, pid, private);
129
130         /* we can't return to the top level here, as that event context is gone,
131            so we now process events in the new event context until there are no
132            more to process */      
133         event_loop_wait(ev2);
134
135         talloc_free(ev2);
136         exit(0);
137 }
138
139 /*
140   called to create a new server task
141 */
142 static void standard_new_task(struct event_context *ev, 
143                               void (*new_task)(struct event_context *, uint32_t , void *), 
144                               void *private)
145 {
146         pid_t pid;
147         struct event_context *ev2;
148
149         pid = fork();
150
151         if (pid != 0) {
152                 /* parent or error code ... go back to the event loop */
153                 return;
154         }
155
156         pid = getpid();
157
158         /* This is now the child code. We need a completely new event_context to work with */
159         ev2 = event_context_init(NULL);
160
161         /* the service has given us a private pointer that
162            encapsulates the context it needs for this new connection -
163            everything else will be freed */
164         talloc_steal(ev2, private);
165
166         /* this will free all the listening sockets and all state that
167            is not associated with this new connection */
168         talloc_free(ev);
169
170         /* tdb needs special fork handling */
171         if (tdb_reopen_all(1) == -1) {
172                 DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
173         }
174
175         /* Ensure that the forked children do not expose identical random streams */
176         set_need_random_reseed();
177
178         setproctitle("task server_id[%d]", pid);
179
180         /* setup this new connection */
181         new_task(ev2, pid, private);
182
183         /* we can't return to the top level here, as that event context is gone,
184            so we now process events in the new event context until there are no
185            more to process */      
186         event_loop_wait(ev2);
187
188         talloc_free(ev2);
189         exit(0);
190 }
191
192
193 /* called when a task goes down */
194 static void standard_terminate(struct event_context *ev, const char *reason) 
195 {
196         DEBUG(2,("standard_terminate: reason[%s]\n",reason));
197
198         /* this init_iconv() has the effect of freeing the iconv context memory,
199            which makes leak checking easier */
200         init_iconv();
201
202         /* the secrets db should really hang off the connection structure */
203         secrets_shutdown();
204
205         talloc_free(ev);
206
207         /* terminate this process */
208         exit(0);
209 }
210
211 /* called to set a title of a task or connection */
212 static void standard_set_title(struct event_context *ev, const char *title) 
213 {
214         if (title) {
215                 setproctitle("%s", title);
216         } else {
217                 setproctitle(NULL);
218         }
219 }
220
221 static const struct model_ops standard_ops = {
222         .name                   = "standard",
223         .model_init             = standard_model_init,
224         .accept_connection      = standard_accept_connection,
225         .new_task               = standard_new_task,
226         .terminate              = standard_terminate,
227         .set_title              = standard_set_title,
228 };
229
230 /*
231   initialise the standard process model, registering ourselves with the process model subsystem
232  */
233 NTSTATUS process_model_standard_init(void)
234 {
235         return register_process_model(&standard_ops);
236 }