r1486: commit the start of the generic server infastructure
authorStefan Metzmacher <metze@samba.org>
Tue, 13 Jul 2004 21:04:56 +0000 (21:04 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:57:35 +0000 (12:57 -0500)
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)

27 files changed:
source4/auth/auth.c
source4/include/includes.h
source4/include/local.h
source4/ntvfs/cifs/vfs_cifs.c
source4/param/loadparm.c
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h
source4/rpc_server/dcerpc_tcp.c
source4/smb_server/connection.c
source4/smb_server/negprot.c
source4/smb_server/reply.c
source4/smb_server/request.c
source4/smb_server/service.c
source4/smb_server/smb_server.c
source4/smb_server/smb_server.h
source4/smbd/config.m4
source4/smbd/config.mk
source4/smbd/process_model.c
source4/smbd/process_model.h
source4/smbd/process_single.c
source4/smbd/process_standard.c
source4/smbd/process_thread.c
source4/smbd/rewrite.c
source4/smbd/server.c
source4/smbd/server.h [new file with mode: 0644]
source4/smbd/service.c [new file with mode: 0644]
source4/smbd/service.h [new file with mode: 0644]

index 703df21d45324981cbc4250be1097a973d9929d5..32913f99960d6652421bf76c09851027a3949959 100644 (file)
@@ -501,3 +501,8 @@ BOOL auth_init(void)
        DEBUG(3,("AUTH subsystem version %d initialised\n", AUTH_INTERFACE_VERSION));
        return True;
 }
+
+NTSTATUS server_service_auth_init(void)
+{
+       return NT_STATUS_OK;    
+}
index 058d54773616da831afbe49754e8d96a084681c4..9ce2b719820fafa068c75a224cd2d49564eca434 100644 (file)
@@ -668,6 +668,8 @@ extern int errno;
 
 #include "librpc/rpc/dcerpc.h"
 
+#include "smbd/server.h"
+#include "smbd/service.h"
 #include "rpc_server/dcerpc_server.h"
 #include "smb_server/smb_server.h"
 #include "ntvfs/ntvfs.h"
index 3f0f8618aaa1e344dce914b2f500992db6263a0e..67b83c316d82ffb5762e21389f754394295d35ad 100644 (file)
 /* Max number of simultaneous winbindd socket connections. */
 #define WINBINDD_MAX_SIMULTANEOUS_CLIENTS 200
 
-/* size of listen() backlog in smbd */
-#define SMBD_LISTEN_BACKLOG 10
-
-/* the range of ports to try for dcerpc over tcp endpoints */
-#define DCERPC_TCP_LOW_PORT  1024
-#define DCERPC_TCP_HIGH_PORT 1300
-
 #endif
