r99: make sure we reap child processes in the standard process model
[samba.git] / source4 / smbd / process_standard.c
1 /* 
2    Unix SMB/CIFS implementation.
3    process model: standard (1 process per client connection)
4    Copyright (C) Andrew Tridgell 1992-2003
5    Copyright (C) James J Myers 2003 <myersjj@samba.org>
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /*
25   called when the process model is selected
26 */
27 static void model_startup(void)
28 {
29         signal(SIGCHLD, SIG_IGN);
30 }
31
32 /*
33   called when a listening socket becomes readable
34 */
35 static void accept_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags)
36 {
37         int accepted_fd;
38         struct sockaddr addr;
39         socklen_t in_addrlen = sizeof(addr);
40         pid_t pid;
41         struct model_ops *model_ops = fde->private;
42
43         accepted_fd = accept(fde->fd,&addr,&in_addrlen);
44         if (accepted_fd == -1) {
45                 DEBUG(0,("accept_connection_standard: accept: %s\n",
46                          strerror(errno)));
47                 return;
48         }
49
50         pid = fork();
51
52         if (pid != 0) {
53                 /* parent or error code ... */
54
55                 close(accepted_fd);
56                 /* go back to the event loop */
57                 return;
58         }
59
60         /* Child code ... */
61
62         /* close all the listening sockets */
63         event_remove_fd_all_handler(ev, model_ops->accept_connection);
64         event_remove_fd_all_handler(ev, model_ops->accept_rpc_connection);
65                         
66         /* tdb needs special fork handling */
67         if (tdb_reopen_all() == -1) {
68                 DEBUG(0,("accept_connection_standard: tdb_reopen_all failed.\n"));
69         }
70
71         /* Load DSO's */
72         init_modules();
73                 
74         /* initialize new process */
75         smbd_process_init();
76                 
77         init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler);
78
79         /* return to the event loop */
80 }
81
82 /*
83   called when a rpc listening socket becomes readable
84 */
85 static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags)
86 {
87         int accepted_fd;
88         struct sockaddr addr;
89         socklen_t in_addrlen = sizeof(addr);
90         pid_t pid;
91
92         accepted_fd = accept(fde->fd,&addr,&in_addrlen);
93         if (accepted_fd == -1) {
94                 DEBUG(0,("accept_connection_standard: accept: %s\n",
95                          strerror(errno)));
96                 return;
97         }
98
99         pid = fork();
100
101         if (pid != 0) {
102                 /* parent or error code ... */
103                 close(accepted_fd);
104                 /* go back to the event loop */
105                 return;
106         }
107
108         /* Child code ... */
109
110         /* close all the listening sockets */
111         event_remove_fd_all_handler(ev, accept_connection);
112         event_remove_fd_all_handler(ev, accept_rpc_connection);
113                         
114         init_rpc_session(ev, fde->private, accepted_fd); 
115 }
116
117 /* called when a SMB connection goes down */
118 static void terminate_connection(struct server_context *server, const char *reason) 
119 {
120         server_terminate(server);
121         /* terminate this process */
122         exit(0);
123 }
124
125 /* called when a rpc connection goes down */
126 static void terminate_rpc_connection(void *r, const char *reason) 
127 {
128         rpc_server_terminate(r);
129         /* terminate this process */
130         exit(0);
131 }
132
133 static int get_id(struct request_context *req)
134 {
135         return (int)req->smb->pid;
136 }
137
138 static void standard_exit_server(struct server_context *smb, const char *reason)
139 {
140         DEBUG(1,("standard_exit_server: reason[%s]\n",reason));
141 }
142
143 /*
144   initialise the standard process model, registering ourselves with the process model subsystem
145  */
146 NTSTATUS process_model_standard_init(void)
147 {
148         NTSTATUS ret;
149         struct model_ops ops;
150
151         ZERO_STRUCT(ops);
152
153         /* fill in our name */
154         ops.name = "standard";
155
156         /* fill in all the operations */
157         ops.model_startup = model_startup;
158         ops.accept_connection = accept_connection;
159         ops.accept_rpc_connection = accept_rpc_connection;
160         ops.terminate_connection = terminate_connection;
161         ops.terminate_rpc_connection = terminate_rpc_connection;
162         ops.exit_server = standard_exit_server;
163         ops.get_id = get_id;
164
165         /* register ourselves with the PROCESS_MODEL subsystem. */
166         ret = register_backend("process_model", &ops);
167         if (!NT_STATUS_IS_OK(ret)) {
168                 DEBUG(0,("Failed to register process_model 'standard'!\n"));
169                 return ret;
170         }
171
172         return ret;
173 }