From 45a85bdd353418828df8017a9d7eb7c14f6f0cd3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Jul 2004 21:04:56 +0000 Subject: r1486: commit the start of the generic server infastructure the idea is to have services as modules (smb, dcerpc, swat, ...) the process_model don't know about the service it self anymore. TODO: - the smbsrv should use the smbsrv_send function - the service subsystem init should be done like for other modules - we need to have a generic socket subsystem, which handle stream, datagram, and virtuell other sockets( e.g. for the ntvfs_ipc module to connect to the dcerpc server , or for smb or dcerpc or whatever to connect to a server wide auth service) - and other fixes... NOTE: process model pthread seems to be broken( but also before this patch!) metze (This used to be commit bbe5e00715ca4013ff0dbc345aa97adc6b5c2458) --- source4/smbd/config.m4 | 7 +- source4/smbd/config.mk | 24 ++-- source4/smbd/process_model.c | 10 +- source4/smbd/process_model.h | 17 ++- source4/smbd/process_single.c | 119 +++++++++++++------- source4/smbd/process_standard.c | 138 ++++++++++++----------- source4/smbd/process_thread.c | 153 ++++++++++++++----------- source4/smbd/rewrite.c | 6 +- source4/smbd/server.c | 42 +++---- source4/smbd/server.h | 40 +++++++ source4/smbd/service.c | 241 ++++++++++++++++++++++++++++++++++++++++ source4/smbd/service.h | 127 +++++++++++++++++++++ 12 files changed, 705 insertions(+), 219 deletions(-) create mode 100644 source4/smbd/server.h create mode 100644 source4/smbd/service.c create mode 100644 source4/smbd/service.h (limited to 'source4/smbd') diff --git a/source4/smbd/config.m4 b/source4/smbd/config.m4 index dd7a707714..52ccb68aa8 100644 --- a/source4/smbd/config.m4 +++ b/source4/smbd/config.m4 @@ -1,9 +1,10 @@ dnl # server subsystem -SMB_MODULE_MK(server_smb,SERVER,STATIC,smbd/config.mk) -SMB_MODULE_MK(server_rpc,SERVER,STATIC,smbd/config.mk) -SMB_MODULE_MK(server_auth,SERVER,STATIC,smbd/config.mk) +SMB_MODULE_MK(server_service_auth,SERVER_SERVICE,STATIC,smbd/config.mk) +SMB_MODULE_MK(server_service_smb,SERVER_SERVICE,STATIC,smbd/config.mk) +SMB_MODULE_MK(server_service_rpc,SERVER_SERVICE,STATIC,smbd/config.mk) +SMB_SUBSYSTEM_MK(SERVER_SERVICE,smbd/config.mk) SMB_SUBSYSTEM_MK(SERVER,smbd/config.mk) SMB_BINARY_MK(smbd, smbd/config.mk) diff --git a/source4/smbd/config.mk b/source4/smbd/config.mk index cd0d80150b..f002341a26 100644 --- a/source4/smbd/config.mk +++ b/source4/smbd/config.mk @@ -1,39 +1,47 @@ # server subsystem ################################################ -# Start MODULE server_auth -[MODULE::server_auth] +# Start MODULE server_service_auth +[MODULE::server_service_auth] REQUIRED_SUBSYSTEMS = \ AUTH # End MODULE server_auth ################################################ ################################################ -# Start MODULE server_smb -[MODULE::server_smb] +# Start MODULE server_service_smb +[MODULE::server_service_smb] REQUIRED_SUBSYSTEMS = \ SMB # End MODULE server_smb ################################################ ################################################ -# Start MODULE server_rpc -[MODULE::server_rpc] +# Start MODULE server_service_rpc +[MODULE::server_service_rpc] REQUIRED_SUBSYSTEMS = \ DCERPC # End MODULE server_rpc ################################################ +####################### +# Start SUBSYSTEM SERVICE +[SUBSYSTEM::SERVER_SERVICE] +INIT_OBJ_FILES = \ + smbd/service.o +# End SUBSYSTEM SERVER +####################### + ####################### # Start SUBSYSTEM SERVER [SUBSYSTEM::SERVER] INIT_OBJ_FILES = \ smbd/server.o ADD_OBJ_FILES = \ - smbd/build_options.o \ smbd/rewrite.o REQUIRED_SUBSYSTEMS = \ - PROCESS_MODEL + PROCESS_MODEL \ + SERVER_SERVICE # End SUBSYSTEM SERVER ####################### diff --git a/source4/smbd/process_model.c b/source4/smbd/process_model.c index f981b36798..0bdb316317 100644 --- a/source4/smbd/process_model.c +++ b/source4/smbd/process_model.c @@ -24,8 +24,7 @@ /* setup the events for the chosen process model */ -void process_model_startup(struct event_context *events, - const char *model) +const struct model_ops *process_model_startup(const char *model) { const struct model_ops *ops; @@ -37,12 +36,7 @@ void process_model_startup(struct event_context *events, ops->model_startup(); - /* now setup the listening sockets, adding - event handlers to the events structure */ - open_sockets_smbd(events, ops); - - /* setup any sockets we need to listen on for RPC over TCP */ - open_sockets_rpc(events, ops); + return ops; } /* the list of currently registered process models */ diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h index c4c3aa68df..376b9a8ef8 100644 --- a/source4/smbd/process_model.h +++ b/source4/smbd/process_model.h @@ -3,6 +3,7 @@ process model manager - main loop Copyright (C) Andrew Tridgell 1992-2003 Copyright (C) James J Myers 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 @@ -22,6 +23,8 @@ #ifndef SAMBA_PROCESS_MODEL_H #define SAMBA_PROCESS_MODEL_H +struct server_service_connection; + /* modules can use the following to determine if the interface has changed * please increment the version number after each interface change * with a comment and maybe update struct process_model_critical_sizes. @@ -40,19 +43,13 @@ struct model_ops { /* function to accept new connection */ void (*accept_connection)(struct event_context *, struct fd_event *, time_t, uint16_t); - - /* function to accept new rpc over tcp connection */ - void (*accept_rpc_connection)(struct event_context *, struct fd_event *, time_t, uint16_t); - + /* function to terminate a connection */ - void (*terminate_connection)(struct smbsrv_connection *smb, const char *reason); + void (*terminate_connection)(struct server_connection *srv_conn, const char *reason); - /* function to terminate a connection */ - void (*terminate_rpc_connection)(void *r, const char *reason); - /* function to exit server */ - void (*exit_server)(struct smbsrv_connection *smb, const char *reason); - + void (*exit_server)(struct server_context *srv_ctx, const char *reason); + /* returns process or thread id */ int (*get_id)(struct smbsrv_request *req); }; diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c index 9c92d8569a..b65418cd01 100644 --- a/source4/smbd/process_single.c +++ b/source4/smbd/process_single.c @@ -3,6 +3,7 @@ process model: process (1 process handles all client connections) Copyright (C) Andrew Tridgell 2003 Copyright (C) James J Myers 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 @@ -21,10 +22,11 @@ #include "includes.h" + /* called when the process model is selected */ -static void model_startup(void) +static void single_start_server(void) { smbd_process_init(); } @@ -32,67 +34,102 @@ static void model_startup(void) /* called when a listening socket becomes readable */ -static void accept_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) +static void single_accept_connection(struct event_context *ev, struct fd_event *srv_fde, time_t t, uint16_t flags) { int accepted_fd; struct sockaddr addr; socklen_t in_addrlen = sizeof(addr); - struct model_ops *model_ops = fde->private; - + struct fd_event fde; + struct timed_event idle; + struct server_socket *server_socket = srv_fde->private; + struct server_connection *conn; + TALLOC_CTX *mem_ctx; + /* accept an incoming connection. */ - accepted_fd = accept(fde->fd,&addr,&in_addrlen); + accepted_fd = accept(srv_fde->fd,&addr,&in_addrlen); if (accepted_fd == -1) { DEBUG(0,("accept_connection_single: accept: %s\n", strerror(errno))); return; } - /* create a smb server context and add it to out event - handling */ - init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler); + mem_ctx = talloc_init("server_service_connection"); + if (!mem_ctx) { + DEBUG(0,("talloc_init(server_service_connection) failed\n")); + return; + } - /* return to event handling */ -} + conn = talloc_p(mem_ctx, struct server_connection); + if (!conn) { + DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n")); + talloc_destroy(mem_ctx); + return; + } + ZERO_STRUCTP(conn); + conn->mem_ctx = mem_ctx; -/* - called when a rpc listening socket becomes readable -*/ -static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) -{ - int accepted_fd; - struct sockaddr addr; - socklen_t in_addrlen = sizeof(addr); - - /* accept an incoming connection. */ - accepted_fd = accept(fde->fd,&addr,&in_addrlen); - if (accepted_fd == -1) { - DEBUG(0,("accept_connection_single: accept: %s\n", - strerror(errno))); + fde.private = conn; + fde.fd = accepted_fd; + fde.flags = EVENT_FD_READ; + fde.handler = server_io_handler; + + idle.private = conn; + idle.next_event = t + 300; + idle.handler = server_idle_handler; + + conn->event.ctx = ev; + conn->event.fde = &fde; + conn->event.idle = &idle; + conn->event.idle_time = 300; + + conn->server_socket = server_socket; + conn->service = server_socket->service; + + /* TODO: we need a generic socket subsystem */ + conn->socket = talloc_p(conn->mem_ctx, struct socket_context); + if (!conn->socket) { + DEBUG(0,("talloc_p(conn->mem_ctx, struct socket_context) failed\n")); + talloc_destroy(mem_ctx); return; } + conn->socket->private_data = NULL; + conn->socket->ops = NULL; + conn->socket->client_addr = NULL; + conn->socket->pkt_count = 0; + conn->socket->fde = conn->event.fde; - init_rpc_session(ev, fde->private, accepted_fd); -} + /* create a smb server context and add it to out event + handling */ + server_socket->service->ops->accept_connection(conn); -/* called when a SMB connection goes down */ -static void terminate_connection(struct smbsrv_connection *server, const char *reason) -{ - server_terminate(server); + /* accpect_connection() of the service may changed idle.next_event */ + conn->event.fde = event_add_fd(ev,&fde); + conn->event.idle = event_add_timed(ev,&idle); + + conn->socket->fde = conn->event.fde; + + DLIST_ADD(server_socket->connection_list,conn); + + /* return to event handling */ + return; } -/* called when a rpc connection goes down */ -static void terminate_rpc_connection(void *r, const char *reason) + + +/* called when a SMB connection goes down */ +static void single_terminate_connection(struct server_connection *conn, const char *reason) { - rpc_server_terminate(r); + DEBUG(0,("single_terminate_connection: reason[%s]\n",reason)); + conn->service->ops->close_connection(conn,reason); } -static int get_id(struct smbsrv_request *req) +static int single_get_id(struct smbsrv_request *req) { return (int)req->smb_conn->pid; } -static void single_exit_server(struct smbsrv_connection *smb, const char *reason) +static void single_exit_server(struct server_context *srv_ctx, const char *reason) { DEBUG(1,("single_exit_server: reason[%s]\n",reason)); } @@ -111,13 +148,11 @@ NTSTATUS process_model_single_init(void) ops.name = "single"; /* fill in all the operations */ - ops.model_startup = model_startup; - ops.accept_connection = accept_connection; - ops.accept_rpc_connection = accept_rpc_connection; - ops.terminate_connection = terminate_connection; - ops.terminate_rpc_connection = terminate_rpc_connection; - ops.exit_server = single_exit_server; - ops.get_id = get_id; + ops.model_startup = single_start_server; + ops.accept_connection = single_accept_connection; + ops.terminate_connection = single_terminate_connection; + ops.exit_server = single_exit_server; + ops.get_id = single_get_id; /* register ourselves with the PROCESS_MODEL subsystem. */ ret = register_backend("process_model", &ops); diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c index 2ee486e1d2..cc02e84d57 100644 --- a/source4/smbd/process_standard.c +++ b/source4/smbd/process_standard.c @@ -3,6 +3,7 @@ process model: standard (1 process per client connection) Copyright (C) Andrew Tridgell 1992-2003 Copyright (C) James J Myers 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 @@ -24,25 +25,31 @@ /* called when the process model is selected */ -static void model_startup(void) +static void standard_model_startup(void) { signal(SIGCHLD, SIG_IGN); + smbd_process_init(); } /* called when a listening socket becomes readable */ -static void accept_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) +static void standard_accept_connection(struct event_context *ev, struct fd_event *srv_fde, time_t t, uint16_t flags) { int accepted_fd; struct sockaddr addr; socklen_t in_addrlen = sizeof(addr); pid_t pid; - struct model_ops *model_ops = fde->private; - - accepted_fd = accept(fde->fd,&addr,&in_addrlen); + struct fd_event fde; + struct timed_event idle; + struct server_socket *server_socket = srv_fde->private; + struct server_connection *conn; + TALLOC_CTX *mem_ctx; + + /* accept an incoming connection. */ + accepted_fd = accept(srv_fde->fd,&addr,&in_addrlen); if (accepted_fd == -1) { - DEBUG(0,("accept_connection_standard: accept: %s\n", + DEBUG(0,("standard_accept_connection: accept: %s\n", strerror(errno))); return; } @@ -60,82 +67,91 @@ static void accept_connection(struct event_context *ev, struct fd_event *fde, ti /* Child code ... */ /* close all the listening sockets */ - event_remove_fd_all_handler(ev, model_ops->accept_connection); - event_remove_fd_all_handler(ev, model_ops->accept_rpc_connection); + event_remove_fd_all_handler(ev, standard_accept_connection); /* tdb needs special fork handling */ if (tdb_reopen_all() == -1) { - DEBUG(0,("accept_connection_standard: tdb_reopen_all failed.\n")); + DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n")); } - /* Load DSO's */ - init_modules(); - - /* initialize new process */ - smbd_process_init(); - - init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler); - - /* return to the event loop */ -} - -/* - called when a rpc listening socket becomes readable -*/ -static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) -{ - int accepted_fd; - struct sockaddr addr; - socklen_t in_addrlen = sizeof(addr); - pid_t pid; + mem_ctx = talloc_init("server_service_connection"); + if (!mem_ctx) { + DEBUG(0,("talloc_init(server_service_connection) failed\n")); + return; + } - accepted_fd = accept(fde->fd,&addr,&in_addrlen); - if (accepted_fd == -1) { - DEBUG(0,("accept_connection_standard: accept: %s\n", - strerror(errno))); + conn = talloc_p(mem_ctx, struct server_connection); + if (!conn) { + DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n")); + talloc_destroy(mem_ctx); return; } - pid = fork(); + ZERO_STRUCTP(conn); + conn->mem_ctx = mem_ctx; - if (pid != 0) { - /* parent or error code ... */ - close(accepted_fd); - /* go back to the event loop */ + fde.private = conn; + fde.fd = accepted_fd; + fde.flags = EVENT_FD_READ; + fde.handler = server_io_handler; + + idle.private = conn; + idle.next_event = t + 300; + idle.handler = server_idle_handler; + + + conn->event.ctx = ev; + conn->event.fde = &fde; + conn->event.idle = &idle; + conn->event.idle_time = 300; + + conn->server_socket = server_socket; + conn->service = server_socket->service; + + /* TODO: we need a generic socket subsystem */ + conn->socket = talloc_p(conn->mem_ctx, struct socket_context); + if (!conn->socket) { + DEBUG(0,("talloc_p(conn->mem_ctx, struct socket_context) failed\n")); + talloc_destroy(mem_ctx); return; } + conn->socket->private_data = NULL; + conn->socket->ops = NULL; + conn->socket->client_addr = NULL; + conn->socket->pkt_count = 0; + conn->socket->fde = conn->event.fde; - /* Child code ... */ + /* create a smb server context and add it to out event + handling */ + server_socket->service->ops->accept_connection(conn); - /* close all the listening sockets */ - event_remove_fd_all_handler(ev, accept_connection); - event_remove_fd_all_handler(ev, accept_rpc_connection); - - init_rpc_session(ev, fde->private, accepted_fd); -} + /* accpect_connection() of the service may changed idle.next_event */ + conn->event.fde = event_add_fd(ev,&fde); + conn->event.idle = event_add_timed(ev,&idle); -/* called when a SMB connection goes down */ -static void terminate_connection(struct smbsrv_connection *server, const char *reason) -{ - server_terminate(server); - /* terminate this process */ - exit(0); + conn->socket->fde = conn->event.fde; + + DLIST_ADD(server_socket->connection_list,conn); + + /* return to the event loop */ } -/* called when a rpc connection goes down */ -static void terminate_rpc_connection(void *r, const char *reason) + +/* called when a SMB connection goes down */ +static void standard_terminate_connection(struct server_connection *conn, const char *reason) { - rpc_server_terminate(r); + DEBUG(0,("single_terminate_connection: reason[%s]\n",reason)); + conn->service->ops->close_connection(conn,reason); /* terminate this process */ exit(0); } -static int get_id(struct smbsrv_request *req) +static int standard_get_id(struct smbsrv_request *req) { return (int)req->smb_conn->pid; } -static void standard_exit_server(struct smbsrv_connection *smb, const char *reason) +static void standard_exit_server(struct server_context *srv_ctx, const char *reason) { DEBUG(1,("standard_exit_server: reason[%s]\n",reason)); } @@ -154,13 +170,11 @@ NTSTATUS process_model_standard_init(void) ops.name = "standard"; /* fill in all the operations */ - ops.model_startup = model_startup; - ops.accept_connection = accept_connection; - ops.accept_rpc_connection = accept_rpc_connection; - ops.terminate_connection = terminate_connection; - ops.terminate_rpc_connection = terminate_rpc_connection; + ops.model_startup = standard_model_startup; + ops.accept_connection = standard_accept_connection; + ops.terminate_connection = standard_terminate_connection; ops.exit_server = standard_exit_server; - ops.get_id = get_id; + ops.get_id = standard_get_id; /* register ourselves with the PROCESS_MODEL subsystem. */ ret = register_backend("process_model", &ops); diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c index f79f34e389..553e67feeb 100644 --- a/source4/smbd/process_thread.c +++ b/source4/smbd/process_thread.c @@ -3,6 +3,7 @@ thread model: standard (1 thread per client connection) Copyright (C) Andrew Tridgell 2003 Copyright (C) James J Myers 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 @@ -25,19 +26,19 @@ #include "execinfo.h" #endif -static void *connection_thread(void *thread_parm) +static void *thread_connection_fn(void *thread_parm) { struct event_context *ev = thread_parm; /* wait for action */ event_loop_wait(ev); - + #if 0 pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */ #endif return NULL; } -static int get_id(struct smbsrv_request *req) +static int thread_get_id(struct smbsrv_request *req) { return (int)pthread_self(); } @@ -45,21 +46,24 @@ static int get_id(struct smbsrv_request *req) /* called when a listening socket becomes readable */ -static void accept_connection(struct event_context *ev, struct fd_event *fde, +static void thread_accept_connection(struct event_context *ev, struct fd_event *srv_fde, time_t t, uint16_t flags) -{ +{ int accepted_fd, rc; struct sockaddr addr; socklen_t in_addrlen = sizeof(addr); pthread_t thread_id; pthread_attr_t thread_attr; - struct model_ops *model_ops = fde->private; - - /* accept an incoming connection */ - accepted_fd = accept(fde->fd,&addr,&in_addrlen); - + struct fd_event fde; + struct timed_event idle; + struct server_socket *server_socket = srv_fde->private; + struct server_connection *conn; + TALLOC_CTX *mem_ctx; + + /* accept an incoming connection. */ + accepted_fd = accept(srv_fde->fd,&addr,&in_addrlen); if (accepted_fd == -1) { - DEBUG(0,("accept_connection_thread: accept: %s\n", + DEBUG(0,("standard_accept_connection: accept: %s\n", strerror(errno))); return; } @@ -70,52 +74,80 @@ static void accept_connection(struct event_context *ev, struct fd_event *fde, with the main event loop, then return. When we return the main event_context is continued. */ + + ev = event_context_init(); - MUTEX_LOCK_BY_ID(MUTEX_SMBD); - init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler); - MUTEX_UNLOCK_BY_ID(MUTEX_SMBD); - - pthread_attr_init(&thread_attr); - pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev); - pthread_attr_destroy(&thread_attr); - if (rc == 0) { - DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", - (unsigned long int)thread_id, accepted_fd)); - } else { - DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", accepted_fd, rc)); + if (!ev) { + DEBUG(0,("thread_accept_connection: failed to create event_context!\n")); + return; } -} + mem_ctx = talloc_init("server_service_connection"); + if (!mem_ctx) { + DEBUG(0,("talloc_init(server_service_connection) failed\n")); + return; + } -/* - called when a rpc listening socket becomes readable -*/ -static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) -{ - int accepted_fd, rc; - struct sockaddr addr; - socklen_t in_addrlen = sizeof(addr); - pthread_t thread_id; - pthread_attr_t thread_attr; - - /* accept an incoming connection */ - accepted_fd = accept(fde->fd,&addr,&in_addrlen); - - if (accepted_fd == -1) { - DEBUG(0,("accept_connection_thread: accept: %s\n", - strerror(errno))); + conn = talloc_p(mem_ctx, struct server_connection); + if (!conn) { + DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n")); + talloc_destroy(mem_ctx); return; } - - ev = event_context_init(); + + ZERO_STRUCTP(conn); + conn->mem_ctx = mem_ctx; + + fde.private = conn; + fde.fd = accepted_fd; + fde.flags = EVENT_FD_READ; + fde.handler = server_io_handler; + + idle.private = conn; + idle.next_event = t + 300; + idle.handler = server_idle_handler; + + conn->event.ctx = ev; + conn->event.fde = &fde; + conn->event.idle = &idle; + conn->event.idle_time = 300; + + conn->server_socket = server_socket; + conn->service = server_socket->service; + + /* TODO: we need a generic socket subsystem */ + conn->socket = talloc_p(conn->mem_ctx, struct socket_context); + if (!conn->socket) { + DEBUG(0,("talloc_p(conn->mem_ctx, struct socket_context) failed\n")); + talloc_destroy(mem_ctx); + return; + } + conn->socket->private_data = NULL; + conn->socket->ops = NULL; + conn->socket->client_addr = NULL; + conn->socket->pkt_count = 0; + conn->socket->fde = conn->event.fde; + + /* create a smb server context and add it to out event + handling */ + server_socket->service->ops->accept_connection(conn); + + /* accpect_connection() of the service may changed idle.next_event */ + conn->event.fde = event_add_fd(ev,&fde); + conn->event.idle = event_add_timed(ev,&idle); + + conn->socket->fde = conn->event.fde; + + /* TODO: is this MUTEX_LOCK in the right place here? + * --metze + */ MUTEX_LOCK_BY_ID(MUTEX_SMBD); - init_rpc_session(ev, fde->private, accepted_fd); + DLIST_ADD(server_socket->connection_list,conn); MUTEX_UNLOCK_BY_ID(MUTEX_SMBD); pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev); + rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, ev); pthread_attr_destroy(&thread_attr); if (rc == 0) { DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", @@ -126,19 +158,10 @@ static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde } /* called when a SMB connection goes down */ -static void terminate_connection(struct smbsrv_connection *server, const char *reason) +static void thread_terminate_connection(struct server_connection *conn, const char *reason) { - server_terminate(server); - - /* terminate this thread */ - pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */ -} - -/* called when a rpc connection goes down */ -static void terminate_rpc_connection(void *r, const char *reason) -{ - rpc_server_terminate(r); - + DEBUG(0,("thread_terminate_connection: reason[%s]\n",reason)); + conn->service->ops->close_connection(conn,reason); /* terminate this thread */ pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */ } @@ -431,7 +454,7 @@ static void thread_fault_handler(int sig) /* called when the process model is selected */ -static void model_startup(void) +static void thread_model_startup(void) { struct mutex_ops m_ops; struct debug_ops d_ops; @@ -465,7 +488,7 @@ static void model_startup(void) register_debug_handlers("thread", &d_ops); } -static void thread_exit_server(struct smbsrv_connection *smb, const char *reason) +static void thread_exit_server(struct server_context *srv_ctx, const char *reason) { DEBUG(1,("thread_exit_server: reason[%s]\n",reason)); } @@ -484,13 +507,11 @@ NTSTATUS process_model_thread_init(void) ops.name = "thread"; /* fill in all the operations */ - ops.model_startup = model_startup; - ops.accept_connection = accept_connection; - ops.accept_rpc_connection = accept_rpc_connection; - ops.terminate_connection = terminate_connection; - ops.terminate_rpc_connection = terminate_rpc_connection; + ops.model_startup = thread_model_startup; + ops.accept_connection = thread_accept_connection; + ops.terminate_connection = thread_terminate_connection; ops.exit_server = thread_exit_server; - ops.get_id = get_id; + ops.get_id = thread_get_id; /* register ourselves with the PROCESS_MODEL subsystem. */ ret = register_backend("process_model", &ops); diff --git a/source4/smbd/rewrite.c b/source4/smbd/rewrite.c index 5bc826bf71..d0a4bad374 100644 --- a/source4/smbd/rewrite.c +++ b/source4/smbd/rewrite.c @@ -79,6 +79,10 @@ void init_subsystems(void) if (!process_model_init()) exit(1); + /* Setup the SERVER_SERVICE subsystem */ + if (!server_service_init()) + exit(1); + /* Setup the AUTH subsystem */ if (!auth_init()) exit(1); @@ -88,7 +92,7 @@ void init_subsystems(void) exit(1); /* Setup the DCERPC subsystem */ - if (!dcesrv_init()) + if (!subsystem_dcerpc_init()) exit(1); } diff --git a/source4/smbd/server.c b/source4/smbd/server.c index 3a579b846a..e748795177 100644 --- a/source4/smbd/server.c +++ b/source4/smbd/server.c @@ -23,10 +23,16 @@ #include "includes.h" +static void exit_server(const char *reason) +{ + DEBUG(3,("Server exit (%s)\n", (reason ? reason : ""))); + exit(0); +} + /**************************************************************************** - main program. + main server. ****************************************************************************/ - int main(int argc,const char *argv[]) +static int binary_smbd_main(int argc,const char *argv[]) { BOOL is_daemon = False; BOOL interactive = False; @@ -34,7 +40,7 @@ BOOL log_stdout = False; int opt; poptContext pc; - struct event_context *events; + struct server_context *srv_ctx; const char *model = "standard"; struct poptOption long_options[] = { POPT_AUTOHELP @@ -42,7 +48,6 @@ {"interactive", 'i', POPT_ARG_VAL, &interactive, True, "Run interactive (not a daemon)"}, {"foreground", 'F', POPT_ARG_VAL, &Fork, False, "Run daemon in foreground (for daemontools & etc)" }, {"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout" }, - {"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" }, {"port", 'p', POPT_ARG_STRING, NULL, 0, "Listen on the specified ports"}, {"model", 'M', POPT_ARG_STRING, &model, 0, "select process model"}, POPT_COMMON_SAMBA @@ -53,11 +58,6 @@ while((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { - case 'b': - /* Display output to screen as well as debug */ - build_options(True); - exit(0); - break; case 'p': lp_set_cmdline("smb ports", poptGetOptArg(pc)); break; @@ -65,8 +65,6 @@ } poptFreeContext(pc); - events = event_context_init(); - load_case_tables(); if (interactive) { @@ -110,15 +108,11 @@ DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION_STRING)); DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2004\n")); - /* Output the build options to the debug log */ - build_options(False); - - if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4) { + if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) { DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); exit(1); } - DEBUG(0,("Using %s process model\n", model)); - + if (!reload_services(NULL, False)) return(-1); @@ -149,8 +143,18 @@ init_subsystems(); - process_model_startup(events, model); + DEBUG(0,("Using %s process model\n", model)); + srv_ctx = server_service_startup(model); + if (!srv_ctx) { + DEBUG(0,("Starting Services failed.\n")); + return 1; + } /* wait for events */ - return event_loop_wait(events); + return event_loop_wait(srv_ctx->events); +} + + int main(int argc, const char *argv[]) +{ + return binary_smbd_main(argc, argv); } diff --git a/source4/smbd/server.h b/source4/smbd/server.h new file mode 100644 index 0000000000..c47cf02d8a --- /dev/null +++ b/source4/smbd/server.h @@ -0,0 +1,40 @@ +/* + Unix SMB/CIFS implementation. + + 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. +*/ + +#ifndef _SERVER_H +#define _SERVER_H + +struct server_service; +struct event_context; + +struct server_context { + TALLOC_CTX *mem_ctx; + struct server_service *service_list; + struct event_context *events; +}; + +/* size of listen() backlog in smbd */ +#define SERVER_LISTEN_BACKLOG 10 + +/* the range of ports to try for dcerpc over tcp endpoints */ +#define SERVER_TCP_LOW_PORT 1024 +#define SERVER_TCP_HIGH_PORT 1300 + +#endif /* _SERVER_H */ 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; +} diff --git a/source4/smbd/service.h b/source4/smbd/service.h new file mode 100644 index 0000000000..41ad381f9e --- /dev/null +++ b/source4/smbd/service.h @@ -0,0 +1,127 @@ +/* + Unix SMB/CIFS implementation. + + SERVER SERVICE code + + 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. +*/ + +#ifndef _SERVER_SERVICE_H +#define _SERVER_SERVICE_H + +struct event_context; +struct model_ops; +struct server_context; + +struct server_connection; +struct server_service; + +/* modules can use the following to determine if the interface has changed + * please increment the version number after each interface change + * with a comment and maybe update struct process_model_critical_sizes. + */ +/* version 1 - initial version - metze */ +#define SERVER_SERVICE_VERSION 1 + +struct server_service_ops { + /* the name of the server_service */ + const char *name; + + /* called at startup when the server_service is selected */ + void (*service_init)(struct server_service *service, const struct model_ops *ops); + + /* function to accept new connection */ + void (*accept_connection)(struct server_connection *); + + /* function to accept new connection */ + void (*recv_handler)(struct server_connection *, time_t, uint16_t); + + /* function to accept new connection */ + void (*send_handler)(struct server_connection *, time_t, uint16_t); + + /* function to accept new connection */ + void (*idle_handler)(struct server_connection *, time_t); + + /* function to close a connection */ + void (*close_connection)(struct server_connection *, const char *reason); + + /* function to exit server */ + void (*service_exit)(struct server_service *srv_ctx, const char *reason); +}; + +struct socket_ops { + int dummy; +}; + +struct socket_context { + void *private_data; + struct socket_ops *ops; + const char *client_addr; + uint_t pkt_count; + struct fd_event *fde; +}; + +struct server_socket { + struct server_socket *next,*prev; + TALLOC_CTX *mem_ctx; + void *private_data; + + struct { + struct event_context *ctx; + struct fd_event *fde; + } event; + + struct socket_context *socket; + + struct server_service *service; + + struct server_connection *connection_list; +}; + +struct server_service { + struct server_service *next,*prev; + TALLOC_CTX *mem_ctx; + void *private_data; + const struct server_service_ops *ops; + + const struct model_ops *model_ops; + + struct server_socket *socket_list; + + struct server_context *srv_ctx; +}; + +struct server_connection { + struct server_connection *next,*prev; + TALLOC_CTX *mem_ctx; + void *private_data; + + struct { + struct event_context *ctx; + struct fd_event *fde; + struct timed_event *idle; + time_t idle_time; + } event; + + struct socket_context *socket; + + struct server_socket *server_socket; + + struct server_service *service; +}; + +#endif /* _SERVER_SERVICE_H */ -- cgit