diff options
Diffstat (limited to 'source4/smbd/service.c')
-rw-r--r-- | source4/smbd/service.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/source4/smbd/service.c b/source4/smbd/service.c new file mode 100644 index 0000000000..2b6e0579fa --- /dev/null +++ b/source4/smbd/service.c @@ -0,0 +1,241 @@ +/* + Unix SMB/CIFS implementation. + + SERVER SERVICE code + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Stefan (metze) Metzmacher 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +struct server_context *server_service_startup(const char *model) +{ + int i; + const char **server_services = lp_server_services(); + TALLOC_CTX *mem_ctx; + struct server_context *srv_ctx; + const struct model_ops *model_ops; + + if (!server_services) { + DEBUG(0,("process_model_startup: no endpoint servers configured\n")); + return NULL; + } + + model_ops = process_model_startup(model); + if (!model_ops) { + DEBUG(0,("process_model_startup('%s') failed\n", model)); + return NULL; + } + + mem_ctx = talloc_init("server_context"); + if (!mem_ctx) { + DEBUG(0,("talloc_init(server_context) failed\n")); + return NULL; + } + + srv_ctx = talloc_p(mem_ctx, struct server_context); + if (!srv_ctx) { + DEBUG(0,("talloc_p(mem_ctx, struct server_context) failed\n")); + return NULL; + } + + ZERO_STRUCTP(srv_ctx); + srv_ctx->mem_ctx = mem_ctx; + + srv_ctx->events = event_context_init(); + if (!srv_ctx->events) { + DEBUG(0,("event_context_init() failed\n")); + return NULL; + } + + + for (i=0;server_services[i];i++) { + TALLOC_CTX *mem_ctx2; + const struct server_service_ops *service_ops; + struct server_service *service; + + service_ops = server_service_byname(server_services[i]); + if (!service_ops) { + DEBUG(0,("process_model_startup: failed to find server service = '%s'\n", server_services[i])); + return NULL; + } + + mem_ctx2 = talloc_init("server_service"); + + service = talloc_p(mem_ctx2, struct server_service); + if (!service) { + DEBUG(0,("talloc_p(mem_ctx, struct server_service) failed\n")); + return NULL; + } + + ZERO_STRUCTP(service); + service->mem_ctx = mem_ctx2; + service->ops = service_ops; + service->model_ops = model_ops; + service->srv_ctx = srv_ctx; + + /* TODO: service_init() should return a result */ + service->ops->service_init(service, model_ops); + } + + return srv_ctx; +} + +/* + setup a single listener of any type + if you pass *port == 0, then a port < 1024 is used + */ +struct server_socket *service_setup_socket(struct server_service *service, + const struct model_ops *model_ops, + struct socket_context *socket_ctx, + struct in_addr *ifip, uint16_t *port) +{ + TALLOC_CTX *mem_ctx; + struct server_socket *sock; + struct fd_event fde; + int i; + + mem_ctx = talloc_init("struct server_socket"); + + sock = talloc_p(mem_ctx, struct server_socket); + if (!sock) { + DEBUG(0,("talloc_p(mem_ctx, struct server_socket) failed\n")); + return NULL; + } + + if (*port == 0) { + fde.fd = -1; + for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) { + fde.fd = open_socket_in(SOCK_STREAM, i, 0, ifip->s_addr, True); + if (fde.fd != -1) break; + } + if (fde.fd != -1) { + *port = i; + } + } else { + fde.fd = open_socket_in(SOCK_STREAM, *port, 0, ifip->s_addr, True); + } + + if (fde.fd == -1) { + DEBUG(0,("Failed to open socket on %s:%u - %s\n", + inet_ntoa(*ifip), *port, strerror(errno))); + return NULL; + } + + /* ready to listen */ + set_socket_options(fde.fd, "SO_KEEPALIVE"); + set_socket_options(fde.fd, lp_socket_options()); + + if (listen(fde.fd, SERVER_LISTEN_BACKLOG) == -1) { + DEBUG(0,("Failed to listen on %s:%u - %s\n", + inet_ntoa(*ifip), *port, strerror(errno))); + close(fde.fd); + return NULL; + } + + /* we are only interested in read events on the listen socket */ + fde.flags = EVENT_FD_READ; + fde.private = sock; + fde.handler = model_ops->accept_connection; + + ZERO_STRUCTP(sock); + sock->mem_ctx = mem_ctx; + sock->service = service; + sock->socket = socket_ctx; + sock->event.ctx = service->srv_ctx->events; + sock->event.fde = event_add_fd(sock->event.ctx, &fde); + if (!sock->event.fde) { + DEBUG(0,("event_add_fd(sock->event.ctx, &fde) failed\n")); + return NULL; + } + + DLIST_ADD(service->socket_list, sock); + + return sock; +} + +/* + close the socket and shutdown a server_context +*/ +void server_terminate_connection(struct server_connection *srv_conn, const char *reason) +{ + DEBUG(0,("server_terminate_connection\n")); + srv_conn->service->model_ops->terminate_connection(srv_conn, reason); +} + +void server_io_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) +{ + struct server_connection *conn = fde->private; + + if (flags & EVENT_FD_WRITE) { + conn->service->ops->send_handler(conn, t, flags); + conn->event.idle->next_event = t + conn->event.idle_time; + } + + if (flags & EVENT_FD_READ) { + conn->service->ops->recv_handler(conn, t, flags); + conn->event.idle->next_event = t + conn->event.idle_time; + } + +} + +void server_idle_handler(struct event_context *ev, struct timed_event *idle, time_t t) +{ + struct server_connection *conn = idle->private; + + conn->event.idle->next_event = t + conn->event.idle_time; + + conn->service->ops->idle_handler(conn,t); +} +/* + return the operations structure for a named backend of the specified type +*/ +const struct server_service_ops *server_service_byname(const char *name) +{ + if (strcmp("smb",name)==0) { + return smbsrv_get_ops(); + } + if (strcmp("rpc",name)==0) { + return dcesrv_get_ops(); + } + return NULL; +} + +static NTSTATUS register_server_service_ops(const void *_ops) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/* + initialise the SERVER SERVICE subsystem +*/ +BOOL server_service_init(void) +{ + NTSTATUS status; + + status = register_subsystem("service", register_server_service_ops); + if (!NT_STATUS_IS_OK(status)) { + return False; + } + + /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */ + static_init_server_service; + + DEBUG(3,("SERVER SERVICE subsystem version %d initialised\n", SERVER_SERVICE_VERSION)); + return True; +} |