r5104: - added support for task based servers. These are servers that within
authorAndrew Tridgell <tridge@samba.org>
Sun, 30 Jan 2005 02:55:30 +0000 (02:55 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:09:23 +0000 (13:09 -0500)
  themselves are run as a single process, but run as a child of the
  main process when smbd is run in the standard model, and run as part
  of the main process when in the single mode.

- rewrote the winbind template code to use the new task services. Also
  fixed the packet queueing

- got rid of event_context_merge() as it is no longer needed

12 files changed:
source/build/smb_build/main.pm
source/include/structs.h
source/lib/events.c
source/smbd/config.mk
source/smbd/process_model.h
source/smbd/process_single.c
source/smbd/process_standard.c
source/smbd/process_thread.c
source/smbd/service_stream.c
source/smbd/service_task.c [new file with mode: 0644]
source/smbd/service_task.h [new file with mode: 0644]
source/winbind/wb_server.c

index 3911820edb5c48a7cd43caf45976e78823d7402c..af4220ec7ba4774700759b0cb18bf0bde623adcb 100644 (file)
@@ -40,6 +40,7 @@ sub smb_build_main($)
                "smb_server/config.mk",
                "rpc_server/config.mk",
                "ldap_server/config.mk",
+               "winbind/config.mk",
                "libcli/auth/gensec.mk",
                "libcli/auth/config.mk",
                "libcli/ldap/config.mk",
index cf59296f320ec939b5a6a736788e48003a86c65f..2fe069e949e62ebc0b1c7e3ddc4ee1135144a3ef 100644 (file)
@@ -154,5 +154,6 @@ struct nbt_name_status;
 
 struct messaging_context;
 struct stream_connection;
+struct task_server;
 struct model_ops;
 struct stream_server_ops;
index d32a1344e0af8aa6126ad1bc5a1bc4761b00fe09..c09d9b50301af280474f46d327617c6454f1dd78 100644 (file)
@@ -110,32 +110,6 @@ static void calc_maxfd(struct event_context *ev)
        }
 }
 
-/*
-  move the event structures from ev2 into ev, upping the reference
-  count on ev. The event context ev2 is then destroyed.
-
-  this is used by modules that need to call on the events of a lower module
-*/
-struct event_context *event_context_merge(struct event_context *ev, 
-                                         struct event_context *ev2)
-{
-       DLIST_CONCATENATE(ev->fd_events, ev2->fd_events, struct fd_event *);
-       DLIST_CONCATENATE(ev->timed_events, ev2->timed_events, struct timed_event *);
-       DLIST_CONCATENATE(ev->loop_events, ev2->loop_events, struct loop_event *);
-
-       ev2->fd_events = NULL;
-       ev2->timed_events = NULL;
-       ev2->loop_events = NULL;
-
-       talloc_steal(ev->events, ev2->events);
-
-       event_context_destroy(ev2);
-
-       calc_maxfd(ev);
-
-       return ev;
-}
-
 /* to mark the ev->maxfd invalid
  * this means we need to recalculate it
  */
index 07847b7fc8d548a4949cd24b21d01526eb729f55..4d5e929c795da5d624255ef917e593cd9e2d3b91 100644 (file)
@@ -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
index 943538d7b2163c7e95454291ee581583e9f2443d..2e064f42772ed04187c33632816ba9f205028529 100644 (file)
@@ -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 */
index d6217d87125a78e0fd7d91ef62a70e9315ccc5e6..7d43855f6c18915ed664b2eef6e9db489b8e2918 100644 (file)
@@ -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,
 };
 
 /*
index ee73cfadcf176fd084ef2ab6572a3459cc18f08c..b7e9076e5d07ad1136ebb3691fe7388541c50355 100644 (file)
@@ -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,
 };
 
 /*
index 6b62ca413e10957093f6f2c26a36488c81b200e3..223fb020850a7fbf4b6a16be6e3c1d42f69056f7 100644 (file)
@@ -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,
 };
 
 /*
index 72a6703995f19882fc89b0672abf9f0250f640c2..0d29c9fcb877acb0dd0ecb55bdd251482a3d8905 100644 (file)
@@ -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/source/smbd/service_task.c b/source/smbd/service_task.c
new file mode 100644 (file)
index 0000000..ea09edf
--- /dev/null
@@ -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/source/smbd/service_task.h b/source/smbd/service_task.h
new file mode 100644 (file)
index 0000000..e8d90d7
--- /dev/null
@@ -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;
+};
+
index b75cc897a8b1a8224fcd1cc5b44a1b958789e647..fb30b76a0acd58d197ea58c00c7942b2320c98de 100644 (file)
@@ -3,6 +3,7 @@
    Main winbindd server routines
 
    Copyright (C) Stefan Metzmacher     2005
+   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
 */
 
 #include "includes.h"
