summaryrefslogtreecommitdiff
path: root/source4/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source4/smbd')
-rw-r--r--source4/smbd/config.mk3
-rw-r--r--source4/smbd/process_model.h10
-rw-r--r--source4/smbd/process_single.c18
-rw-r--r--source4/smbd/process_standard.c58
-rw-r--r--source4/smbd/process_thread.c69
-rw-r--r--source4/smbd/service_stream.c4
-rw-r--r--source4/smbd/service_task.c90
-rw-r--r--source4/smbd/service_task.h30
8 files changed, 266 insertions, 16 deletions
diff --git a/source4/smbd/config.mk b/source4/smbd/config.mk
index 07847b7fc8..4d5e929c79 100644
--- a/source4/smbd/config.mk
+++ b/source4/smbd/config.mk
@@ -45,7 +45,8 @@ REQUIRED_SUBSYSTEMS = \
[SUBSYSTEM::SERVER_SERVICE]
INIT_OBJ_FILES = \
smbd/service.o \
- smbd/service_stream.o
+ smbd/service_stream.o \
+ smbd/service_task.o
REQUIRED_SUBSYSTEMS = \
MESSAGING
# End SUBSYSTEM SERVER
diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h
index 943538d7b2..2e064f4277 100644
--- a/source4/smbd/process_model.h
+++ b/source4/smbd/process_model.h
@@ -44,8 +44,14 @@ struct model_ops {
uint32_t , void *),
void *);
- /* function to terminate a connection */
- void (*terminate_connection)(struct event_context *, const char *reason);
+ /* function to create a task */
+ void (*new_task)(struct event_context *,
+ void (*)(struct event_context *, uint32_t, void *),
+ void *);
+
+ /* function to terminate a task */
+ void (*terminate)(struct event_context *, 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 d6217d8712..7d43855f6c 100644
--- a/source4/smbd/process_single.c
+++ b/source4/smbd/process_single.c
@@ -59,17 +59,29 @@ static void single_accept_connection(struct event_context *ev,
new_conn(ev, sock2, socket_get_fd(sock), private);
}
+/*
+ called to startup a new task
+*/
+static void single_new_task(struct event_context *ev,
+ void (*new_task)(struct event_context *, uint32_t, void *),
+ void *private)
+{
+ static uint32_t taskid = 0x10000000;
+ new_task(ev, taskid++, private);
+}
+
-/* called when a connection goes down */
-static void single_terminate_connection(struct event_context *ev, const char *reason)
+/* called when a task goes down */
+static void single_terminate(struct event_context *ev, const char *reason)
{
}
static const struct model_ops single_ops = {
.name = "single",
.model_init = single_model_init,
+ .new_task = single_new_task,
.accept_connection = single_accept_connection,
- .terminate_connection = single_terminate_connection,
+ .terminate = single_terminate,
};
/*
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index ee73cfadcf..b7e9076e5d 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -104,11 +104,60 @@ static void standard_accept_connection(struct event_context *ev,
exit(0);
}
+/*
+ called to create a new server task
+*/
+static void standard_new_task(struct event_context *ev,
+ void (*new_task)(struct event_context *, uint32_t , void *),
+ void *private)
+{
+ pid_t pid;
+ struct event_context *ev2;
+
+ pid = fork();
+
+ if (pid != 0) {
+ /* parent or error code ... go back to the event loop */
+ return;
+ }
+
+ /* This is now the child code. We need a completely new event_context to work with */
+ ev2 = event_context_init(NULL);
+
+ /* the service has given us a private pointer that
+ encapsulates the context it needs for this new connection -
+ everything else will be freed */
+ talloc_steal(ev2, private);
+
+ /* this will free all the listening sockets and all state that
+ is not associated with this new connection */
+ talloc_free(ev);
+
+ /* 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();
+
+ /* setup this new connection */
+ new_task(ev2, getpid(), private);
+
+ /* we can't return to the top level here, as that event context is gone,
+ so we now process events in the new event context until there are no
+ more to process */
+ event_loop_wait(ev2);
+
+ talloc_free(ev2);
+ exit(0);
+}
+
-/* called when a connection goes down */
-static void standard_terminate_connection(struct event_context *ev, const char *reason)
+/* called when a task goes down */
+static void standard_terminate(struct event_context *ev, const char *reason)
{
- DEBUG(2,("standard_terminate_connection: reason[%s]\n",reason));
+ DEBUG(2,("standard_terminate: reason[%s]\n",reason));
/* this init_iconv() has the effect of freeing the iconv context memory,
which makes leak checking easier */
@@ -128,7 +177,8 @@ static const struct model_ops standard_ops = {
.name = "standard",
.model_init = standard_model_init,
.accept_connection = standard_accept_connection,
- .terminate_connection = standard_terminate_connection,
+ .new_task = standard_new_task,
+ .terminate = standard_terminate,
};
/*
diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c
index 6b62ca413e..223fb02085 100644
--- a/source4/smbd/process_thread.c
+++ b/source4/smbd/process_thread.c
@@ -105,10 +105,70 @@ static void thread_accept_connection(struct event_context *ev,
}
}
-/* called when a SMB connection goes down */
-static void thread_terminate_connection(struct event_context *event_ctx, const char *reason)
+
+struct new_task_state {
+ struct event_context *ev;
+ void (*new_task)(struct event_context *, uint32_t , void *);
+ void *private;
+};
+
+static void *thread_task_fn(void *thread_parm)
+{
+ struct new_task_state *new_task = talloc_get_type(thread_parm, struct new_task_state);
+
+ new_task->new_task(new_task->ev, pthread_self(), new_task->private);
+
+ /* run this connection from here */
+ event_loop_wait(new_task->ev);
+
+ talloc_free(new_task);
+
+ return NULL;
+}
+
+/*
+ called when a new task is needed
+*/
+static void thread_new_task(struct event_context *ev,
+ void (*new_task)(struct event_context *, uint32_t , void *),
+ void *private)
+{
+ int rc;
+ pthread_t thread_id;
+ pthread_attr_t thread_attr;
+ struct new_task_state *state;
+ struct event_context *ev2;
+
+ ev2 = event_context_init(ev);
+ if (ev2 == NULL) return;
+
+ state = talloc(ev2, struct new_task_state);
+ if (state == NULL) {
+ talloc_free(ev2);
+ return;
+ }
+
+ state->new_task = new_task;
+ state->private = private;
+ state->ev = ev2;
+
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+ rc = pthread_create(&thread_id, &thread_attr, thread_task_fn, state);
+ pthread_attr_destroy(&thread_attr);
+ if (rc == 0) {
+ DEBUG(4,("thread_new_task: created thread_id=%lu\n",
+ (unsigned long int)thread_id));
+ } else {
+ DEBUG(0,("thread_new_task: thread create failed rc=%d\n", rc));
+ talloc_free(ev2);
+ }
+}
+
+/* called when a task goes down */
+static void thread_terminate(struct event_context *event_ctx, const char *reason)
{
- DEBUG(10,("thread_terminate_connection: reason[%s]\n",reason));
+ DEBUG(10,("thread_terminate: reason[%s]\n",reason));
talloc_free(event_ctx);
@@ -442,7 +502,8 @@ static const struct model_ops thread_ops = {
.name = "thread",
.model_init = thread_model_init,
.accept_connection = thread_accept_connection,
- .terminate_connection = thread_terminate_connection,
+ .new_task = thread_new_task,
+ .terminate = thread_terminate,
};
/*
diff --git a/source4/smbd/service_stream.c b/source4/smbd/service_stream.c
index 72a6703995..0d29c9fcb8 100644
--- a/source4/smbd/service_stream.c
+++ b/source4/smbd/service_stream.c
@@ -1,7 +1,7 @@
/*
Unix SMB/CIFS implementation.
- hepler functions for stream based servers
+ helper functions for stream based servers
Copyright (C) Andrew Tridgell 2003-2005
Copyright (C) Stefan (metze) Metzmacher 2004
@@ -54,7 +54,7 @@ void stream_terminate_connection(struct stream_connection *srv_conn, const char
struct event_ctx *event_ctx = srv_conn->event.ctx;
const struct model_ops *model_ops = srv_conn->model_ops;
talloc_free(srv_conn);
- model_ops->terminate_connection(event_ctx, reason);
+ model_ops->terminate(event_ctx, reason);
}
/*
diff --git a/source4/smbd/service_task.c b/source4/smbd/service_task.c
new file mode 100644
index 0000000000..ea09edf3f4
--- /dev/null
+++ b/source4/smbd/service_task.c
@@ -0,0 +1,90 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ helper functions for task based servers (nbtd, winbind etc)
+
+ Copyright (C) Andrew Tridgell 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
+ 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"
+#include "process_model.h"
+#include "events.h"
+#include "smbd/service_task.h"
+
+/*
+ terminate a task service
+*/
+void task_terminate(struct task_server *task, const char *reason)
+{
+ struct event_ctx *event_ctx = task->event_ctx;
+ const struct model_ops *model_ops = task->model_ops;
+ talloc_free(task);
+ model_ops->terminate(event_ctx, reason);
+}
+
+/* used for the callback from the process model code */
+struct task_state {
+ void (*task_init)(struct task_server *);
+ const struct model_ops *model_ops;
+};
+
+
+/*
+ called by the process model code when the new task starts up. This then calls
+ the server specific startup code
+*/
+static void task_server_callback(struct event_context *event_ctx, uint32_t server_id, void *private)
+{
+ struct task_state *state = talloc_get_type(private, struct task_state);
+ struct task_server *task;
+
+ task = talloc(event_ctx, struct task_server);
+ if (task == NULL) return;
+
+ task->event_ctx = event_ctx;
+ task->model_ops = state->model_ops;
+ task->server_id = server_id;
+
+ task->msg_ctx = messaging_init(task, task->server_id, task->event_ctx);
+ if (!task->msg_ctx) {
+ task_terminate(task, "messaging_init() failed");
+ return;
+ }
+
+ state->task_init(task);
+}
+
+/*
+ startup a task based server
+*/
+NTSTATUS task_server_startup(struct event_context *event_ctx,
+ const struct model_ops *model_ops,
+ void (*task_init)(struct task_server *))
+{
+ struct task_state *state;
+
+ state = talloc(event_ctx, struct task_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+
+ state->task_init = task_init;
+ state->model_ops = model_ops;
+
+ model_ops->new_task(event_ctx, task_server_callback, state);
+
+ return NT_STATUS_OK;
+}
+
diff --git a/source4/smbd/service_task.h b/source4/smbd/service_task.h
new file mode 100644
index 0000000000..e8d90d7631
--- /dev/null
+++ b/source4/smbd/service_task.h
@@ -0,0 +1,30 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ structures for task based servers
+
+ Copyright (C) Andrew Tridgell 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
+ 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.
+*/
+
+
+struct task_server {
+ struct event_context *event_ctx;
+ const struct model_ops *model_ops;
+ struct messaging_context *msg_ctx;
+ uint32_t server_id;
+};
+