index 93b9f2630e9f79208bcd9c15a2d36113d7aec039..b6d3486ad8c18c8c44197710d2bc2880298f98e5 100644 (file)
@@ -51,7 +51,7 @@ struct async_info {
 static void idle_func(struct cli_transport *transport, void *p_private)
 {
        struct cvfs_private *private = p_private;
-       if (socket_pending(private->tcon->smb_conn->socket.fd)) {
+       if (socket_pending(private->tcon->smb_conn->connection->socket->fde->fd)) {
                smbd_process_async(private->tcon->smb_conn);
        }
 }
@@ -164,7 +164,7 @@ static NTSTATUS cvfs_connect(struct smbsrv_request *req, const char *sharename)
        fde.private = private;
        fde.handler = cifs_socket_handler;
 
-       event_add_fd(tcon->smb_conn->events, &fde);
+       event_add_fd(tcon->smb_conn->connection->event.ctx, &fde);
 
        /* we need to receive oplock break requests from the server */
        cli_oplock_handler(private->transport, oplock_handler, private);
@@ -180,7 +180,7 @@ static NTSTATUS cvfs_disconnect(struct smbsrv_tcon *tcon)
 {
        struct cvfs_private *private = tcon->ntvfs_private;
 
-       event_remove_fd_all(tcon->smb_conn->events, private->transport->socket->fd);
+       event_remove_fd_all(tcon->smb_conn->connection->event.ctx, private->transport->socket->fd);
        smb_tree_disconnect(private->tree);
        cli_tree_close(private->tree);
 
index 5493b2617cad061047fee7fcde6d0a9f8b9d6ef6..293df3bb1f018616061e9ac14d6ea888988a0375 100644 (file)
@@ -137,6 +137,7 @@ typedef struct
        char *szWINSHook;
        char *szWINSPartners;
        char **dcerpc_ep_servers;
+       char **server_services;
        char *szWinbindUID;
        char *szWinbindGID;
        char *szNonUnixAccountRange;
@@ -568,6 +569,7 @@ static struct parm_struct parm_table[] = {
        {"bind interfaces only", P_BOOL, P_GLOBAL, &Globals.bBindInterfacesOnly, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER},
        {"ntvfs handler", P_STRING, P_LOCAL, &sDefault.ntvfs_handler, NULL, NULL, FLAG_ADVANCED},
        {"dcerpc endpoint servers", P_LIST, P_GLOBAL, &Globals.dcerpc_ep_servers, NULL, NULL, FLAG_ADVANCED},
+       {"server services", P_LIST, P_GLOBAL, &Globals.server_services, NULL, NULL, FLAG_ADVANCED},
 
        {"Security Options", P_SEP, P_SEPARATOR},
        
@@ -959,6 +961,8 @@ static void init_globals(void)
 
        Globals.dcerpc_ep_servers = str_list_make("epmapper srvsvc wkssvc rpcecho samr netlogon lsarpc spoolss", NULL);
 
+       Globals.server_services = str_list_make("smb rpc", NULL);
+
        Globals.AuthMethods = str_list_make("guest sam_ignoredomain", NULL);
 
        string_set(&Globals.szSMBPasswdFile, dyn_SMB_PASSWD_FILE);
@@ -1218,6 +1222,7 @@ FN_GLOBAL_STRING(lp_printcapname, &Globals.szPrintcapname)
 FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir)
 FN_GLOBAL_STRING(lp_piddir, &Globals.szPidDir)
 FN_GLOBAL_LIST(lp_dcerpc_endpoint_servers, &Globals.dcerpc_ep_servers)
+FN_GLOBAL_LIST(lp_server_services, &Globals.server_services)
 FN_GLOBAL_STRING(lp_rootdir, &Globals.szRootdir)
 FN_GLOBAL_STRING(lp_defaultservice, &Globals.szDefaultService)
 FN_GLOBAL_STRING(lp_hosts_equiv, &Globals.szHostsEquiv)
index e5c4c120a5359a41189e1f3931827ac1ffeb53d0..34756349c6e379025b339ae5c37f9c71b68294a1 100644 (file)
@@ -271,6 +271,7 @@ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
        (*p)->auth_state.auth_info = NULL;
        (*p)->auth_state.gensec_security = NULL;
        (*p)->auth_state.session_info = NULL;
+       (*p)->srv_conn = NULL;
 
        return NT_STATUS_OK;
 }
@@ -1016,6 +1017,87 @@ NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
        return NT_STATUS_OK;
 }
 
+static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
+{
+       TALLOC_CTX *mem_ctx;
+       struct dcesrv_context *dce_ctx;
+       int i;
+       const char **endpoint_servers = lp_dcerpc_endpoint_servers();
+
+       DEBUG(0,("dcesrv_init\n"));
+
+
+       if (!endpoint_servers) {
+               DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
+               return;
+       }
+
+       mem_ctx = talloc_init("struct dcesrv_context");
+
+       dce_ctx = talloc_p(mem_ctx, struct dcesrv_context);
+       if (!dce_ctx) {
+               DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
+               return;
+       }
+
+       ZERO_STRUCTP(dce_ctx);
+       dce_ctx->mem_ctx        = mem_ctx;
+       dce_ctx->endpoint_list  = NULL;
+
+       for (i=0;endpoint_servers[i];i++) {
+               NTSTATUS ret;
+               const struct dcesrv_endpoint_server *ep_server;
+               
+               ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
+               if (!ep_server) {
+                       DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
+                       return;
+               }
+
+               ret = ep_server->init_server(dce_ctx, ep_server);
+               if (!NT_STATUS_IS_OK(ret)) {
+                       DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
+                       return;
+               }
+       }
+
+       dcesrv_tcp_init(service, model_ops, dce_ctx);
+
+       return; 
+}
+
+static void dcesrv_accept(struct server_connection *srv_conn)
+{
+       dcesrv_tcp_accept(srv_conn);
+}
+
+static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
+{
+       dcesrv_tcp_recv(srv_conn, t, flags);
+}
+
+static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
+{
+       dcesrv_tcp_send(srv_conn, t, flags);
+}
+
+static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
+{
+       dcesrv_tcp_idle(srv_conn, t);
+}
+
+static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
+{
+       dcesrv_tcp_close(srv_conn, reason);
+       return; 
+}
+
+static void dcesrv_exit(struct server_service *service, const char *reason)
+{
+       dcesrv_tcp_exit(service, reason);
+       return; 
+}
+
 /* the list of currently registered DCERPC endpoint servers.
  */
 static struct {
@@ -1101,7 +1183,7 @@ const struct dcesrv_critical_sizes *dcerpc_module_version(void)
 /*
   initialise the DCERPC subsystem
 */
-BOOL dcesrv_init(void)
+BOOL subsystem_dcerpc_init(void)
 {
        NTSTATUS status;
 
@@ -1116,3 +1198,24 @@ BOOL dcesrv_init(void)
        DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
        return True;
 }
+
+static const struct server_service_ops dcesrv_ops = {
+       .name                   = "rpc",
+       .service_init           = dcesrv_init,
+       .accept_connection      = dcesrv_accept,
+       .recv_handler           = dcesrv_recv,
+       .send_handler           = dcesrv_send,
+       .idle_handler           = dcesrv_idle,
+       .close_connection       = dcesrv_close,
+       .service_exit           = dcesrv_exit,  
+};
+
+const struct server_service_ops *dcesrv_get_ops(void)
+{
+       return &dcesrv_ops;
+}
+
+NTSTATUS server_service_rpc_init(void)
+{
+       return NT_STATUS_OK;    
+}
index b1754dd4a3d893adfdc19f518802603f4d1426b2..15da3e38bbef085faa53eb494275334f835c1629 100644 (file)
@@ -39,7 +39,7 @@ struct dcesrv_ep_description {
        enum endpoint_type type;
        union {
                const char *smb_pipe;
-               uint32_t tcp_port;
+               uint16_t tcp_port;
        } info;
 };
 
@@ -132,6 +132,8 @@ struct dcesrv_connection {
 
        /* the current authentication state */
        struct dcesrv_auth auth_state;
+
+       struct server_connection *srv_conn;
 };
 
 
index 83a9140dd162401b2f9ed07e38227f10f11162d2..c506cf16cf0144c1eb68d5ee0c2e5872794506d3 100644 (file)
 
 #include "includes.h"
 
-struct rpc_server_context {
-       struct dcesrv_ep_description *ep_description;
+struct dcesrv_socket_context {
        const struct dcesrv_endpoint *endpoint;
-       const struct model_ops *model_ops;
-       struct dcesrv_connection *dce_conn;
-       struct dcesrv_context dcesrv_context;
-       int socket_fd;
-       struct event_context *events;   
+       struct dcesrv_context *dcesrv_ctx;      
 };
 
-/*
-  a callback from the process model termination routine 
-*/
-void rpc_server_terminate(void *rr)
-{
-       struct rpc_server_context *r = rr;
-
-       dcesrv_endpoint_disconnect(r->dce_conn);
-       close(r->socket_fd);
-       event_remove_fd_all(r->events, r->socket_fd);
-       free(r);
-}
-
-/*
-  called when a rpc session needs to be shutdown
-*/
-static void terminate_rpc_session(struct rpc_server_context *r, const char *reason)
-{
-       r->model_ops->terminate_rpc_connection(r, reason);
-}
-
-
 /*
   write_fn callback for dcesrv_output()
 */
@@ -69,45 +42,128 @@ static ssize_t dcerpc_write_fn(void *private, const void *buf, size_t count)
        return ret;
 }
 
+void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
+{
+       server_terminate_connection(dce_conn->srv_conn, reason);
+}
+
 /*
-  called when a RPC socket becomes writable
+  add a socket address to the list of events, one event per dcerpc endpoint
 */
-static void dcerpc_write_handler(struct event_context *ev, struct fd_event *fde, 
-                                time_t t, uint16_t flags)
+static void add_socket_rpc(struct server_service *service, 
+                      const struct model_ops *model_ops,
+                      struct socket_context *socket_ctx,
+                      struct dcesrv_context *dce_ctx, 
+                      struct in_addr *ifip)
 {
-       struct rpc_server_context *r = fde->private;
-       NTSTATUS status;
+       struct dcesrv_endpoint *e;
 
-       status = dcesrv_output(r->dce_conn, fde, dcerpc_write_fn);
-       if (NT_STATUS_IS_ERR(status)) {
-               /* TODO: destroy fd_event? */
+       for (e=dce_ctx->endpoint_list;e;e=e->next) {
+               if (e->ep_description.type == ENDPOINT_TCP) {
+                       struct server_socket *sock;
+                       struct dcesrv_socket_context *dcesrv_sock;
+
+                       sock = service_setup_socket(service,model_ops,socket_ctx,ifip, &e->ep_description.info.tcp_port);
+                       if (!sock) {
+                               DEBUG(0,("service_setup_socket(port=%u) failed\n",e->ep_description.info.tcp_port));
+                               continue;
+                       }
+
+                       dcesrv_sock = talloc_p(sock->mem_ctx, struct dcesrv_socket_context);
+                       if (!dcesrv_sock) {
+                               DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
+                               continue;
+                       }
+
+                       /* remeber the enpoint of this socket */
+                       dcesrv_sock->endpoint           = e;
+                       dcesrv_sock->dcesrv_ctx         = dce_ctx;
+                       
+                       sock->private_data = dcesrv_sock;
+               }
        }
+}
 
-       if (!r->dce_conn->call_list || !r->dce_conn->call_list->replies) {
-               fde->flags &= ~EVENT_FD_WRITE;
+/****************************************************************************
+ Open the listening sockets for RPC over TCP
+****************************************************************************/
+void dcesrv_tcp_init(struct server_service *service, const struct model_ops *model_ops, struct dcesrv_context *dce_ctx)
+{
+       DEBUG(1,("dcesrv_tcp_init\n"));
+
+       if (lp_interfaces() && lp_bind_interfaces_only()) {
+               int num_interfaces = iface_count();
+               int i;
+               for(i = 0; i < num_interfaces; i++) {
+                       struct in_addr *ifip = iface_n_ip(i);
+                       if (ifip == NULL) {
+                               continue;
+                       }
+                       add_socket_rpc(service, model_ops, NULL, dce_ctx,  ifip);
+               }
+       } else {
+               struct in_addr *ifip;
+               TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd");
+               if (!mem_ctx) {
+                       smb_panic("No memory");
+               }
+
+               ifip = interpret_addr2(mem_ctx, lp_socket_address());
+               add_socket_rpc(service, model_ops, NULL, dce_ctx,  ifip);
+               talloc_destroy(mem_ctx);
        }
+
+       return; 
 }
 
-/*
-  called when a RPC socket becomes readable
-*/
-static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde, 
-                               time_t t, uint16_t flags)
+void dcesrv_tcp_accept(struct server_connection *conn)
+{
+       NTSTATUS status;
+       struct dcesrv_socket_context *dcesrv_sock = conn->server_socket->private_data;
+       struct dcesrv_connection *dcesrv_conn = NULL;
+
+       DEBUG(5,("dcesrv_tcp_accept\n"));
+
+
+
+       status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, dcesrv_sock->endpoint, &dcesrv_conn);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("dcesrv_tcp_accept: dcesrv_endpoint_connect failed: %s\n", 
+                       nt_errstr(status)));
+               return;
+       }
+
+       dcesrv_conn->srv_conn = conn;
+
+       conn->private_data = dcesrv_conn;
+
+       /* TODO: this should to the generic code
+        *       but the smb server can't handle it yet
+        *       --metze
+        */ 
+       set_blocking(conn->socket->fde->fd, False);
+
+       return; 
+}
+
+void dcesrv_tcp_recv(struct server_connection *conn, time_t t, uint16_t flags)
 {
-       struct rpc_server_context *r = fde->private;
+       struct dcesrv_connection *dce_conn = conn->private_data;
        DATA_BLOB blob;
        ssize_t ret;
 
+       DEBUG(10,("dcesrv_tcp_recv\n"));
+
        blob = data_blob(NULL, 0x4000);
        if (!blob.data) {
-               terminate_rpc_session(r, "out of memory");
+               dcesrv_terminate_connection(dce_conn, "eof on socket");
                return;
        }
 
-       ret = read(fde->fd, blob.data, blob.length);
+       ret = read(conn->socket->fde->fd, blob.data, blob.length);
        if (ret == 0 || (ret == -1 && errno != EINTR)) {
                data_blob_free(&blob);
-               terminate_rpc_session(r, "eof on socket");
+               dcesrv_terminate_connection(dce_conn, "eof on socket");
                return;
        }
        if (ret == -1) {
@@ -117,197 +173,61 @@ static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde,
 
        blob.length = ret;
 
-       dcesrv_input(r->dce_conn, &blob);
+       dcesrv_input(dce_conn, &blob);
 
        data_blob_free(&blob);
 
-       if (r->dce_conn->call_list && r->dce_conn->call_list->replies) {
-               fde->flags |= EVENT_FD_WRITE;
+       if (dce_conn->call_list && dce_conn->call_list->replies) {
+               conn->socket->fde->flags |= EVENT_FD_WRITE;
        }
-}
-
 
-
-
-/*
-  called when a RPC socket becomes readable
-*/
-static void dcerpc_io_handler(struct event_context *ev, struct fd_event *fde, 
-                             time_t t, uint16_t flags)
-{
-       if (flags & EVENT_FD_WRITE) {
-               dcerpc_write_handler(ev, fde, t, flags);
-       }
-
-       if (flags & EVENT_FD_READ) {
-               dcerpc_read_handler(ev, fde, t, flags);
-       }
+       return; 
 }
-       
-/*
-  initialise a server_context from a open socket and register a event handler
-  for reading from that socket
-*/
-void init_rpc_session(struct event_context *ev, void *private, int fd)
+
+void dcesrv_tcp_send(struct server_connection *conn, time_t t, uint16_t flags)
 {
-       struct fd_event fde;
-       struct rpc_server_context *r = private;
+       struct dcesrv_connection *dce_conn = conn->private_data;
        NTSTATUS status;
 
-       r = memdup(r, sizeof(struct rpc_server_context));
-
-       r->events = ev;
-       r->socket_fd = fd;
+       DEBUG(10,("dcesrv_tcp_send\n"));
 
-       set_socket_options(fd,"SO_KEEPALIVE");
-       set_socket_options(fd, lp_socket_options());
-
-       status = dcesrv_endpoint_connect(&r->dcesrv_context, r->endpoint, &r->dce_conn);
-       if (!NT_STATUS_IS_OK(status)) {
-               close(fd);
-               free(r);
-               DEBUG(0,("init_rpc_session: connection to endpoint failed: %s\n", 
-                       nt_errstr(status)));
-               return;
+       status = dcesrv_output(dce_conn, conn->socket->fde, dcerpc_write_fn);
+       if (NT_STATUS_IS_ERR(status)) {
+               /* TODO: destroy fd_event? */
        }
 
-       r->dce_conn->dce_ctx = &r->dcesrv_context;
-
-       set_blocking(fd, False);
-
-       /* setup a event handler for this socket. We are initially
-          only interested in reading from the socket */
-       fde.fd = fd;
-       fde.handler = dcerpc_io_handler;
-       fde.private = r;
-       fde.flags = EVENT_FD_READ;
+       if (!dce_conn->call_list || !dce_conn->call_list->replies) {
+               conn->socket->fde->flags &= ~EVENT_FD_WRITE;
+       }
 
-       event_add_fd(ev, &fde);
+       return; 
 }
 
-
-/*
-  setup a single rpc listener
- */
-static void setup_listen_rpc(struct event_context *events,
-                            const struct model_ops *model_ops, 
-                            struct in_addr *ifip, uint32_t *port,
-                            struct rpc_server_context *r,
-                            const struct dcesrv_endpoint *endpoint)
+void dcesrv_tcp_idle(struct server_connection *conn, time_t t)
 {
-       struct fd_event fde;
-       int i;
-
-       if (*port == 0) {
-               fde.fd = -1;
-               for (i=DCERPC_TCP_LOW_PORT;i<= DCERPC_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);
-       }
+       DEBUG(10,("dcesrv_tcp_idle\n"));
+       conn->event.idle->next_event = t + 5;
 
-       if (fde.fd == -1) {
-               DEBUG(0,("Failed to open socket on %s:%u - %s\n",
-                        inet_ntoa(*ifip), *port, strerror(errno)));
-               return;
-       }
-
-       /* each listening socket has separate state, so must use a different context */
-       r = memdup(r, sizeof(struct rpc_server_context));
-       if (!r) {
-               smb_panic("out of memory");
-       }
-
-       r->ep_description = malloc(sizeof(struct dcesrv_ep_description));
-       if (!r->ep_description) {
-               smb_panic("out of memory");
-       }
-       r->ep_description->type = ENDPOINT_TCP;
-       r->ep_description->info.tcp_port = *port;
-
-       r->endpoint = endpoint;
-
-       /* ready to listen */
-       set_socket_options(fde.fd, "SO_KEEPALIVE"); 
-       set_socket_options(fde.fd, lp_socket_options());
-      
-       if (listen(fde.fd, SMBD_LISTEN_BACKLOG) == -1) {
-               DEBUG(0,("Failed to listen on %s:%d - %s\n",
-                        inet_ntoa(*ifip), *port, strerror(errno)));
-               close(fde.fd);
-               return;
-       }
-
-       /* we are only interested in read events on the listen socket */
-       fde.flags = EVENT_FD_READ;
-       fde.private = r;
-       fde.handler = model_ops->accept_rpc_connection;
-       
-       event_add_fd(events, &fde);
+       return; 
 }
 
-/*
-  add a socket address to the list of events, one event per dcerpc endpoint
-*/
-static void add_socket_rpc(struct event_context *events, 
-                          const struct model_ops *model_ops, 
-                          struct in_addr *ifip)
+void dcesrv_tcp_close(struct server_connection *conn, const char *reason)
 {
-       struct dcesrv_endpoint *e;
-       struct rpc_server_context *r;
+       struct dcesrv_connection *dce_conn = conn->private_data;
 
-       r = malloc(sizeof(struct rpc_server_context));
-       if (!r) {
-               smb_panic("out of memory");
-       }
+       DEBUG(5,("dcesrv_tcp_close: %s\n",reason));
 
-       r->dcesrv_context.endpoint_list = NULL;
-       dcesrv_init_context(&r->dcesrv_context);
-       r->ep_description = NULL;
-       r->model_ops = model_ops;
-       r->dce_conn = NULL;
-       r->socket_fd = -1;
-       r->events = NULL;
-       
-       for (e=r->dcesrv_context.endpoint_list;e;e=e->next) {
-               if (e->ep_description.type == ENDPOINT_TCP) {
-                       setup_listen_rpc(events, model_ops, ifip, 
-                                        &e->ep_description.info.tcp_port, 
-                                        r, e);
-               }
-       }
+       close(conn->event.fde->fd);
+       event_remove_fd_all(conn->event.ctx, conn->socket->fde->fd);
+       event_remove_timed(conn->event.ctx, conn->event.idle);
 
-       free(r);
+       talloc_destroy(dce_conn->mem_ctx);
+
+       return;
 }
 
-/****************************************************************************
- Open the listening sockets for RPC over TCP
-****************************************************************************/
-void open_sockets_rpc(struct event_context *events,
-                     const struct model_ops *model_ops)
+void dcesrv_tcp_exit(struct server_service *service, const char *reason)
 {
-       if (lp_interfaces() && lp_bind_interfaces_only()) {
-               int num_interfaces = iface_count();
-               int i;
-               for(i = 0; i < num_interfaces; i++) {
-                       struct in_addr *ifip = iface_n_ip(i);
-                       if (ifip == NULL) {
-                               continue;
-                       }
-                       add_socket_rpc(events, model_ops, ifip);
-               }
-       } else {
-               TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd");         
-               struct in_addr *ifip = interpret_addr2(mem_ctx, lp_socket_address());
-               if (!mem_ctx) {
-                       smb_panic("No memory");
-               }
-               add_socket_rpc(events, model_ops, ifip);
-               talloc_destroy(mem_ctx);
-       } 
+       DEBUG(1,("dcesrv_tcp_exit: %s\n",reason));
+       return;
 }
index 77f2395d9e08ee72fe4e18591fe967e0544c6e87..4cb4f2168ad5b5ed55a0344af66e76d50f9550db 100644 (file)
@@ -166,7 +166,7 @@ BOOL claim_connection(struct smbsrv_tcon *tcon, const char *name,int max_connect
        crec.bcast_msg_flags = msg_flags;
        
        StrnCpy(crec.machine,sub_get_remote_machine(),sizeof(crec.machine)-1);
-       StrnCpy(crec.addr,tcon?tcon->smb_conn->socket.client_addr:"NONE",sizeof(crec.addr)-1);
+       StrnCpy(crec.addr,tcon?tcon->smb_conn->connection->socket->client_addr:"NONE",sizeof(crec.addr)-1);
 
        dbuf.dptr = (char *)&crec;
        dbuf.dsize = sizeof(crec);
index f239e6ae81c3117d9e2d771dbaa9873da1d368b9..c9c775e62f6c964819c5d99ec06d55c5ee683315 100644 (file)
@@ -342,7 +342,7 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice)
                memcpy(req->out.ptr, blob.data, blob.length);
                DEBUG(3,("using SPNEGO\n"));
 #else
-               exit_server(req->smb_conn, "no SPNEGO please");
+               smbsrv_terminate_connection(req->smb_conn, "no SPNEGO please");
 #endif
        }
        
@@ -450,7 +450,7 @@ void reply_negprot(struct smbsrv_request *req)
        int arch = ARCH_ALL;
 
        if (req->smb_conn->negotiate.done_negprot) {
-               exit_server(req->smb_conn, "multiple negprot's are not permitted");
+               smbsrv_terminate_connection(req->smb_conn, "multiple negprot's are not permitted");
        }
        req->smb_conn->negotiate.done_negprot = True;
 
index 1c3ffd58bd4a2b6d66d7facd6674542df29a1a15..bc79892204ca09f47aec1a783155be9c317cb794 100644 (file)
@@ -2300,7 +2300,7 @@ void reply_special(struct smbsrv_request *req)
        switch (msg_type) {
        case 0x81: /* session request */
                if (req->smb_conn->negotiate.done_nbt_session) {
-                       exit_server(req->smb_conn, "multiple session request not permitted");
+                       smbsrv_terminate_connection(req->smb_conn, "multiple session request not permitted");
                }
                
                SCVAL(buf,0,0x82);
index 3bfe6a4e7341a3d2133894559e98cf7c3fa1e6b5..f4cdba79ccc7e14adc5519a6c27e5b20ca74bc90 100644 (file)
@@ -54,12 +54,12 @@ struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
           structure itself is also allocated inside this context, so
           we need to allocate it before we construct the request
        */
-       mem_ctx = talloc_init("request_context[%d]", smb_conn->socket.pkt_count);
+       mem_ctx = talloc_init("request_context[%d]", smb_conn->connection->socket->pkt_count);
        if (!mem_ctx) {
                return NULL;
        }
 
-       smb_conn->socket.pkt_count++;
+       smb_conn->connection->socket->pkt_count++;
 
        req = talloc(mem_ctx, sizeof(*req));
        if (!req) {
@@ -91,7 +91,7 @@ static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t
 
        req->out.buffer = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated);
        if (!req->out.buffer) {
-               exit_server(req->smb_conn, "allocation failed");
+               smbsrv_terminate_connection(req->smb_conn, "allocation failed");
        }
 
        req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
@@ -125,7 +125,7 @@ void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
 
        req->out.buffer = talloc(req->mem_ctx, req->out.allocated);
        if (!req->out.buffer) {
-               exit_server(req->smb_conn, "allocation failed");
+               smbsrv_terminate_connection(req->smb_conn, "allocation failed");
        }
 
        req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
@@ -262,7 +262,7 @@ void req_send_reply_nosign(struct smbsrv_request *req)
                _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
        }
 
-       if (write_data(req->smb_conn->socket.fd, req->out.buffer, req->out.size) != req->out.size) {
+       if (write_data(req->smb_conn->connection->socket->fde->fd, req->out.buffer, req->out.size) != req->out.size) {
                smb_panic("failed to send reply\n");
        }
 
index 44aae340b2e63ef3563aa29b1871e504046ec013..0a06e2edfa6bf0d64c52da1ec65c874d013ebfea 100644 (file)
@@ -259,7 +259,7 @@ close a cnum
 void close_cnum(struct smbsrv_tcon *tcon)
 {
        DEBUG(3,("%s closed connection to service %s\n",
-                tcon->smb_conn->socket.client_addr, lp_servicename(SNUM(tcon))));
+                tcon->smb_conn->connection->socket->client_addr, lp_servicename(SNUM(tcon))));
 
        yield_connection(tcon, lp_servicename(SNUM(tcon)));
 
index 16d1d774c0fe1042d96261d999b1821309a4a336..351d9ddf4ef5e784d12d356fb667c1ae29cedad2 100644 (file)
@@ -63,7 +63,7 @@ static struct smbsrv_request *receive_smb_request(struct smbsrv_connection *smb_
        char header[4];
        struct smbsrv_request *req;
 
-       len = read_data(smb_conn->socket.fd, header, 4);
+       len = read_data(smb_conn->connection->socket->fde->fd, header, 4);
        if (len != 4) {
                return NULL;
        }
@@ -81,7 +81,7 @@ static struct smbsrv_request *receive_smb_request(struct smbsrv_connection *smb_
        /* fill in the already received header */
        memcpy(req->in.buffer, header, 4);
 
-       len2 = read_data(smb_conn->socket.fd, req->in.buffer + NBT_HDR_SIZE, len);
+       len2 = read_data(smb_conn->connection->socket->fde->fd, req->in.buffer + NBT_HDR_SIZE, len);
        if (len2 != len) {
                return NULL;
        }
@@ -467,7 +467,7 @@ static void switch_message(int type, struct smbsrv_request *req)
        if (req->user_ctx) {
                req->user_ctx->vuid = session_tag;
        }
-       DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->model_ops->get_id(req)));
+       DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->connection->service->model_ops->get_id(req)));
 
        /* does this protocol need to be run as root? */
        if (!(flags & AS_USER)) {
@@ -562,19 +562,19 @@ static void construct_reply(struct smbsrv_request *req)
        if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
                DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n", 
                         req->in.size));