+#include "dlinklist.h"
 #include "events.h"
-#include "system/time.h"
+#include "smbd/service_task.h"
+#include "smbd/service_stream.h"
 
 #define WINBINDD_DIR "/tmp/.winbindd/"
 #define WINBINDD_ECHO_SOCKET  WINBINDD_DIR"echo"
 #define WINBINDD_ECHO_ADDR WINBINDD_ADDR_PREFIX"1"
 #define WINBINDD_ECHO_PORT 55555
 
-static void winbind_accept(struct server_connection *conn)
-{
-       DEBUG(10,("winbind_accept:\n"));
-}
+/*
+  state of an open winbind connection
+*/
+struct wbserver_connection {
+       DATA_BLOB blob;
+       struct send_queue {
+               struct send_queue *next, *prev;
+               DATA_BLOB blob;
+       } *queue;
+};
 
-static DATA_BLOB tmp_blob;
 
-static void winbind_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
+/*
+  called when we get a new connection
+*/
+static void winbind_accept(struct stream_connection *conn)
 {
+       struct wbserver_connection *wbconn;
 
+       wbconn = talloc_zero(conn, struct wbserver_connection);
+       wbconn->blob = data_blob_talloc(wbconn, NULL, 1024);
+       
+       conn->private = wbconn;
+}
 
