summaryrefslogtreecommitdiff
path: root/source4/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source4/smbd')
-rw-r--r--source4/smbd/config.mk19
-rw-r--r--source4/smbd/process_model.c4
-rw-r--r--source4/smbd/process_model.h16
-rw-r--r--source4/smbd/process_single.c71
-rw-r--r--source4/smbd/process_standard.c115
-rw-r--r--source4/smbd/process_thread.c136
-rw-r--r--source4/smbd/rewrite.c8
-rw-r--r--source4/smbd/server.c27
-rw-r--r--source4/smbd/server.h9
-rw-r--r--source4/smbd/service.c221
-rw-r--r--source4/smbd/service.h80
11 files changed, 444 insertions, 262 deletions
diff --git a/source4/smbd/config.mk b/source4/smbd/config.mk
index df421326d8..cd2fb4ab72 100644
--- a/source4/smbd/config.mk
+++ b/source4/smbd/config.mk
@@ -50,24 +50,15 @@ REQUIRED_SUBSYSTEMS = \
# End SUBSYSTEM SERVER
#######################
-#######################
-# Start SUBSYSTEM SERVER
-[SUBSYSTEM::SERVER]
-INIT_OBJ_FILES = \
- smbd/server.o
-ADD_OBJ_FILES = \
- smbd/rewrite.o
-REQUIRED_SUBSYSTEMS = \
- PROCESS_MODEL \
- SERVER_SERVICE
-# End SUBSYSTEM SERVER
-#######################
-
#################################
# Start BINARY smbd
[BINARY::smbd]
+OBJ_FILES = \
+ smbd/server.o \
+ smbd/rewrite.o
REQUIRED_SUBSYSTEMS = \
- SERVER \
+ PROCESS_MODEL \
+ SERVER_SERVICE \
CONFIG \
LIBCMDLINE \
LIBBASIC
diff --git a/source4/smbd/process_model.c b/source4/smbd/process_model.c
index ad9a26d377..f2abfd0a49 100644
--- a/source4/smbd/process_model.c
+++ b/source4/smbd/process_model.c
@@ -27,7 +27,7 @@
/*
setup the events for the chosen process model
*/
-const struct model_ops *process_model_startup(const char *model)
+const struct model_ops *process_model_startup(struct server_context *srv_ctx, const char *model)
{
const struct model_ops *ops;
@@ -37,7 +37,7 @@ const struct model_ops *process_model_startup(const char *model)
exit(-1);
}
- ops->model_startup();
+ ops->model_init(srv_ctx);
return ops;
}
diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h
index 92d92a70ad..fb9bdfd44b 100644
--- a/source4/smbd/process_model.h
+++ b/source4/smbd/process_model.h
@@ -3,7 +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
+ Copyright (C) Stefan (metze) Metzmacher 2004-2005
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
@@ -37,21 +37,23 @@ struct model_ops {
const char *name;
/* called at startup when the model is selected */
- void (*model_startup)(void);
+ void (*model_init)(struct server_context *srv_ctx);
+ /* called at th eend of the main server process */
+ void (*model_exit)(struct server_context *srv_ctx, const char *reason);
+
/* function to accept new connection */
void (*accept_connection)(struct event_context *, struct fd_event *,
struct timeval t, uint16_t);
-
/* function to terminate a connection */
void (*terminate_connection)(struct server_connection *srv_conn,
const char *reason);
- /* function to exit server */
- void (*exit_server)(struct server_context *srv_ctx, const char *reason);
- /* returns process or thread id */
- int (*get_id)(struct smbsrv_request *req);
+ /* function to create a new task event_context */
+ void (*create_task)(struct server_task *task);
+ /* function to exit this task */
+ void (*terminate_task)(struct server_task *task, const char *reason);
};
/* this structure is used by modules to determine the size of some critical types */
diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c
index da23470303..6a00ad237f 100644
--- a/source4/smbd/process_single.c
+++ b/source4/smbd/process_single.c
@@ -30,9 +30,15 @@
/*
called when the process model is selected
*/
-static void single_start_server(void)
+static void single_model_init(struct server_context *server)
{
- smbd_process_init();
+}
+
+static void single_model_exit(struct server_context *server, const char *reason)
+{
+ DEBUG(1,("single_exit_server: reason[%s]\n",reason));
+ talloc_free(server);
+ exit(0);
}
/*
@@ -43,18 +49,18 @@ static void single_accept_connection(struct event_context *ev, struct fd_event *
{
NTSTATUS status;
struct socket_context *sock;
- struct server_socket *server_socket = srv_fde->private;
+ struct server_stream_socket *stream_socket = srv_fde->private;
struct server_connection *conn;
/* accept an incoming connection. */
- status = socket_accept(server_socket->socket, &sock);
+ status = socket_accept(stream_socket->socket, &sock);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("accept_connection_single: accept: %s\n",
nt_errstr(status)));
return;
}
- conn = server_setup_connection(ev, server_socket, sock, t, socket_get_fd(sock));
+ conn = server_setup_connection(ev, stream_socket, sock, t, socket_get_fd(sock));
if (!conn) {
DEBUG(10,("server_setup_connection failed\n"));
return;
@@ -62,8 +68,6 @@ static void single_accept_connection(struct event_context *ev, struct fd_event *
talloc_steal(conn, sock);
- DLIST_ADD(server_socket->connection_list,conn);
-
/* return to event handling */
return;
}
@@ -80,38 +84,57 @@ static void single_terminate_connection(struct server_connection *conn, const ch
}
}
-static int single_get_id(struct smbsrv_request *req)
+/*
+ called to create a new event context for a new task
+*/
+static void single_create_task(struct server_task *task)
{
- return (int)req->smb_conn->pid;
+ task->task.id = (uint32_t)task;
+ task->event.ctx = task->service->server->event.ctx;
+
+ /* setup to receive internal messages on this connection */
+ task->messaging.ctx = messaging_init(task, task->task.id, task->event.ctx);
+ if (!task->messaging.ctx) {
+ server_terminate_task(task, "messaging_init() failed");
+ return;
+ }
+
+ task->task.ops->task_init(task);
+ return;
}
-static void single_exit_server(struct server_context *srv_ctx, const char *reason)
+/*
+ called to exit from a server_task
+*/
+static void single_terminate_task(struct server_task *task, const char *reason)
{
DEBUG(1,("single_exit_server: reason[%s]\n",reason));
+ talloc_free(task);
+ return;
}
+static const struct model_ops single_ops = {
+ .name = "single",
+
+ .model_init = single_model_init,
+ .model_exit = single_model_exit,
+
+ .accept_connection = single_accept_connection,
+ .terminate_connection = single_terminate_connection,
+
+ .create_task = single_create_task,
+ .terminate_task = single_terminate_task
+};
+
/*
initialise the single process model, registering ourselves with the process model subsystem
*/
NTSTATUS process_model_single_init(void)
{
NTSTATUS ret;
- struct model_ops ops;
-
- ZERO_STRUCT(ops);
-
- /* fill in our name */
- ops.name = "single";
-
- /* fill in all the operations */
- 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_process_model(&ops);
+ ret = register_process_model(&single_ops);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("Failed to register process_model 'single'!\n"));
return ret;
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index 3612c6a7f4..b0f7cf1a11 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -29,10 +29,16 @@
/*
called when the process model is selected
*/
-static void standard_model_startup(void)
+static void standard_model_init(struct server_context *server)
{
signal(SIGCHLD, SIG_IGN);
- smbd_process_init();
+}
+
+static void standard_model_exit(struct server_context *server, const char *reason)
+{
+ DEBUG(1,("standard_model_exit: reason[%s]\n",reason));
+ talloc_free(server);
+ exit(0);
}
/*
@@ -43,12 +49,12 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event
{
NTSTATUS status;
struct socket_context *sock;
- struct server_socket *server_socket = srv_fde->private;
+ struct server_stream_socket *stream_socket = srv_fde->private;
struct server_connection *conn;
pid_t pid;
/* accept an incoming connection. */
- status = socket_accept(server_socket->socket, &sock);
+ status = socket_accept(stream_socket->socket, &sock);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("standard_accept_connection: accept: %s\n",
nt_errstr(status)));
@@ -68,7 +74,7 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event
/* Child code ... */
/* close all the listening sockets */
- service_close_listening_sockets(server_socket->service->srv_ctx);
+ event_remove_fd_all_handler(ev, server_accept_handler);
/* we don't care if the dup fails, as its only a select()
speed optimisation */
@@ -83,16 +89,15 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event
set_need_random_reseed();
- conn = server_setup_connection(ev, server_socket, sock, t, getpid());
+ conn = server_setup_connection(ev, stream_socket, sock, t, getpid());
if (!conn) {
DEBUG(0,("server_setup_connection(ev, server_socket, sock, t) failed\n"));
+ exit(1);
return;
}
talloc_steal(conn, sock);
- DLIST_ADD(server_socket->connection_list,conn);
-
/* return to the event loop */
}
@@ -103,7 +108,7 @@ static void standard_terminate_connection(struct server_connection *conn, const
DEBUG(2,("standard_terminate_connection: reason[%s]\n",reason));
if (conn) {
- talloc_free(conn->service->srv_ctx);
+ talloc_free(conn->stream_socket->service->server);
}
/* this init_iconv() has the effect of freeing the iconv context memory,
@@ -117,38 +122,94 @@ static void standard_terminate_connection(struct server_connection *conn, const
exit(0);
}
-static int standard_get_id(struct smbsrv_request *req)
+/*
+ called to create a new event context for a new task
+*/
+static void standard_create_task(struct server_task *task)
{
- return (int)req->smb_conn->pid;
+ pid_t pid;
+
+ pid = fork();
+
+ if (pid != 0) {
+ /* parent or error code ... */
+ talloc_free(task);
+ /* go back to the event loop */
+ return;
+ }
+
+ /* Child code ... */
+
+ /* close all the listening sockets */
+ event_remove_fd_all_handler(task->service->server->event.ctx, server_accept_handler);
+
+ /* tdb needs special fork handling */
+ if (tdb_reopen_all() == -1) {
+ DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n"));
+ }
+
+ /* Ensure that the forked children do not expose identical random streams */
+
+ set_need_random_reseed();
+
+ task->task.id = (uint32)getpid();
+ task->event.ctx = task->service->server->event.ctx;
+
+ /* setup to receive internal messages on this connection */
+ task->messaging.ctx = messaging_init(task, task->task.id, task->event.ctx);
+ if (!task->messaging.ctx) {
+ server_terminate_task(task, "messaging_init() failed");
+ return;
+ }
+
+ task->task.ops->task_init(task);
+
+ server_terminate_task(task, "exit");
+ return;
}
-static void standard_exit_server(struct server_context *srv_ctx, const char *reason)
+/*
+ called to destroy a new event context for a new task
+*/
+static void standard_terminate_task(struct server_task *task, const char *reason)
{
- DEBUG(1,("standard_exit_server: reason[%s]\n",reason));
+ DEBUG(2,("standard_terminate_task: reason[%s]\n",reason));
+
+ talloc_free(task);
+
+ /* this init_iconv() has the effect of freeing the iconv context memory,
+ which makes leak checking easier */
+ init_iconv();
+
+ /* the secrets db should really hang off the connection structure */
+ secrets_shutdown();
+
+ /* terminate this process */
+ exit(0);
}
+static const struct model_ops standard_ops = {
+ .name = "standard",
+
+ .model_init = standard_model_init,
+ .model_exit = standard_model_exit,
+
+ .accept_connection = standard_accept_connection,
+ .terminate_connection = standard_terminate_connection,
+
+ .create_task = standard_create_task,
+ .terminate_task = standard_terminate_task
+};
+
/*
initialise the standard process model, registering ourselves with the process model subsystem
*/
NTSTATUS process_model_standard_init(void)
{
NTSTATUS ret;
- struct model_ops ops;
-
- ZERO_STRUCT(ops);
-
- /* fill in our name */
- ops.name = "standard";
-
- /* fill in all the operations */
- 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 = standard_get_id;
/* register ourselves with the PROCESS_MODEL subsystem. */
- ret = register_process_model(&ops);
+ ret = register_process_model(&standard_ops);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("Failed to register process_model 'standard'!\n"));
return ret;
diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c
index 8e8ee23aaf..f0e98221ae 100644
--- a/source4/smbd/process_thread.c
+++ b/source4/smbd/process_thread.c
@@ -33,9 +33,12 @@
static void *thread_connection_fn(void *thread_parm)
{
- struct event_context *ev = thread_parm;
+ struct server_connection *conn = thread_parm;
+
+ conn->connection.id = pthread_self();
+
/* wait for action */
- event_loop_wait(ev);
+ event_loop_wait(conn->event.ctx);
#if 0
pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */
@@ -43,11 +46,6 @@ static void *thread_connection_fn(void *thread_parm)
return NULL;
}
-static int thread_get_id(struct smbsrv_request *req)
-{
- return (int)pthread_self();
-}
-
/*
called when a listening socket becomes readable
*/
@@ -59,15 +57,15 @@ static void thread_accept_connection(struct event_context *ev, struct fd_event *
int rc;
pthread_t thread_id;
pthread_attr_t thread_attr;
- struct server_socket *server_socket = srv_fde->private;
+ struct server_stream_socket *stream_socket = srv_fde->private;
struct server_connection *conn;
/* accept an incoming connection. */
- status = socket_accept(server_socket->socket, &sock);
+ status = socket_accept(stream_socket->socket, &sock);
if (!NT_STATUS_IS_OK(status)) {
return;
}
-
+
/* create new detached thread for this connection. The new
thread gets a new event_context with a single fd_event for
receiving from the new socket. We set that thread running
@@ -75,13 +73,13 @@ static void thread_accept_connection(struct event_context *ev, struct fd_event *
main event_context is continued.
*/
- ev = event_context_init(server_socket);
+ ev = event_context_init(stream_socket);
if (!ev) {
socket_destroy(sock);
- return;
+ return;
}
- conn = server_setup_connection(ev, server_socket, sock, t, pthread_self());
+ conn = server_setup_connection(ev, stream_socket, sock, t, -1);
if (!conn) {
event_context_destroy(ev);
socket_destroy(sock);
@@ -91,16 +89,9 @@ static void thread_accept_connection(struct event_context *ev, struct fd_event *
talloc_steal(conn, ev);
talloc_steal(conn, sock);
- /* TODO: is this MUTEX_LOCK in the right place here?
- * --metze
- */
- MUTEX_LOCK_BY_ID(MUTEX_SMBD);
- 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, thread_connection_fn, ev);
+ rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, conn);
pthread_attr_destroy(&thread_attr);
if (rc == 0) {
DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n",
@@ -414,7 +405,7 @@ static void thread_fault_handler(int sig)
/*
called when the process model is selected
*/
-static void thread_model_startup(void)
+static void thread_model_init(struct server_context *server)
{
struct mutex_ops m_ops;
struct debug_ops d_ops;
@@ -422,8 +413,6 @@ static void thread_model_startup(void)
ZERO_STRUCT(m_ops);
ZERO_STRUCT(d_ops);
- smbd_process_init();
-
/* register mutex/rwlock handlers */
m_ops.mutex_init = thread_mutex_init;
m_ops.mutex_lock = thread_mutex_lock;
@@ -448,33 +437,100 @@ static void thread_model_startup(void)
register_debug_handlers("thread", &d_ops);
}
-static void thread_exit_server(struct server_context *srv_ctx, const char *reason)
+static void thread_model_exit(struct server_context *server, const char *reason)
{
- DEBUG(1,("thread_exit_server: reason[%s]\n",reason));
+ DEBUG(1,("thread_model_exit: reason[%s]\n",reason));
+ talloc_free(server);
+ exit(0);
}
+static void *thread_task_fn(void *thread_parm)
+{
+ struct server_task *task = thread_parm;
+
+ task->task.id = pthread_self();
+
+ task->event.ctx = event_context_init(task);
+ if (!task->event.ctx) {
+ server_terminate_task(task, "event_context_init() failed");
+ return NULL;
+ }
+
+ task->messaging.ctx = messaging_init(task, task->task.id, task->event.ctx);
+ if (!task->messaging.ctx) {
+ server_terminate_task(task, "messaging_init() failed");
+ return NULL;
+ }
+
+ task->task.ops->task_init(task);
+
+ /* wait for action */
+ event_loop_wait(task->event.ctx);
+
+ server_terminate_task(task, "exit");
+#if 0
+ pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */
+#endif
+ return NULL;
+}
+/*
+ called to create a new event context for a new task
+*/
+static void thread_create_task(struct server_task *task)
+{
+ int rc;
+ pthread_t thread_id;
+ pthread_attr_t thread_attr;
+
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+ rc = pthread_create(&thread_id, &thread_attr, thread_task_fn, task);
+ pthread_attr_destroy(&thread_attr);
+ if (rc == 0) {
+ DEBUG(4,("thread_create_task: created thread_id=%lu for task='%s'\n",
+ (unsigned long int)thread_id, task->task.ops->name));
+ } else {
+ DEBUG(0,("thread_create_task: thread create failed for task='%s', rc=%d\n", task->task.ops->name, rc));
+ return;
+ }
+ return;
+}
+
+/*
+ called to destroy a new event context for a new task
+*/
+static void thread_terminate_task(struct server_task *task, const char *reason)
+{
+ DEBUG(2,("thread_terminate_task: reason[%s]\n",reason));
+
+ talloc_free(task);
+
+ /* terminate this thread */
+ pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
+}
+
+static const struct model_ops thread_ops = {
+ .name = "thread",
+
+ .model_init = thread_model_init,
+ .model_exit = thread_model_exit,
+
+ .accept_connection = thread_accept_connection,
+ .terminate_connection = thread_terminate_connection,
+
+ .create_task = thread_create_task,
+ .terminate_task = thread_terminate_task
+};
+
/*
initialise the thread process model, registering ourselves with the model subsystem
*/
NTSTATUS process_model_thread_init(void)
{
NTSTATUS ret;
- struct model_ops ops;
-
- ZERO_STRUCT(ops);
-
- /* fill in our name */
- ops.name = "thread";
-
- /* fill in all the operations */
- 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 = thread_get_id;
/* register ourselves with the PROCESS_MODEL subsystem. */
- ret = register_process_model(&ops);
+ ret = register_process_model(&thread_ops);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,("Failed to register process_model 'thread'!\n"));
return ret;
diff --git a/source4/smbd/rewrite.c b/source4/smbd/rewrite.c
index 8e7ddc405e..7128a0ad0d 100644
--- a/source4/smbd/rewrite.c
+++ b/source4/smbd/rewrite.c
@@ -1,14 +1,6 @@
#include "includes.h"
#include "dynconfig.h"
-/*
-
- this is a set of temporary stub functions used during the core smbd rewrite.
- This file will need to go away before the rewrite is complete
-*/
-
-BOOL pcap_printername_ok(const char *service, const char *foo)
-{ return True; }
/*
* initialize an smb process. Guaranteed to be called only once per
diff --git a/source4/smbd/server.c b/source4/smbd/server.c
index 830d26fa7f..369391bdbf 100644
--- a/source4/smbd/server.c
+++ b/source4/smbd/server.c
@@ -24,12 +24,6 @@
#include "includes.h"
#include "lib/cmdline/popt_common.h"
-static void exit_server(const char *reason)
-{
- DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
- exit(0);
-}
-
/****************************************************************************
main server.
****************************************************************************/
@@ -41,10 +35,10 @@ static int binary_smbd_main(int argc,const char *argv[])
BOOL log_stdout = False;
int opt;
poptContext pc;
- struct server_context *srv_ctx;
+ struct server_context *server;
const char *model = "standard";
struct poptOption long_options[] = {
- POPT_AUTOHELP
+ POPT_AUTOHELP
POPT_COMMON_SAMBA
{"daemon", 'D', POPT_ARG_VAL, &is_daemon, True, "Become a daemon (default)" , NULL },
{"interactive", 'i', POPT_ARG_VAL, &interactive, True, "Run interactive (not a daemon)", NULL},
@@ -52,6 +46,7 @@ static int binary_smbd_main(int argc,const char *argv[])
{"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout", NULL },
{"port", 'p', POPT_ARG_STRING, NULL, 0, "Listen on the specified ports", "PORTS"},
{"model", 'M', POPT_ARG_STRING, &model, True, "Select process model", "MODEL"},
+ POPT_COMMON_VERSION
POPT_TABLEEND
};
@@ -77,7 +72,7 @@ static int binary_smbd_main(int argc,const char *argv[])
}
setup_logging(argv[0], log_stdout?DEBUG_STDOUT:DEBUG_FILE);
- fault_setup((void (*)(void *))exit_server);
+ fault_setup(NULL);
/* we are never interested in SIGPIPE */
BlockSignals(True,SIGPIPE);
@@ -105,7 +100,7 @@ static int binary_smbd_main(int argc,const char *argv[])
reopen_logs();
DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION_STRING));
- DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2004\n"));
+ DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2005\n"));
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"));
@@ -142,15 +137,21 @@ static int binary_smbd_main(int argc,const char *argv[])
init_subsystems();
+ smbd_process_init();
+
DEBUG(0,("Using %s process model\n", model));
- srv_ctx = server_service_startup(model);
- if (!srv_ctx) {
+ server = server_service_startup(model, lp_server_services());
+ if (!server) {
DEBUG(0,("Starting Services failed.\n"));
return 1;
}
/* wait for events */
- return event_loop_wait(srv_ctx->events);
+ event_loop_wait(server->event.ctx);
+
+ server_service_shutdown(server, "exit");
+
+ return 0;
}
int main(int argc, const char *argv[])
diff --git a/source4/smbd/server.h b/source4/smbd/server.h
index e76adec44d..6021df12c5 100644
--- a/source4/smbd/server.h
+++ b/source4/smbd/server.h
@@ -25,8 +25,15 @@ struct server_service;
struct event_context;
struct server_context {
+ struct {
+ struct event_context *ctx;
+ } event;
+
+ struct {
+ const struct model_ops *ops;
+ } model;
+
struct server_service *service_list;
- struct event_context *events;
};
/* size of listen() backlog in smbd */
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index 586c05c2c6..e0ec3cf07e 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -27,38 +27,33 @@
#include "dlinklist.h"
#include "process_model.h"
-struct server_context *server_service_startup(const char *model)
+struct server_context *server_service_startup(const char *model, const char **server_services)
{
int i;
- const char **server_services = lp_server_services();
- struct server_context *srv_ctx;
- const struct model_ops *model_ops;
+ struct server_context *server;
if (!server_services) {
- DEBUG(0,("process_model_startup: no endpoint servers configured\n"));
+ DEBUG(0,("server_service_startup: no endpoint servers configured\n"));
return NULL;
}
- model_ops = process_model_startup(model);
- if (!model_ops) {
- DEBUG(0,("process_model_startup('%s') failed\n", model));
- return NULL;
- }
-
- srv_ctx = talloc_p(NULL, struct server_context);
- if (!srv_ctx) {
+ server = talloc_zero(NULL, struct server_context);
+ if (!server) {
return NULL;
}
- ZERO_STRUCTP(srv_ctx);
+ server->model.ops = process_model_startup(server, model);
+ if (!server->model.ops) {
+ DEBUG(0,("process_model_startup('%s') failed\n", model));
+ return NULL;
+ }
- srv_ctx->events = event_context_init(srv_ctx);
- if (!srv_ctx->events) {
+ server->event.ctx = event_context_init(server);
+ if (!server->event.ctx) {
DEBUG(0,("event_context_init() failed\n"));
- return NULL;
+ return NULL;
}
-
for (i=0;server_services[i];i++) {
const struct server_service_ops *service_ops;
struct server_service *service;
@@ -69,63 +64,64 @@ struct server_context *server_service_startup(const char *model)
return NULL;
}
- service = talloc_p(srv_ctx, struct server_service);
+ service = talloc_zero(server, struct server_service);
if (!service) {
return NULL;
}
- ZERO_STRUCTP(service);
- service->ops = service_ops;
- service->model_ops = model_ops;
- service->srv_ctx = srv_ctx;
-
+ service->service.ops = service_ops;
+ service->server = server;
+
/* TODO: service_init() should return a result */
- service->ops->service_init(service, model_ops);
+ service->service.ops->service_init(service);
- DLIST_ADD(srv_ctx->service_list, service);
+ DLIST_ADD(server->service_list, service);
}
- return srv_ctx;
+ return server;
+}
+
+void server_service_shutdown(struct server_context *server, const char *reason)
+{
+ server->model.ops->model_exit(server, reason);
}
/*
setup a listen stream socket
if you pass *port == 0, then a port > 1024 is used
*/
-struct server_socket *service_setup_socket(struct server_service *service,
- const struct model_ops *model_ops,
- const char *family,
- const char *sock_addr,
- uint16_t *port)
+struct server_stream_socket *service_setup_stream_socket(struct server_service *service,
+ const struct server_stream_ops *stream_ops,
+ const char *family,
+ const char *sock_addr,
+ uint16_t *port)
{
NTSTATUS status;
- struct server_socket *srv_sock;
- struct socket_context *socket_ctx;
+ struct server_stream_socket *stream_socket;
+ struct socket_context *sock;
struct fd_event fde;
int i;
- status = socket_create(family, SOCKET_TYPE_STREAM, &socket_ctx, 0);
+ status = socket_create(family, SOCKET_TYPE_STREAM, &sock, 0);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to open socket on %s:%u - %s\n",
sock_addr, *port, nt_errstr(status)));
return NULL;
}
- talloc_steal(service, socket_ctx);
-
/* ready to listen */
- status = socket_set_option(socket_ctx, "SO_KEEPALIVE SO_REUSEADDR=1", NULL);
+ status = socket_set_option(sock, "SO_KEEPALIVE SO_REUSEADDR=1", NULL);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("socket_set_option(socket_ctx, SO_KEEPALIVE, NULL): %s\n",
nt_errstr(status)));
- socket_destroy(socket_ctx);
+ socket_destroy(sock);
return NULL;
}
- status = socket_set_option(socket_ctx, lp_socket_options(), NULL);
+ status = socket_set_option(sock, lp_socket_options(), NULL);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("socket_set_option(socket_ctx, lp_socket_options(), NULL): %s\n",
nt_errstr(status)));
- socket_destroy(socket_ctx);
+ socket_destroy(sock);
return NULL;
}
@@ -133,64 +129,70 @@ struct server_socket *service_setup_socket(struct server_service *service,
if (*port == 0) {
for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
- status = socket_listen(socket_ctx, sock_addr, i, SERVER_LISTEN_BACKLOG, 0);
+ status = socket_listen(sock, sock_addr, i, SERVER_LISTEN_BACKLOG, 0);
if (NT_STATUS_IS_OK(status)) {
*port = i;
break;
}
}
} else {
- status = socket_listen(socket_ctx, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0);
+ status = socket_listen(sock, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0);
}
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to listen on %s:%u - %s\n",
sock_addr, *port, nt_errstr(status)));
- socket_destroy(socket_ctx);
+ socket_destroy(sock);
return NULL;
}
- srv_sock = talloc_p(service, struct server_socket);
- if (!srv_sock) {
- DEBUG(0,("talloc_p(mem_ctx, struct server_socket) failed\n"));
- socket_destroy(socket_ctx);
+ stream_socket = talloc_zero(service, struct server_stream_socket);
+ if (!stream_socket) {
+ DEBUG(0,("talloc_p(mem_ctx, struct server_stream_socket) failed\n"));
+ socket_destroy(sock);
return NULL;
}
/* we are only interested in read events on the listen socket */
- fde.fd = socket_get_fd(socket_ctx);
+ fde.fd = socket_get_fd(sock);
fde.flags = EVENT_FD_READ;
- fde.private = srv_sock;
- fde.handler = model_ops->accept_connection;
-
- ZERO_STRUCTP(srv_sock);
- srv_sock->service = service;
- srv_sock->socket = socket_ctx;
- srv_sock->event.ctx = service->srv_ctx->events;
- srv_sock->event.fde = event_add_fd(srv_sock->event.ctx, &fde);
- if (!srv_sock->event.fde) {
- DEBUG(0,("event_add_fd(srv_sock->event.ctx, &fde) failed\n"));
- socket_destroy(socket_ctx);
+ fde.private = stream_socket;
+ fde.handler = server_accept_handler;
+
+ stream_socket->stream.ops = stream_ops;
+ stream_socket->service = service;
+ stream_socket->socket = sock;
+ stream_socket->event.ctx = service->server->event.ctx;
+ stream_socket->event.fde = event_add_fd(stream_socket->event.ctx, &fde);
+ if (!stream_socket->event.fde) {
+ DEBUG(0,("event_add_fd(stream_socket->event.ctx, &fde) failed\n"));
+ socket_destroy(sock);
return NULL;
}
- DLIST_ADD(service->socket_list, srv_sock);
+ talloc_steal(stream_socket, sock);
- return srv_sock;
+ if (stream_socket->stream.ops->socket_init) {
+ stream_socket->stream.ops->socket_init(stream_socket);
+ }
+
+ return stream_socket;
}
/*
destructor that handles necessary event context changes
*/
-static int server_destructor(void *ptr)
+static int server_connection_destructor(void *ptr)
{
struct server_connection *conn = ptr;
- if (conn->service) {
- conn->service->ops->close_connection(conn, "shutdown");
- }
-
- socket_destroy(conn->socket);
+ if (conn->stream_socket &&
+ conn->stream_socket->stream.ops->close_connection) {
+ /* don't remove this! the stream service needs to free it's data
+ * before we destroy the server_connection
+ */
+ conn->stream_socket->stream.ops->close_connection(conn, "shutdown");
+ }
if (conn->event.fde) {
event_remove_fd(conn->event.ctx, conn->event.fde);
@@ -201,13 +203,11 @@ static int server_destructor(void *ptr)
conn->event.idle = NULL;
}
- DLIST_REMOVE(conn->server_socket->connection_list, conn);
-
return 0;
}
struct server_connection *server_setup_connection(struct event_context *ev,
- struct server_socket *server_socket,
+ struct server_stream_socket *stream_socket,
struct socket_context *sock,
struct timeval t,
servid_t server_id)
@@ -216,7 +216,7 @@ struct server_connection *server_setup_connection(struct event_context *ev,
struct timed_event idle;
struct server_connection *srv_conn;
- srv_conn = talloc_p(server_socket, struct server_connection);
+ srv_conn = talloc_p(stream_socket, struct server_connection);
if (!srv_conn) {
DEBUG(0,("talloc_p(mem_ctx, struct server_connection) failed\n"));
return NULL;
@@ -238,20 +238,19 @@ struct server_connection *server_setup_connection(struct event_context *ev,
srv_conn->event.idle = &idle;
srv_conn->event.idle_time = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0);
- srv_conn->server_socket = server_socket;
- srv_conn->service = server_socket->service;
+ srv_conn->stream_socket = stream_socket;
srv_conn->socket = sock;
- srv_conn->server_id = server_id;
+ srv_conn->connection.id = server_id;
/* create a server context and add it to out event
handling */
- server_socket->service->ops->accept_connection(srv_conn);
+ stream_socket->stream.ops->accept_connection(srv_conn);
/* accpect_connection() of the service may changed idle.next_event */
srv_conn->event.fde = event_add_fd(ev,&fde);
srv_conn->event.idle = event_add_timed(ev,&idle);
- talloc_set_destructor(srv_conn, server_destructor);
+ talloc_set_destructor(srv_conn, server_connection_destructor);
if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) {
server_terminate_connection(srv_conn, "denied by access rules");
@@ -259,7 +258,11 @@ struct server_connection *server_setup_connection(struct event_context *ev,
}
/* setup to receive internal messages on this connection */
- srv_conn->messaging_ctx = messaging_init(srv_conn, srv_conn->server_id, ev);
+ srv_conn->messaging.ctx = messaging_init(srv_conn, srv_conn->connection.id, ev);
+ if (!srv_conn->messaging.ctx) {
+ server_terminate_connection(srv_conn, "messaging_init() failed");
+ return NULL;
+ }
return srv_conn;
}
@@ -270,7 +273,15 @@ struct server_connection *server_setup_connection(struct event_context *ev,
void server_terminate_connection(struct server_connection *srv_conn, const char *reason)
{
DEBUG(2,("server_terminate_connection\n"));
- srv_conn->service->model_ops->terminate_connection(srv_conn, reason);
+ srv_conn->stream_socket->service->server->model.ops->terminate_connection(srv_conn, reason);
+}
+
+void server_accept_handler(struct event_context *ev, struct fd_event *fde,
+ struct timeval t, uint16_t flags)
+{
+ struct server_stream_socket *stream_socket = fde->private;
+
+ stream_socket->service->server->model.ops->accept_connection(ev, fde, t, flags);
}
void server_io_handler(struct event_context *ev, struct fd_event *fde,
@@ -281,12 +292,12 @@ void server_io_handler(struct event_context *ev, struct fd_event *fde,
conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
if (flags & EVENT_FD_WRITE) {
- conn->service->ops->send_handler(conn, t, flags);
+ conn->stream_socket->stream.ops->send_handler(conn, t, flags);
return;
}
if (flags & EVENT_FD_READ) {
- conn->service->ops->recv_handler(conn, t, flags);
+ conn->stream_socket->stream.ops->recv_handler(conn, t, flags);
}
}
@@ -296,13 +307,34 @@ void server_idle_handler(struct event_context *ev, struct timed_event *idle,
{
struct server_connection *conn = idle->private;
- conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
-
/* Not all services provide an idle handler */
- if (conn->service->ops->idle_handler) {
- conn->service->ops->idle_handler(conn, t);
+ if (conn->stream_socket->stream.ops->idle_handler) {
+ conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
+ conn->stream_socket->stream.ops->idle_handler(conn, t);
}
}
+
+void server_terminate_task(struct server_task *task, const char *reason)
+{
+ task->service->server->model.ops->terminate_task(task, reason);
+ return;
+}
+
+void server_run_task(struct server_service *service, const struct server_task_ops *ops)
+{
+ struct server_task *task;
+
+ task = talloc_zero(service, struct server_task);
+ if (!task) {
+ return;
+ }
+ task->service = service;
+ task->task.ops = ops;
+
+ service->server->model.ops->create_task(task);
+ return;
+}
+
/*
return the operations structure for a named backend of the specified type
*/
@@ -326,25 +358,6 @@ NTSTATUS register_server_service_ops(const void *_ops)
}
/*
- close all listening sockets. This is called by process models that fork, to
- ensure that the listen sockets from the parent are closed
-*/
-void service_close_listening_sockets(struct server_context *srv_ctx)
-{
- struct server_service *svc;
- for (svc=srv_ctx->service_list;svc;svc=svc->next) {
- struct server_socket *sock;
- for (sock=svc->socket_list;sock;sock=sock->next) {
- event_remove_fd(sock->event.ctx, sock->event.fde);
- sock->event.fde = NULL;
- socket_destroy(sock->socket);
- sock->socket = NULL;
- }
- }
-}
-
-
-/*
cleanup temporary files. This is the new alternative to
TDB_CLEAR_IF_FIRST. Unfortunately TDB_CLEAR_IF_FIRST is not
efficient on unix systems due to the lack of scaling of the byte
diff --git a/source4/smbd/service.h b/source4/smbd/service.h
index 20bf6e9b8f..d5335b1cef 100644
--- a/source4/smbd/service.h
+++ b/source4/smbd/service.h
@@ -42,7 +42,17 @@ struct server_service_ops {
const char *name;
/* called at startup when the server_service is selected */
- void (*service_init)(struct server_service *service, const struct model_ops *ops);
+ void (*service_init)(struct server_service *service);
+};
+
+struct server_stream_socket;
+
+struct server_stream_ops {
+ /* the name of the server_service */
+ const char *name;
+
+ /* called at startup when the server_service is selected */
+ void (*socket_init)(struct server_stream_socket *socket);
/* function to accept new connection */
void (*accept_connection)(struct server_connection *);
@@ -56,16 +66,16 @@ struct server_service_ops {
/* 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_context;
-struct server_socket {
- struct server_socket *next,*prev;
- void *private_data;
+struct server_stream_socket {
+ struct server_stream_socket *next,*prev;
+ struct {
+ const struct server_stream_ops *ops;
+ void *private_data;
+ } stream;
struct {
struct event_context *ctx;
@@ -75,20 +85,16 @@ struct server_socket {
struct socket_context *socket;
struct server_service *service;
-
- struct server_connection *connection_list;
};
struct server_service {
struct server_service *next,*prev;
- void *private_data;
- const struct server_service_ops *ops;
-
- const struct model_ops *model_ops;
-
- struct server_socket *socket_list;
+ struct {
+ const struct server_service_ops *ops;
+ void *private_data;
+ } service;
- struct server_context *srv_ctx;
+ struct server_context *server;
};
/* the concept of whether two operations are on the same server
@@ -106,7 +112,10 @@ typedef uint32_t servid_t;
struct server_connection {
struct server_connection *next,*prev;
- void *private_data;
+ struct {
+ void *private_data;
+ servid_t id;
+ } connection;
struct {
struct event_context *ctx;
@@ -115,15 +124,42 @@ struct server_connection {
struct timeval idle_time;
} event;
- servid_t server_id;
-
struct socket_context *socket;
- struct server_socket *server_socket;
+ struct server_stream_socket *stream_socket;
- struct server_service *service;
+ struct {
+ struct messaging_context *ctx;
+ } messaging;
+};
+
+struct server_task;
+
+struct server_task_ops {
+ /* the name of the server_task */
+ const char *name;
+
+ /* called at startup when the server_task is selected */
+ void (*task_init)(struct server_task *task);
+};
+
+struct server_task {
+ struct server_task *next,*prev;
+ struct {
+ const struct server_task_ops *ops;
+ void *private_data;
+ servid_t id;
+ } task;
+
+ struct {
+ struct event_context *ctx;
+ } event;
+
+ struct {
+ struct messaging_context *ctx;
+ } messaging;
- struct messaging_context *messaging_ctx;
+ struct server_service *service;
};
#endif /* _SERVER_SERVICE_H */