-               exit_server(req->smb_conn, "Non-SMB packet");
+               smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
                return;
        }
 
        if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
                DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
-               exit_server(req->smb_conn, "Invalid SMB packet");
+               smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
                return;
        }
 
        if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
                DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
-               exit_server(req->smb_conn, "Invalid SMB packet");
+               smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
                return;
        }
 
@@ -667,64 +667,26 @@ error:
 /*
   close the socket and shutdown a server_context
 */
-void server_terminate(struct smbsrv_connection *smb_conn)
+void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
 {
-       close(smb_conn->socket.fd);
-       event_remove_fd_all(smb_conn->events, smb_conn->socket.fd);
-
-       conn_close_all(smb_conn);
-
-       talloc_destroy(smb_conn->mem_ctx);
+       server_terminate_connection(smb_conn->connection, reason);
 }
 
 /*
   called on a fatal error that should cause this server to terminate
 */
-void exit_server(struct smbsrv_connection *smb_conn, const char *reason)
-{
-       smb_conn->model_ops->terminate_connection(smb_conn, reason);
-}
-
-/*
-  setup a single listener of any type
- */
-static void setup_listen(struct event_context *events,
-                        const struct model_ops *model_ops, 
-                        void (*accept_handler)(struct event_context *,struct fd_event *,time_t,uint16_t),
-                        struct in_addr *ifip, uint_t port)
+static void smbsrv_exit(struct server_service *service, const char *reason)
 {
-       struct fd_event fde;
-       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;
-       }
-
-       /* ready to listen */
-       set_socket_options(fde.fd, "SO_KEEPALIVE"); 
-       set_socket_options(fde.fd, lp_socket_options());
-      
-       if (listen(fde.fd, SMBD_LISTEN_BACKLOG) == -1) {
-               DEBUG(0,("Failed to listen on %s:%d - %s\n",
-                        inet_ntoa(*ifip), port, strerror(errno)));
-               close(fde.fd);
-               return;
-       }
-
-       /* we are only interested in read events on the listen socket */
-       fde.flags = EVENT_FD_READ;
-       fde.private = model_ops;
-       fde.handler = accept_handler;
-       
-       event_add_fd(events, &fde);
+       DEBUG(1,("smbsrv_exit\n"));
+       return;
 }
 
 /*
   add a socket address to the list of events, one event per port
 */
