diff options
author | Andrew Tridgell <tridge@samba.org> | 2005-01-30 00:54:57 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:09:22 -0500 |
commit | 55d4d36993293fee914a009f1d8f05810e347f2b (patch) | |
tree | 587a9bafd1c8df901aad8766acb0fe9ef4c3d8c0 /source4/smbd/service.c | |
parent | 5540449f1cd9d9a6efab59f2bf47be4e1487ffc2 (diff) | |
download | samba-55d4d36993293fee914a009f1d8f05810e347f2b.tar.gz |
r5102: This is a major simplification of the logic for controlling top level
servers in smbd. The old code still contained a fairly bit of legacy
from the time when smbd was only handling SMB connection. The new code
gets rid of all of the smb_server specific code in smbd/, and creates
a much simpler infrastructures for new server code.
Major changes include:
- simplified the process model code a lot.
- got rid of the top level server and service structures
completely. The top level context is now the event_context. This
got rid of service.h and server.h completely (they were the most
confusing parts of the old code)
- added service_stream.[ch] for the helper functions that are
specific to stream type services (services that handle streams, and
use a logically separate process per connection)
- got rid of the builtin idle_handler code in the service logic, as
none of the servers were using it, and it can easily be handled by
a server in future by adding its own timed_event to the event
context.
- fixed some major memory leaks in the rpc server code.
- added registration of servers, rather than hard coding our list of
possible servers. This allows for servers as modules in the future.
- temporarily disabled the winbind code until I add the helper
functions for that type of server
- added error checking on service startup. If a configured server
fails to startup then smbd doesn't startup.
- cleaned up the command line handling in smbd, removing unused options
(This used to be commit cf6a46c3cbde7b1eb1b86bd3882b953a2de3a42e)
Diffstat (limited to 'source4/smbd/service.c')
-rw-r--r-- | source4/smbd/service.c | 394 |
1 files changed, 47 insertions, 347 deletions
diff --git a/source4/smbd/service.c b/source4/smbd/service.c index 2d532b638d5..ab377dc29b2 100644 --- a/source4/smbd/service.c +++ b/source4/smbd/service.c @@ -3,7 +3,7 @@ SERVER SERVICE code - Copyright (C) Andrew Tridgell 2003 + Copyright (C) Andrew Tridgell 2003-2005 Copyright (C) Stefan (metze) Metzmacher 2004 This program is free software; you can redistribute it and/or modify @@ -22,377 +22,77 @@ */ #include "includes.h" -#include "events.h" -#include "system/dir.h" #include "dlinklist.h" #include "process_model.h" -struct server_context *server_service_startup(const char *model, const char **server_services) -{ - int i; - struct server_context *server; - - if (!server_services) { - DEBUG(0,("server_service_startup: no endpoint servers configured\n")); - return NULL; - } - - server = talloc_zero(NULL, struct server_context); - if (!server) { - return NULL; - } - - server->model.ops = process_model_startup(server, model); - if (!server->model.ops) { - DEBUG(0,("process_model_startup('%s') failed\n", model)); - return NULL; - } - - server->event.ctx = event_context_init(server); - if (!server->event.ctx) { - DEBUG(0,("event_context_init() failed\n")); - return NULL; - } - - for (i=0;server_services[i];i++) { - 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; - } - - service = talloc_zero(server, struct server_service); - if (!service) { - return NULL; - } - - service->service.ops = service_ops; - service->server = server; - - /* TODO: service_init() should return a result */ - service->service.ops->service_init(service); - - DLIST_ADD(server->service_list, service); - } - - 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_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_stream_socket *stream_socket; - struct socket_context *sock; - struct fd_event fde; - int i; - - 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; - } - - /* ready to listen */ - 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(sock); - return 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(sock); - return NULL; - } - - /* TODO: set socket ACL's here when they're implemented */ - - if (*port == 0) { - for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) { - status = socket_listen(sock, sock_addr, i, SERVER_LISTEN_BACKLOG, 0); - if (NT_STATUS_IS_OK(status)) { - *port = i; - break; - } - } - } else { - 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(sock); - return NULL; - } - - stream_socket = talloc_zero(service, struct server_stream_socket); - if (!stream_socket) { - DEBUG(0,("talloc(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(sock); - fde.flags = EVENT_FD_READ; - 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, stream_socket); - if (!stream_socket->event.fde) { - socket_destroy(sock); - return NULL; - } - - talloc_steal(stream_socket, 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_connection_destructor(void *ptr) -{ - struct server_connection *conn = ptr; - - 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"); - } - - return 0; -} - -struct server_connection *server_setup_connection(struct event_context *ev, - struct server_stream_socket *stream_socket, - struct socket_context *sock, - struct timeval t, - servid_t server_id) -{ - struct fd_event fde; - struct timed_event idle; - struct server_connection *srv_conn; - - srv_conn = talloc(stream_socket, struct server_connection); - if (!srv_conn) { - DEBUG(0,("talloc(mem_ctx, struct server_connection) failed\n")); - return NULL; - } - - ZERO_STRUCTP(srv_conn); - - fde.private = srv_conn; - fde.fd = socket_get_fd(sock); - fde.flags = EVENT_FD_READ; - fde.handler = server_io_handler; - - idle.private = srv_conn; - idle.next_event = timeval_add(&t, SERVER_DEFAULT_IDLE_TIME, 0); - idle.handler = server_idle_handler; - - srv_conn->event.ctx = ev; - srv_conn->event.fde = &fde; - srv_conn->event.idle = &idle; - srv_conn->event.idle_time = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0); - - srv_conn->stream_socket = stream_socket; - srv_conn->socket = sock; - srv_conn->connection.id = server_id; - - /* create a server context and add it to out event - handling */ - 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); - srv_conn->event.idle = event_add_timed(ev, &idle, srv_conn); - - 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"); - return NULL; - } - - /* setup to receive internal messages on this connection */ - 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; -} + a linked list of registered servers +*/ +static struct registered_server { + struct registered_server *next, *prev; + const char *service_name; + NTSTATUS (*service_init)(struct event_context *, const struct model_ops *); +} *registered_servers; /* - close the socket and shutdown a server_context + register a server service. */ -void server_terminate_connection(struct server_connection *srv_conn, const char *reason) -{ - DEBUG(2,("server_terminate_connection\n")); - 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) +NTSTATUS register_server_service(const char *name, + NTSTATUS (*service_init)(struct event_context *, const struct model_ops *)) { - struct server_stream_socket *stream_socket = talloc_get_type(fde->private, - struct server_stream_socket); - - stream_socket->service->server->model.ops->accept_connection(ev, fde, t, flags); + struct registered_server *srv; + srv = talloc(talloc_autofree_context(), struct registered_server); + NT_STATUS_HAVE_NO_MEMORY(srv); + srv->service_name = name; + srv->service_init = service_init; + DLIST_ADD_END(registered_servers, srv, struct registered_server *); + return NT_STATUS_OK; } -void server_io_handler(struct event_context *ev, struct fd_event *fde, - struct timeval t, uint16_t flags) -{ - struct server_connection *conn = talloc_get_type(fde->private, - struct server_connection); - - conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time); - - if (flags & EVENT_FD_WRITE) { - conn->stream_socket->stream.ops->send_handler(conn, t, flags); - return; - } - - if (flags & EVENT_FD_READ) { - conn->stream_socket->stream.ops->recv_handler(conn, t, flags); - } - -} - -void server_idle_handler(struct event_context *ev, struct timed_event *idle, - struct timeval t) -{ - struct server_connection *conn = talloc_get_type(idle->private, - struct server_connection); - - /* Not all services provide an idle handler */ - 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 + initialise a server service */ -const struct server_service_ops *server_service_byname(const char *name) +static NTSTATUS server_service_init(const char *name, + struct event_context *event_ctx, + const struct model_ops *model_ops) { - if (strcmp("smb",name)==0) { - return smbsrv_get_ops(); - } - if (strcmp("rpc",name)==0) { - return dcesrv_get_ops(); - } - if (strcmp("ldap",name)==0) { - return ldapsrv_get_ops(); - } - if (strcmp("winbind",name)==0) { - return winbind_get_ops(); - } - if (strcmp("winbind_task",name)==0) { - return winbind_task_get_ops(); + struct registered_server *srv; + for (srv=registered_servers; srv; srv=srv->next) { + if (strcasecmp(name, srv->service_name) == 0) { + return srv->service_init(event_ctx, model_ops); + } } - return NULL; + return NT_STATUS_INVALID_SYSTEM_SERVICE; } -NTSTATUS register_server_service_ops(const void *_ops) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} /* - 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 - range locking system. So instead of putting the burden on tdb to - cleanup tmp files, this function deletes them. + startup all of our server services */ -void service_cleanup_tmp_files(void) +NTSTATUS server_service_startup(struct event_context *event_ctx, + const char *model, const char **server_services) { - char *path; - DIR *dir; - struct dirent *de; - TALLOC_CTX *mem_ctx = talloc_init("service_cleanup_tmp_files"); + int i; + const struct model_ops *model_ops; - path = smbd_tmp_path(mem_ctx, NULL); + if (!server_services) { + DEBUG(0,("server_service_startup: no endpoint servers configured\n")); + return NT_STATUS_INVALID_PARAMETER; + } - dir = opendir(path); - if (!dir) { - talloc_free(mem_ctx); - return; + model_ops = process_model_startup(event_ctx, model); + if (!model_ops) { + DEBUG(0,("process_model_startup('%s') failed\n", model)); + return NT_STATUS_INTERNAL_ERROR; } - for (de=readdir(dir);de;de=readdir(dir)) { - char *fname = talloc_asprintf(mem_ctx, "%s/%s", path, de->d_name); - int ret = unlink(fname); - if (ret == -1 && - errno != ENOENT && - errno != EISDIR && - errno != EISDIR) { - DEBUG(0,("Unabled to delete '%s' - %s\n", - fname, strerror(errno))); - smb_panic("unable to cleanup tmp files"); - } - talloc_free(fname); + for (i=0;server_services[i];i++) { + NTSTATUS status; + + status = server_service_init(server_services[i], event_ctx, model_ops); + NT_STATUS_NOT_OK_RETURN(status); } - closedir(dir); - talloc_free(mem_ctx); + return NT_STATUS_OK; } |