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