-static void add_socket(struct event_context *events, 
-                      const struct model_ops *model_ops, 
+static void add_socket(struct server_service *service, 
+                      const struct model_ops *model_ops,
+                      struct socket_context *socket_ctx, 
                       struct in_addr *ifip)
 {
        char *ptr, *tok;
@@ -733,18 +695,19 @@ static void add_socket(struct event_context *events,
        for (tok=strtok_r(lp_smb_ports(), delim, &ptr); 
             tok; 
             tok=strtok_r(NULL, delim, &ptr)) {
-               uint_t port = atoi(tok);
+               uint16_t port = atoi(tok);
                if (port == 0) continue;
-               setup_listen(events, model_ops, model_ops->accept_connection, ifip, port);
+               service_setup_socket(service, model_ops, socket_ctx, ifip, &port);
        }
 }
 
 /****************************************************************************
  Open the socket communication.
 ****************************************************************************/
-void open_sockets_smbd(struct event_context *events,
-                             const struct model_ops *model_ops)
-{
+static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
+{      
+       DEBUG(1,("smbsrv_init\n"));
+
        if (lp_interfaces() && lp_bind_interfaces_only()) {
                int num_interfaces = iface_count();
                int i;
@@ -761,33 +724,37 @@ void open_sockets_smbd(struct event_context *events,
                                continue;
                        }
 
-                       add_socket(events, model_ops, ifip);
+                       add_socket(service, model_ops, NULL, ifip);
                }
        } else {
+               struct in_addr *ifip;
                TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd");
-               
-               struct in_addr *ifip = interpret_addr2(mem_ctx, lp_socket_address());
-               /* Just bind to lp_socket_address() (usually 0.0.0.0) */
+
                if (!mem_ctx) {
                        smb_panic("No memory");
-               }
-               add_socket(events, model_ops, ifip);
+               }       
+
+               /* Just bind to lp_socket_address() (usually 0.0.0.0) */
+               ifip = interpret_addr2(mem_ctx, lp_socket_address());
+               add_socket(service, model_ops, NULL, ifip);
+
                talloc_destroy(mem_ctx);
-       } 
+       }
 }
 
 /*
   called when a SMB socket becomes readable
 */
