r1520: only call write handler or read handler, not both. This copes with the
[bbaumbach/samba-autobuild/.git] / source4 / smbd / service.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    SERVER SERVICE code
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Stefan (metze) Metzmacher      2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 struct server_context *server_service_startup(const char *model)
27 {
28         int i;
29         const char **server_services = lp_server_services();
30         TALLOC_CTX *mem_ctx;
31         struct server_context *srv_ctx;
32         const struct model_ops *model_ops;
33
34         if (!server_services) {
35                 DEBUG(0,("process_model_startup: no endpoint servers configured\n"));
36                 return NULL;
37         }
38
39         model_ops = process_model_startup(model);
40         if (!model_ops) {
41                 DEBUG(0,("process_model_startup('%s') failed\n", model));
42                 return NULL;
43         }
44
45         mem_ctx = talloc_init("server_context");
46         if (!mem_ctx) {
47                 DEBUG(0,("talloc_init(server_context) failed\n"));
48                 return NULL;
49         }
50
51         srv_ctx = talloc_p(mem_ctx, struct server_context);
52         if (!srv_ctx) {
53                 DEBUG(0,("talloc_p(mem_ctx, struct server_context) failed\n"));
54                 return NULL;    
55         }
56
57         ZERO_STRUCTP(srv_ctx);
58         srv_ctx->mem_ctx = mem_ctx;
59
60         srv_ctx->events = event_context_init();
61         if (!srv_ctx->events) {
62                 DEBUG(0,("event_context_init() failed\n"));
63                 return NULL;    
64         }
65
66
67         for (i=0;server_services[i];i++) {
68                 TALLOC_CTX *mem_ctx2;
69                 const struct server_service_ops *service_ops;
70                 struct server_service *service;
71
72                 service_ops = server_service_byname(server_services[i]);
73                 if (!service_ops) {
74                         DEBUG(0,("process_model_startup: failed to find server service = '%s'\n", server_services[i]));
75                         return NULL;
76                 }
77
78                 mem_ctx2 = talloc_init("server_service");
79
80                 service = talloc_p(mem_ctx2, struct server_service);
81                 if (!service) {
82                         DEBUG(0,("talloc_p(mem_ctx, struct server_service) failed\n"));
83                         return NULL;
84                 }
85
86                 ZERO_STRUCTP(service);
87                 service->mem_ctx        = mem_ctx2;
88                 service->ops            = service_ops;
89                 service->model_ops      = model_ops;
90                 service->srv_ctx        = srv_ctx;
91                 
92                 /* TODO: service_init() should return a result */
93                 service->ops->service_init(service, model_ops);
94         }
95
96         return srv_ctx;
97 }
98
99 /*
100   setup a single listener of any type
101   if you pass *port == 0, then a port < 1024 is used
102  */
103 struct server_socket *service_setup_socket(struct server_service *service,
104                          const struct model_ops *model_ops,
105                          struct socket_context *socket_ctx,
106                          struct in_addr *ifip, uint16_t *port)
107 {
108         TALLOC_CTX *mem_ctx;
109         struct server_socket *sock;
110         struct fd_event fde;
111         int i;
112
113         mem_ctx = talloc_init("struct server_socket");
114
115         sock = talloc_p(mem_ctx, struct server_socket);
116         if (!sock) {
117                 DEBUG(0,("talloc_p(mem_ctx, struct server_socket) failed\n"));
118                 return NULL;    
119         }
120
121         if (*port == 0) {
122                 fde.fd = -1;
123                 for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
124                         fde.fd = open_socket_in(SOCK_STREAM, i, 0, ifip->s_addr, True);                 
125                         if (fde.fd != -1) break;
126                 }
127                 if (fde.fd != -1) {
128                         *port = i;
129                 }
130         } else {
131                 fde.fd = open_socket_in(SOCK_STREAM, *port, 0, ifip->s_addr, True);
132         }
133
134         if (fde.fd == -1) {
135                 DEBUG(0,("Failed to open socket on %s:%u - %s\n",
136                          inet_ntoa(*ifip), *port, strerror(errno)));
137                 return NULL;
138         }
139
140         /* ready to listen */
141         set_socket_options(fde.fd, "SO_KEEPALIVE"); 
142         set_socket_options(fde.fd, lp_socket_options());
143       
144         if (listen(fde.fd, SERVER_LISTEN_BACKLOG) == -1) {
145                 DEBUG(0,("Failed to listen on %s:%u - %s\n",
146                          inet_ntoa(*ifip), *port, strerror(errno)));
147                 close(fde.fd);
148                 return NULL;
149         }
150
151         /* we are only interested in read events on the listen socket */
152         fde.flags = EVENT_FD_READ;
153         fde.private = sock;
154         fde.handler = model_ops->accept_connection;
155
156         ZERO_STRUCTP(sock);
157         sock->mem_ctx   = mem_ctx;
158         sock->service   = service;
159         sock->socket    = socket_ctx;
160         sock->event.ctx = service->srv_ctx->events;
161         sock->event.fde = event_add_fd(sock->event.ctx, &fde);
162         if (!sock->event.fde) {
163                 DEBUG(0,("event_add_fd(sock->event.ctx, &fde) failed\n"));
164                 return NULL;
165         }
166
167         DLIST_ADD(service->socket_list, sock);
168
169         return sock;
170 }
171
172 struct server_connection *server_setup_connection(struct event_context *ev, struct server_socket *server_socket, int accepted_fd, time_t t)
173 {
174         struct fd_event fde;
175         struct timed_event idle;
176         struct server_connection *srv_conn;
177         TALLOC_CTX *mem_ctx;
178
179         mem_ctx = talloc_init("server_service_connection");
180         if (!mem_ctx) {
181                 DEBUG(0,("talloc_init(server_service_connection) failed\n"));
182                 return NULL;
183         }
184
185         srv_conn = talloc_p(mem_ctx, struct server_connection);
186         if (!srv_conn) {
187                 DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n"));
188                 talloc_destroy(mem_ctx);
189                 return NULL;
190         }
191
192         ZERO_STRUCTP(srv_conn);
193         srv_conn->mem_ctx = mem_ctx;
194
195         fde.private     = srv_conn;
196         fde.fd          = accepted_fd;
197         fde.flags       = EVENT_FD_READ;
198         fde.handler     = server_io_handler;
199
200         idle.private    = srv_conn;
201         idle.next_event = t + SERVER_DEFAULT_IDLE_TIME;
202         idle.handler    = server_idle_handler;
203
204         srv_conn->event.ctx             = ev;
205         srv_conn->event.fde             = &fde;
206         srv_conn->event.idle            = &idle;
207         srv_conn->event.idle_time       = SERVER_DEFAULT_IDLE_TIME;
208
209         srv_conn->server_socket         = server_socket;
210         srv_conn->service               = server_socket->service;
211
212         /* TODO: we need a generic socket subsystem */
213         srv_conn->socket                = talloc_p(srv_conn->mem_ctx, struct socket_context);
214         if (!srv_conn->socket) {
215                 DEBUG(0,("talloc_p(srv_conn->mem_ctx, struct socket_context) failed\n"));
216                 talloc_destroy(mem_ctx);
217                 return NULL;
218         }
219         srv_conn->socket->private_data  = NULL;
220         srv_conn->socket->ops           = NULL;
221         srv_conn->socket->client_addr   = NULL;
222         srv_conn->socket->pkt_count     = 0;
223         srv_conn->socket->fde           = srv_conn->event.fde;
224
225         /* create a smb server context and add it to out event
226            handling */
227         server_socket->service->ops->accept_connection(srv_conn);
228
229         /* accpect_connection() of the service may changed idle.next_event */
230         srv_conn->event.fde     = event_add_fd(ev,&fde);
231         srv_conn->event.idle    = event_add_timed(ev,&idle);
232
233         srv_conn->socket->fde   = srv_conn->event.fde;
234
235         return srv_conn;
236 }
237
238 /*
239   close the socket and shutdown a server_context
240 */
241 void server_terminate_connection(struct server_connection *srv_conn, const char *reason)
242 {
243         DEBUG(0,("server_terminate_connection\n"));
244         srv_conn->service->model_ops->terminate_connection(srv_conn, reason);
245 }
246
247 void server_destroy_connection(struct server_connection *srv_conn)
248 {
249         close(srv_conn->event.fde->fd);
250
251         event_remove_fd(srv_conn->event.ctx, srv_conn->event.fde);
252         srv_conn->event.fde = NULL;
253         event_remove_timed(srv_conn->event.ctx, srv_conn->event.idle);
254         srv_conn->event.idle = NULL;
255
256         talloc_destroy(srv_conn->mem_ctx);
257 }
258
259 void server_io_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
260 {
261         struct server_connection *conn = fde->private;
262
263         conn->event.idle->next_event = t + conn->event.idle_time;
264
265         if (flags & EVENT_FD_WRITE) {
266                 conn->service->ops->send_handler(conn, t, flags);
267                 return;
268         }
269
270         if (flags & EVENT_FD_READ) {
271                 conn->service->ops->recv_handler(conn, t, flags);
272         }
273
274 }
275
276 void server_idle_handler(struct event_context *ev, struct timed_event *idle, time_t t)
277 {
278         struct server_connection *conn = idle->private;
279
280         conn->event.idle->next_event = t + conn->event.idle_time;
281
282         conn->service->ops->idle_handler(conn,t);
283 }
284 /*
285   return the operations structure for a named backend of the specified type
286 */
287 const struct server_service_ops *server_service_byname(const char *name)
288 {
289         if (strcmp("smb",name)==0) {
290                 return smbsrv_get_ops();
291         }
292         if (strcmp("rpc",name)==0) {
293                 return dcesrv_get_ops();
294         }
295         return NULL;
296 }
297
298 static NTSTATUS register_server_service_ops(const void *_ops)
299 {
300         return NT_STATUS_NOT_IMPLEMENTED;
301 }
302
303 /*
304   initialise the SERVER SERVICE subsystem
305 */
306 BOOL server_service_init(void)
307 {
308         NTSTATUS status;
309
310         status = register_subsystem("service", register_server_service_ops); 
311         if (!NT_STATUS_IS_OK(status)) {
312                 return False;
313         }
314
315         /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
316         static_init_server_service;
317
318         DEBUG(3,("SERVER SERVICE subsystem version %d initialised\n", SERVER_SERVICE_VERSION));
319         return True;
320 }