+/*
+  receive some data on a winbind connection
+*/
+static void winbind_recv(struct stream_connection *conn, struct timeval t, uint16_t flags)
+{
+       struct wbserver_connection *wbconn = talloc_get_type(conn->private, struct wbserver_connection);
        NTSTATUS status;
        size_t nread;
+       struct send_queue *q;
 
-if (!tmp_blob.data) {
-       tmp_blob = data_blob_talloc(conn, NULL, 1024);
-       if (tmp_blob.data == NULL) {
-               return;
-       }
-}
-       tmp_blob.length = 1024;
-       status = socket_recv(conn->socket, tmp_blob.data, tmp_blob.length, &nread, 0);
+       status = socket_recv(conn->socket, wbconn->blob.data, wbconn->blob.length, &nread, 0);
        if (NT_STATUS_IS_ERR(status)) {
                DEBUG(10,("socket_recv: %s\n",nt_errstr(status)));
-               talloc_free(tmp_blob.data);
-               server_terminate_connection(conn, "socket_recv: failed\n");
+               stream_terminate_connection(conn, "socket_recv: failed\n");
                return;
        }
-       tmp_blob.length = nread;
-#if 0
-DEBUG(0,("winbind_recv:\n"));
-dump_data(0, tmp_blob.data, tmp_blob.length);
-#endif
-       conn->event.fde->flags |= EVENT_FD_WRITE;
-}
-
-static void winbind_send(struct server_connection *conn, struct timeval t, uint16_t flags)
-{
-       NTSTATUS status;
-       size_t sendlen;
-
-       if (tmp_blob.length > 1 && tmp_blob.data[0] == (uint8_t)'q') {
-
-       }
 
-       status = socket_send(conn->socket, &tmp_blob, &sendlen, 0);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(10,("socket_send() %s\n",nt_errstr(status)));
-               server_terminate_connection(conn, "socket_send: failed\n");
+       /* just reflect the data back down the socket */
+       q = talloc(wbconn, struct send_queue);
+       if (q == NULL) {
+               stream_terminate_connection(conn, "winbind_recv: out of memory\n");
                return;
        }
 
-       if (tmp_blob.length > 1 && tmp_blob.data[0] == (uint8_t)'q') {
-               server_terminate_connection(conn, "winbind_send: user quit\n");
+       q->blob = data_blob_talloc(q, wbconn->blob.data, nread);
+       if (q->blob.data == NULL) {
+               stream_terminate_connection(conn, "winbind_recv: out of memory\n");
                return;
        }
-#if 0
-DEBUG(0,("winbind_send:\n"));
-dump_data(0, tmp_blob.data, tmp_blob.length);
-#endif
-       tmp_blob.length -= sendlen;
-
-       if (tmp_blob.length == 0) {
-               conn->event.fde->flags &= ~EVENT_FD_WRITE;
-       }
-}
 
-static void winbind_idle(struct server_connection *conn, struct timeval t)
-{
-       DEBUG(1,("winbind_idle: not implemented!\n"));
-       return;
-}
+       DLIST_ADD_END(wbconn->queue, q, struct send_queue *);
 
-static void winbind_close(struct server_connection *conn, const char *reason)
-{
-       DEBUG(10,("winbind_close: %s\n", reason));
-}
-
-
-
-static int winbind_task_server_contect_destructor(void *ptr)
-{
-       struct server_context *server = ptr;
-
-       server_service_shutdown(server, "exit");
-
-       return 0;       
+       conn->event.fde->flags |= EVENT_FD_WRITE;
 }
 
-static void winbind_server_task_init(struct server_task *task)
+/*
+  called when we can write to a connection
+*/
+static void winbind_send(struct stream_connection *conn, struct timeval t, uint16_t flags)
 {
-       const char *wb_task_service[] = { "winbind_task", NULL };
-       struct server_context *server;
-
-       DEBUG(1,("winbindsrv_task_init\n"));
-       server = server_service_startup("single", wb_task_service);
-       if (!server) {
-               DEBUG(0,("Starting Services (winbind_task) failed.\n"));
-               return;
+       struct wbserver_connection *wbconn = talloc_get_type(conn->private, struct wbserver_connection);
+
+       while (wbconn->queue) {
+               struct send_queue *q = wbconn->queue;
+               NTSTATUS status;
+               size_t sendlen;
+
+               status = socket_send(conn->socket, &q->blob, &sendlen, 0);
+               if (NT_STATUS_IS_ERR(status)) {
+                       DEBUG(10,("socket_send() %s\n",nt_errstr(status)));
+                       stream_terminate_connection(conn, "socket_send: failed\n");
+                       return;
+               }
+               if (!NT_STATUS_IS_OK(status)) {
+                       return;
+               }
+
+               q->blob.length -= sendlen;
+               q->blob.data   += sendlen;
+
+               if (q->blob.length == 0) {
+                       DLIST_REMOVE(wbconn->queue, q);
+                       talloc_free(q);
+               }
        }
 
-       task->task.private_data = talloc_steal(task, server);
-
-       task->event.ctx = event_context_merge(task->event.ctx, server->event.ctx);
-       server->event.ctx = talloc_reference(server, task->event.ctx);
-
-       talloc_set_destructor(server, winbind_task_server_contect_destructor);
-
-       /* wait for events */
-       event_loop_wait(task->event.ctx);
+       conn->event.fde->flags &= ~EVENT_FD_WRITE;
 }
 
-static const struct server_task_ops winbind_srver_task_ops = {
-       .name           = "winbind_server_task",
-       .task_init      = winbind_server_task_init
-};
-
-static const struct server_task_ops *winbind_srver_task_get_ops(void)
-{
-       return &winbind_srver_task_ops;
-}
-
-static const struct server_stream_ops winbind_stream_ops = {
-       .name                   = "winbind",
-       .socket_init            = NULL,
+static const struct stream_server_ops winbind_stream_ops = {
+       .name                   = "smb",
        .accept_connection      = winbind_accept,
        .recv_handler           = winbind_recv,
        .send_handler           = winbind_send,
-       .idle_handler           = winbind_idle,
-       .close_connection       = winbind_close
 };
 
-static const struct server_stream_ops *winbind_get_stream_ops(void)
-{
-       return &winbind_stream_ops;
-}
-
-static void winbind_task_init(struct server_service *service)
+/*
+  startup the winbind task
+*/
+static void winbind_task_init(struct task_server *task)
 {
-       struct server_stream_socket *stream_socket;
        uint16_t port = 1;
+       const struct model_ops *model_ops;
+       NTSTATUS status;
 
-       DEBUG(1,("winbind_task_init\n"));
+       /* within the winbind task we want to be a single process, so
+          ask for the single process model ops and pass these to the
+          stream_setup_socket() call. */
+       model_ops = process_model_byname("single");
+       if (!model_ops) {
+               task_terminate(task, "Can't find 'single' process model_ops");
+               return;
+       }
 
        /* Make sure the directory for NCALRPC exists */
        if (!directory_exist(WINBINDD_DIR, NULL)) {
                mkdir(WINBINDD_DIR, 0755);
        }
 
-       stream_socket = service_setup_stream_socket(service, winbind_get_stream_ops(), "unix", WINBINDD_ECHO_SOCKET, &port);
-       if (!stream_socket) {
-               DEBUG(0,("service_setup_stream_socket(path=%s) failed\n",WINBINDD_ECHO_SOCKET));
+       status = stream_setup_socket(task->event_ctx, model_ops, &winbind_stream_ops, 
+                                    "unix", WINBINDD_ECHO_SOCKET, &port, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
+                        WINBINDD_ECHO_SOCKET, nt_errstr(status)));
+               task_terminate(task, "winbind Failed to find to ECHO unix socket");
                return;
        }
 
        port = WINBINDD_ECHO_PORT;
-       stream_socket = service_setup_stream_socket(service, winbind_get_stream_ops(), "ipv4", WINBINDD_ECHO_ADDR, &port);
-       if (!stream_socket) {
-               DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed\n",WINBINDD_ECHO_ADDR, port));
+
+       status = stream_setup_socket(task->event_ctx, model_ops, &winbind_stream_ops,
+                                    "ipv4", WINBINDD_ECHO_ADDR, &port, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
+                        WINBINDD_ECHO_ADDR, port, nt_errstr(status)));
+               task_terminate(task, "winbind Failed to find to ECHO tcp socket");
                return;
        }
-
-       return;
 }
 
-static const struct server_service_ops winbind_task_ops = {
-       .name                   = "winbind_task",
-       .service_init           = winbind_task_init,
-};
-
-const struct server_service_ops *winbind_task_get_ops(void)
+/*
+  initialise the winbind server
+ */
+static NTSTATUS winbind_init(struct event_context *event_ctx, const struct model_ops *model_ops)
 {
-       return &winbind_task_ops;
-}
-
-static void winbind_init(struct server_service *service)
-{
-       DEBUG(1,("winbind_init\n"));
-
-       server_run_task(service, winbind_srver_task_get_ops());
-
-       return;
-}
-
-static const struct server_service_ops winbind_ops = {
-       .name                   = "winbind",
-       .service_init           = winbind_init,
-};
-
-const struct server_service_ops *winbind_get_ops(void)
-{
-       return &winbind_ops;
+       return task_server_startup(event_ctx, model_ops, winbind_task_init);
 }
 
+/*
+  register ourselves as a available server
+*/
 NTSTATUS server_service_winbind_init(void)
 {
-       return NT_STATUS_OK;    
+       return register_server_service("winbind", winbind_init);
 }