-void smbd_read_handler(struct event_context *ev, struct fd_event *fde, 
-                      time_t t, uint16_t flags)
+static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
 {
        struct smbsrv_request *req;
-       struct smbsrv_connection *smb_conn = fde->private;
-       
+       struct smbsrv_connection *smb_conn = conn->private_data;
+
+       DEBUG(10,("smbsrv_recv\n"));
+
        req = receive_smb_request(smb_conn);
        if (!req) {
-               smb_conn->model_ops->terminate_connection(smb_conn, "receive error");
+               smbsrv_terminate_connection(smb_conn, "receive error");
                return;
        }
 
@@ -795,8 +762,44 @@ void smbd_read_handler(struct event_context *ev, struct fd_event *fde,
 
        /* free up temporary memory */
        lp_talloc_free();
+       return;
+}
+
+/*
+  called when a SMB socket becomes writable
+*/
+static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
+{
+       DEBUG(10,("smbsrv_send\n"));
+       return;
+}
+
+/*
+  called when connection is idle
+*/
+static void smbsrv_idle(struct server_connection *conn, time_t t)
+{
+       DEBUG(10,("smbsrv_idle: not implemented!\n"));
+       conn->event.idle->next_event = t + 5;
+
+       return;
 }
 
+static void smbsrv_close(struct server_connection *conn, const char *reason)
+{
+       struct smbsrv_connection *smb_conn = conn->private_data;
+
+       DEBUG(5,("smbsrv_close: %s\n",reason));
+
+       close(conn->event.fde->fd);
+       event_remove_fd_all(conn->event.ctx, conn->socket->fde->fd);
+       event_remove_timed(conn->event.ctx, conn->event.idle);
+
+       conn_close_all(smb_conn);
+
+       talloc_destroy(smb_conn->mem_ctx);
+       return;
+}
 
 /*
   process a message from an SMB socket while still processing a
@@ -810,7 +813,7 @@ void smbd_process_async(struct smbsrv_connection *smb_conn)
        
        req = receive_smb_request(smb_conn);
        if (!req) {
-               smb_conn->model_ops->terminate_connection(smb_conn, "receive error");
+               smbsrv_terminate_connection(smb_conn, "receive error");
                return;
        }
 
@@ -822,18 +825,15 @@ void smbd_process_async(struct smbsrv_connection *smb_conn)
   initialise a server_context from a open socket and register a event handler
   for reading from that socket
 */
-void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int fd,
-                    void (*read_handler)(struct event_context *, struct fd_event *, time_t, uint16_t))
+void smbsrv_accept(struct server_connection *conn)
 {
        struct smbsrv_connection *smb_conn;
        TALLOC_CTX *mem_ctx;
-       struct fd_event fde;
        char *socket_addr;
 
-       set_socket_options(fd,"SO_KEEPALIVE");
-       set_socket_options(fd, lp_socket_options());
+       DEBUG(5,("smbsrv_accept\n"));
 
-       mem_ctx = talloc_init("server_context");
+       mem_ctx = talloc_init("smbsrv_context");
 
        smb_conn = talloc_p(mem_ctx, struct smbsrv_connection);
        if (!smb_conn) return;
@@ -841,16 +841,14 @@ void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int
        ZERO_STRUCTP(smb_conn);
 
        smb_conn->mem_ctx = mem_ctx;
-       smb_conn->socket.fd = fd;
        smb_conn->pid = getpid();
 
        sub_set_context(&smb_conn->substitute);
 
        /* set an initial client name based on its IP address. This will be replaced with
           the netbios name later if it gives us one */
-       socket_addr = get_socket_addr(smb_conn->mem_ctx, fd);
+       socket_addr = get_socket_addr(smb_conn->mem_ctx, conn->socket->fde->fd);
        sub_set_remote_machine(socket_addr);
-       smb_conn->socket.client_addr = socket_addr;
 
        /* now initialise a few default values associated with this smb socket */
        smb_conn->negotiate.max_send = 0xFFFF;
@@ -862,21 +860,36 @@ void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int
        smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
 
        smb_conn->users.next_vuid = VUID_OFFSET;
-       
-       smb_conn->events = ev;
-       smb_conn->model_ops = model_ops;
 
        conn_init(smb_conn);
 
-       /* setup a event handler for this socket. We are initially
-          only interested in reading from the socket */
-       fde.fd = fd;
-       fde.handler = read_handler;
-       fde.private = smb_conn;
-       fde.flags = EVENT_FD_READ;
+       smb_conn->connection = conn;
 
-       event_add_fd(ev, &fde);
+       conn->private_data = smb_conn;
 
        /* setup the DCERPC server subsystem */
        dcesrv_init_context(&smb_conn->dcesrv);
+
+       return;
+}
+
+static const struct server_service_ops smb_server_ops = {
+       .name                   = "smb",
+       .service_init           = smbsrv_init,
+       .accept_connection      = smbsrv_accept,
+       .recv_handler           = smbsrv_recv,
+       .send_handler           = smbsrv_send,
+       .idle_handler           = smbsrv_idle,
+       .close_connection       = smbsrv_close,
+       .service_exit           = smbsrv_exit,  
+};
+
+const struct server_service_ops *smbsrv_get_ops(void)
+{
+       return &smb_server_ops;
+}
+
+NTSTATUS server_service_smb_init(void)
+{
+       return NT_STATUS_OK;    
 }
