summaryrefslogtreecommitdiff
path: root/source4/smbd
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2004-07-13 21:04:56 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:57:35 -0500
commit45a85bdd353418828df8017a9d7eb7c14f6f0cd3 (patch)
tree14ec6ac1262f9a0a1974b6725a7f26afddb38f61 /source4/smbd
parent9b4ac4d81ecf9786d2a3f96914af4a2895046676 (diff)
downloadsamba-45a85bdd353418828df8017a9d7eb7c14f6f0cd3.tar.gz
samba-45a85bdd353418828df8017a9d7eb7c14f6f0cd3.tar.bz2
samba-45a85bdd353418828df8017a9d7eb7c14f6f0cd3.zip
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)
Diffstat (limited to 'source4/smbd')
-rw-r--r--source4/smbd/config.m47
-rw-r--r--source4/smbd/config.mk24
-rw-r--r--source4/smbd/process_model.c10
-rw-r--r--source4/smbd/process_model.h17
-rw-r--r--source4/smbd/process_single.c119
-rw-r--r--source4/smbd/process_standard.c138
-rw-r--r--source4/smbd/process_thread.c153
-rw-r--r--source4/smbd/rewrite.c6
-rw-r--r--source4/smbd/server.c42
-rw-r--r--source4/smbd/server.h40
-rw-r--r--source4/smbd/service.c241
-rw-r--r--source4/smbd/service.h127
12 files changed, 705 insertions, 219 deletions
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 <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);
};
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 <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
@@ -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 <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
@@ -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 <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
@@ -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 */