diff options
Diffstat (limited to 'source4/smbd/service.c')
-rw-r--r-- | source4/smbd/service.c | 221 |
1 files changed, 117 insertions, 104 deletions
diff --git a/source4/smbd/service.c b/source4/smbd/service.c index 586c05c2c6..e0ec3cf07e 100644 --- a/source4/smbd/service.c +++ b/source4/smbd/service.c @@ -27,38 +27,33 @@ #include "dlinklist.h" #include "process_model.h" -struct server_context *server_service_startup(const char *model) +struct server_context *server_service_startup(const char *model, const char **server_services) { int i; - const char **server_services = lp_server_services(); - struct server_context *srv_ctx; - const struct model_ops *model_ops; + struct server_context *server; if (!server_services) { - DEBUG(0,("process_model_startup: no endpoint servers configured\n")); + DEBUG(0,("server_service_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; - } - - srv_ctx = talloc_p(NULL, struct server_context); - if (!srv_ctx) { + server = talloc_zero(NULL, struct server_context); + if (!server) { return NULL; } - ZERO_STRUCTP(srv_ctx); + server->model.ops = process_model_startup(server, model); + if (!server->model.ops) { + DEBUG(0,("process_model_startup('%s') failed\n", model)); + return NULL; + } - srv_ctx->events = event_context_init(srv_ctx); - if (!srv_ctx->events) { + server->event.ctx = event_context_init(server); + if (!server->event.ctx) { DEBUG(0,("event_context_init() failed\n")); - return NULL; + return NULL; } - for (i=0;server_services[i];i++) { const struct server_service_ops *service_ops; struct server_service *service; @@ -69,63 +64,64 @@ struct server_context *server_service_startup(const char *model) return NULL; } - service = talloc_p(srv_ctx, struct server_service); + service = talloc_zero(server, struct server_service); if (!service) { return NULL; } - ZERO_STRUCTP(service); - service->ops = service_ops; - service->model_ops = model_ops; - service->srv_ctx = srv_ctx; - + service->service.ops = service_ops; + service->server = server; + /* TODO: service_init() should return a result */ - service->ops->service_init(service, model_ops); + service->service.ops->service_init(service); - DLIST_ADD(srv_ctx->service_list, service); + DLIST_ADD(server->service_list, service); } - return srv_ctx; + return server; +} + +void server_service_shutdown(struct server_context *server, const char *reason) +{ + server->model.ops->model_exit(server, reason); } /* setup a listen stream socket 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, - const char *family, - const char *sock_addr, - uint16_t *port) +struct server_stream_socket *service_setup_stream_socket(struct server_service *service, + const struct server_stream_ops *stream_ops, + const char *family, + const char *sock_addr, + uint16_t *port) { NTSTATUS status; - struct server_socket *srv_sock; - struct socket_context *socket_ctx; + struct server_stream_socket *stream_socket; + struct socket_context *sock; struct fd_event fde; int i; - status = socket_create(family, SOCKET_TYPE_STREAM, &socket_ctx, 0); + status = socket_create(family, SOCKET_TYPE_STREAM, &sock, 0); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to open socket on %s:%u - %s\n", sock_addr, *port, nt_errstr(status))); return NULL; } - talloc_steal(service, socket_ctx); - /* ready to listen */ - status = socket_set_option(socket_ctx, "SO_KEEPALIVE SO_REUSEADDR=1", NULL); + status = socket_set_option(sock, "SO_KEEPALIVE SO_REUSEADDR=1", NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("socket_set_option(socket_ctx, SO_KEEPALIVE, NULL): %s\n", nt_errstr(status))); - socket_destroy(socket_ctx); + socket_destroy(sock); return NULL; } - status = socket_set_option(socket_ctx, lp_socket_options(), NULL); + status = socket_set_option(sock, lp_socket_options(), NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("socket_set_option(socket_ctx, lp_socket_options(), NULL): %s\n", nt_errstr(status))); - socket_destroy(socket_ctx); + socket_destroy(sock); return NULL; } @@ -133,64 +129,70 @@ struct server_socket *service_setup_socket(struct server_service *service, if (*port == 0) { for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) { - status = socket_listen(socket_ctx, sock_addr, i, SERVER_LISTEN_BACKLOG, 0); + status = socket_listen(sock, sock_addr, i, SERVER_LISTEN_BACKLOG, 0); if (NT_STATUS_IS_OK(status)) { *port = i; break; } } } else { - status = socket_listen(socket_ctx, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0); + status = socket_listen(sock, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0); } if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to listen on %s:%u - %s\n", sock_addr, *port, nt_errstr(status))); - socket_destroy(socket_ctx); + socket_destroy(sock); return NULL; } - srv_sock = talloc_p(service, struct server_socket); - if (!srv_sock) { - DEBUG(0,("talloc_p(mem_ctx, struct server_socket) failed\n")); - socket_destroy(socket_ctx); + stream_socket = talloc_zero(service, struct server_stream_socket); + if (!stream_socket) { + DEBUG(0,("talloc_p(mem_ctx, struct server_stream_socket) failed\n")); + socket_destroy(sock); return NULL; } /* we are only interested in read events on the listen socket */ - fde.fd = socket_get_fd(socket_ctx); + fde.fd = socket_get_fd(sock); fde.flags = EVENT_FD_READ; - fde.private = srv_sock; - fde.handler = model_ops->accept_connection; - - ZERO_STRUCTP(srv_sock); - srv_sock->service = service; - srv_sock->socket = socket_ctx; - srv_sock->event.ctx = service->srv_ctx->events; - srv_sock->event.fde = event_add_fd(srv_sock->event.ctx, &fde); - if (!srv_sock->event.fde) { - DEBUG(0,("event_add_fd(srv_sock->event.ctx, &fde) failed\n")); - socket_destroy(socket_ctx); + fde.private = stream_socket; + fde.handler = server_accept_handler; + + stream_socket->stream.ops = stream_ops; + stream_socket->service = service; + stream_socket->socket = sock; + stream_socket->event.ctx = service->server->event.ctx; + stream_socket->event.fde = event_add_fd(stream_socket->event.ctx, &fde); + if (!stream_socket->event.fde) { + DEBUG(0,("event_add_fd(stream_socket->event.ctx, &fde) failed\n")); + socket_destroy(sock); return NULL; } - DLIST_ADD(service->socket_list, srv_sock); + talloc_steal(stream_socket, sock); - return srv_sock; + if (stream_socket->stream.ops->socket_init) { + stream_socket->stream.ops->socket_init(stream_socket); + } + + return stream_socket; } /* destructor that handles necessary event context changes */ -static int server_destructor(void *ptr) +static int server_connection_destructor(void *ptr) { struct server_connection *conn = ptr; - if (conn->service) { - conn->service->ops->close_connection(conn, "shutdown"); - } - - socket_destroy(conn->socket); + if (conn->stream_socket && + conn->stream_socket->stream.ops->close_connection) { + /* don't remove this! the stream service needs to free it's data + * before we destroy the server_connection + */ + conn->stream_socket->stream.ops->close_connection(conn, "shutdown"); + } if (conn->event.fde) { event_remove_fd(conn->event.ctx, conn->event.fde); @@ -201,13 +203,11 @@ static int server_destructor(void *ptr) conn->event.idle = NULL; } - DLIST_REMOVE(conn->server_socket->connection_list, conn); - return 0; } struct server_connection *server_setup_connection(struct event_context *ev, - struct server_socket *server_socket, + struct server_stream_socket *stream_socket, struct socket_context *sock, struct timeval t, servid_t server_id) @@ -216,7 +216,7 @@ struct server_connection *server_setup_connection(struct event_context *ev, struct timed_event idle; struct server_connection *srv_conn; - srv_conn = talloc_p(server_socket, struct server_connection); + srv_conn = talloc_p(stream_socket, struct server_connection); if (!srv_conn) { DEBUG(0,("talloc_p(mem_ctx, struct server_connection) failed\n")); return NULL; @@ -238,20 +238,19 @@ struct server_connection *server_setup_connection(struct event_context *ev, srv_conn->event.idle = &idle; srv_conn->event.idle_time = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0); - srv_conn->server_socket = server_socket; - srv_conn->service = server_socket->service; + srv_conn->stream_socket = stream_socket; srv_conn->socket = sock; - srv_conn->server_id = server_id; + srv_conn->connection.id = server_id; /* create a server context and add it to out event handling */ - server_socket->service->ops->accept_connection(srv_conn); + stream_socket->stream.ops->accept_connection(srv_conn); /* accpect_connection() of the service may changed idle.next_event */ srv_conn->event.fde = event_add_fd(ev,&fde); srv_conn->event.idle = event_add_timed(ev,&idle); - talloc_set_destructor(srv_conn, server_destructor); + talloc_set_destructor(srv_conn, server_connection_destructor); if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) { server_terminate_connection(srv_conn, "denied by access rules"); @@ -259,7 +258,11 @@ struct server_connection *server_setup_connection(struct event_context *ev, } /* setup to receive internal messages on this connection */ - srv_conn->messaging_ctx = messaging_init(srv_conn, srv_conn->server_id, ev); + srv_conn->messaging.ctx = messaging_init(srv_conn, srv_conn->connection.id, ev); + if (!srv_conn->messaging.ctx) { + server_terminate_connection(srv_conn, "messaging_init() failed"); + return NULL; + } return srv_conn; } @@ -270,7 +273,15 @@ struct server_connection *server_setup_connection(struct event_context *ev, void server_terminate_connection(struct server_connection *srv_conn, const char *reason) { DEBUG(2,("server_terminate_connection\n")); - srv_conn->service->model_ops->terminate_connection(srv_conn, reason); + srv_conn->stream_socket->service->server->model.ops->terminate_connection(srv_conn, reason); +} + +void server_accept_handler(struct event_context *ev, struct fd_event *fde, + struct timeval t, uint16_t flags) +{ + struct server_stream_socket *stream_socket = fde->private; + + stream_socket->service->server->model.ops->accept_connection(ev, fde, t, flags); } void server_io_handler(struct event_context *ev, struct fd_event *fde, @@ -281,12 +292,12 @@ void server_io_handler(struct event_context *ev, struct fd_event *fde, conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time); if (flags & EVENT_FD_WRITE) { - conn->service->ops->send_handler(conn, t, flags); + conn->stream_socket->stream.ops->send_handler(conn, t, flags); return; } if (flags & EVENT_FD_READ) { - conn->service->ops->recv_handler(conn, t, flags); + conn->stream_socket->stream.ops->recv_handler(conn, t, flags); } } @@ -296,13 +307,34 @@ void server_idle_handler(struct event_context *ev, struct timed_event *idle, { struct server_connection *conn = idle->private; - conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time); - /* Not all services provide an idle handler */ - if (conn->service->ops->idle_handler) { - conn->service->ops->idle_handler(conn, t); + if (conn->stream_socket->stream.ops->idle_handler) { + conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time); + conn->stream_socket->stream.ops->idle_handler(conn, t); } } + +void server_terminate_task(struct server_task *task, const char *reason) +{ + task->service->server->model.ops->terminate_task(task, reason); + return; +} + +void server_run_task(struct server_service *service, const struct server_task_ops *ops) +{ + struct server_task *task; + + task = talloc_zero(service, struct server_task); + if (!task) { + return; + } + task->service = service; + task->task.ops = ops; + + service->server->model.ops->create_task(task); + return; +} + /* return the operations structure for a named backend of the specified type */ @@ -326,25 +358,6 @@ NTSTATUS register_server_service_ops(const void *_ops) } /* - close all listening sockets. This is called by process models that fork, to - ensure that the listen sockets from the parent are closed -*/ -void service_close_listening_sockets(struct server_context *srv_ctx) -{ - struct server_service *svc; - for (svc=srv_ctx->service_list;svc;svc=svc->next) { - struct server_socket *sock; - for (sock=svc->socket_list;sock;sock=sock->next) { - event_remove_fd(sock->event.ctx, sock->event.fde); - sock->event.fde = NULL; - socket_destroy(sock->socket); - sock->socket = NULL; - } - } -} - - -/* cleanup temporary files. This is the new alternative to TDB_CLEAR_IF_FIRST. Unfortunately TDB_CLEAR_IF_FIRST is not efficient on unix systems due to the lack of scaling of the byte |