index 6dc40aee081eba1c296a31102be67cbe40454039..e7b0ecfb0212a4beed95960320cc7a53873ce0e2 100644 (file)
@@ -342,10 +342,8 @@ struct smbsrv_connection {
 
        struct dcesrv_context dcesrv;
 
-       const struct model_ops *model_ops;
-
-       struct event_context *events;
-
        /* the pid of the process handling this session */
        pid_t pid;
+       
+       struct server_connection *connection;
 };
index dd7a7077145c0458d4b21e175839ac0be46f74df..52ccb68aa8d29e5a8dba085bf13b6fcb78e32777 100644 (file)
@@ -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)
index cd0d80150bb281fe4a71864aa2141d0a1dacfb49..f002341a267f0df0e228893daaf3520254115222 100644 (file)
@@ -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
 #######################
 
index f981b36798d3ca82d8539a9daa7de7ea8fdbfe9c..0bdb3163176336480f69cbb9c9830b3b31f2c6fb 100644 (file)
@@ -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 */
index c4c3aa68df07fbfca5b9ab87f85df03dc0958bb3..376b9a8ef89e6e27580da21f84504c36a4b2e446 100644 (file)
@@ -3,6 +3,7 @@
    process model manager - main loop
    Copyright (C) Andrew Tridgell 1992-2003
    Copyright (C) James J Myers 2003 <myersjj@samba.org>
+   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);
 };
index 9c92d8569a10c9935a6589feb05f0cc994cdb429..b65418cd01ea8681be8fe7947cf1cb2ece13800e 100644 (file)
@@ -3,6 +3,7 @@
    process model: process (1 process handles all client connections)
    Copyright (C) Andrew Tridgell 2003
    Copyright (C) James J Myers 2003 <myersjj@samba.org>
+   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
 
 #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);
index 2ee486e1d2f0013b73777e9503b44524fe3d5158..cc02e84d5716bb85be76557cb9d5c7f737402fba 100644 (file)
@@ -3,6 +3,7 @@
    process model: standard (1 process per client connection)
    Copyright (C) Andrew Tridgell 1992-2003
    Copyright (C) James J Myers 2003 <myersjj@samba.org>
+   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
 /*
   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);
index f79f34e3896057585959f8376d8e7f68d564ac75..553e67feebaca380fdac772a86d911b9c9589d4c 100644 (file)
@@ -3,6 +3,7 @@
    thread model: standard (1 thread per client connection)
    Copyright (C) Andrew Tridgell 2003
    Copyright (C) James J Myers 2003 <myersjj@samba.org>
+   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
 #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);
index 5bc826bf7111f753f1aeebb0957bf6d24954d353..d0a4bad37494a5185b3325ac017298c77b03f83e 100644 (file)
@@ -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);
 
 }
index 3a579b846a21e5b4df48dc7c713054d18133a34a..e7487951775b4c4cc89222c16983a91cfb736676 100644 (file)
 
 #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
        
        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) {
        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);     
 
 
        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 (file)
index 0000000..c47cf02
--- /dev/null
@@ -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 (file)
index 0000000..2b6e057
--- /dev/null
@@ -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 (file)
index 0000000..41ad381
--- /dev/null
@@ -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 */