summaryrefslogtreecommitdiff
path: root/source4/smbd/service.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/smbd/service.c')
-rw-r--r--source4/smbd/service.c221
1 files changed, 117 insertions, 104 deletions
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index 586c05c2c6..e0ec3cf07e 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -27,38 +27,33 @@
#include "dlinklist.h"
#include "process_model.h"
-struct server_context *server_service_startup(const char *model)
+struct server_context *server_service_startup(const char *model, const char **server_services)
{
int i;
- const char **server_services = lp_server_services();
- struct server_context *srv_ctx;
- const struct model_ops *model_ops;
+ struct server_context *server;
if (!server_services) {
- DEBUG(0,("process_model_startup: no endpoint servers configured\n"));
+ DEBUG(0,("server_service_startup: no endpoint servers configured\n"));
return NULL;
}
- model_ops = process_model_startup(model);
- if (!model_ops) {
- DEBUG(0,("process_model_startup('%s') failed\n", model));
- return NULL;
- }
-
- srv_ctx = talloc_p(NULL, struct server_context);
- if (!srv_ctx) {
+ server = talloc_zero(NULL, struct server_context);
+ if (!server) {
return NULL;
}
- ZERO_STRUCTP(srv_ctx);
+ server->model.ops = process_model_startup(server, model);
+ if (!server->model.ops) {
+ DEBUG(0,("process_model_startup('%s') failed\n", model));
+ return NULL;
+ }
- srv_ctx->events = event_context_init(srv_ctx);
- if (!srv_ctx->events) {
+ server->event.ctx = event_context_init(server);
+ if (!server->event.ctx) {
DEBUG(0,("event_context_init() failed\n"));
- return NULL;
+ return NULL;
}
-
for (i=0;server_services[i];i++) {
const struct server_service_ops *service_ops;
struct server_service *service;
@@ -69,63 +64,64 @@ struct server_context *server_service_startup(const char *model)
return NULL;
}
- service = talloc_p(srv_ctx, struct server_service);
+ service = talloc_zero(server, struct server_service);
if (!service) {
return NULL;
}
- ZERO_STRUCTP(service);
- service->ops = service_ops;
- service->model_ops = model_ops;
- service->srv_ctx = srv_ctx;
-
+ service->service.ops = service_ops;
+ service->server = server;
+
/* TODO: service_init() should return a result */
- service->ops->service_init(service, model_ops);
+ service->service.ops->service_init(service);
- DLIST_ADD(srv_ctx->service_list, service);
+ DLIST_ADD(server->service_list, service);
}
- return srv_ctx;
+ return server;
+}
+
+void server_service_shutdown(struct server_context *server, const char *reason)
+{
+ server->model.ops->model_exit(server, reason);
}
/*
setup a listen stream socket
if you pass *port == 0, then a port > 1024 is used
*/
-struct server_socket *service_setup_socket(struct server_service *service,
- const struct model_ops *model_ops,
- const char *family,
- const char *sock_addr,
- uint16_t *port)
+struct server_stream_socket *service_setup_stream_socket(struct server_service *service,
+ const struct server_stream_ops *stream_ops,
+ const char *family,
+ const char *sock_addr,
+ uint16_t *port)
{
NTSTATUS status;
- struct server_socket *srv_sock;
- struct socket_context *socket_ctx;
+ struct server_stream_socket *stream_socket;
+ struct socket_context *sock;
struct fd_event fde;
int i;
- status = socket_create(family, SOCKET_TYPE_STREAM, &socket_ctx, 0);
+ status = socket_create(family, SOCKET_TYPE_STREAM, &sock, 0);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to open socket on %s:%u - %s\n",
sock_addr, *port, nt_errstr(status)));
return NULL;
}
- talloc_steal(service, socket_ctx);
-
/* ready to listen */
- status = socket_set_option(socket_ctx, "SO_KEEPALIVE SO_REUSEADDR=1", NULL);
+ status = socket_set_option(sock, "SO_KEEPALIVE SO_REUSEADDR=1", NULL);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("socket_set_option(socket_ctx, SO_KEEPALIVE, NULL): %s\n",
nt_errstr(status)));
- socket_destroy(socket_ctx);
+ socket_destroy(sock);
return NULL;
}
- status = socket_set_option(socket_ctx, lp_socket_options(), NULL);
+ status = socket_set_option(sock, lp_socket_options(), NULL);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("socket_set_option(socket_ctx, lp_socket_options(), NULL): %s\n",
nt_errstr(status)));
- socket_destroy(socket_ctx);
+ socket_destroy(sock);
return NULL;
}
@@ -133,64 +129,70 @@ struct server_socket *service_setup_socket(struct server_service *service,
if (*port == 0) {
for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
- status = socket_listen(socket_ctx, sock_addr, i, SERVER_LISTEN_BACKLOG, 0);
+ status = socket_listen(sock, sock_addr, i, SERVER_LISTEN_BACKLOG, 0);
if (NT_STATUS_IS_OK(status)) {
*port = i;
break;
}
}
} else {
- status = socket_listen(socket_ctx, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0);
+ status = socket_listen(sock, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0);
}
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to listen on %s:%u - %s\n",
sock_addr, *port, nt_errstr(status)));
- socket_destroy(socket_ctx);
+ socket_destroy(sock);
return NULL;
}
- srv_sock = talloc_p(service, struct server_socket);
- if (!srv_sock) {
- DEBUG(0,("talloc_p(mem_ctx, struct server_socket) failed\n"));
- socket_destroy(socket_ctx);
+ stream_socket = talloc_zero(service, struct server_stream_socket);
+ if (!stream_socket) {
+ DEBUG(0,("talloc_p(mem_ctx, struct server_stream_socket) failed\n"));
+ socket_destroy(sock);
return NULL;
}
/* we are only interested in read events on the listen socket */
- fde.fd = socket_get_fd(socket_ctx);
+ fde.fd = socket_get_fd(sock);
fde.flags = EVENT_FD_READ;
- fde.private = srv_sock;
- fde.handler = model_ops->accept_connection;
-
- ZERO_STRUCTP(srv_sock);
- srv_sock->service = service;
- srv_sock->socket = socket_ctx;
- srv_sock->event.ctx = service->srv_ctx->events;
- srv_sock->event.fde = event_add_fd(srv_sock->event.ctx, &fde);
- if (!srv_sock->event.fde) {
- DEBUG(0,("event_add_fd(srv_sock->event.ctx, &fde) failed\n"));
- socket_destroy(socket_ctx);
+ fde.private = stream_socket;
+ fde.handler = server_accept_handler;
+
+ stream_socket->stream.ops = stream_ops;
+ stream_socket->service = service;
+ stream_socket->socket = sock;
+ stream_socket->event.ctx = service->server->event.ctx;
+ stream_socket->event.fde = event_add_fd(stream_socket->event.ctx, &fde);
+ if (!stream_socket->event.fde) {
+ DEBUG(0,("event_add_fd(stream_socket->event.ctx, &fde) failed\n"));
+ socket_destroy(sock);
return NULL;
}
- DLIST_ADD(service->socket_list, srv_sock);
+ talloc_steal(stream_socket, sock);
- return srv_sock;
+ if (stream_socket->stream.ops->socket_init) {
+ stream_socket->stream.ops->socket_init(stream_socket);
+ }
+
+ return stream_socket;
}
/*
destructor that handles necessary event context changes
*/
-static int server_destructor(void *ptr)
+static int server_connection_destructor(void *ptr)
{
struct server_connection *conn = ptr;
- if (conn->service) {
- conn->service->ops->close_connection(conn, "shutdown");
- }
-
- socket_destroy(conn->socket);
+ if (conn->stream_socket &&
+ conn->stream_socket->stream.ops->close_connection) {
+ /* don't remove this! the stream service needs to free it's data
+ * before we destroy the server_connection
+ */
+ conn->stream_socket->stream.ops->close_connection(conn, "shutdown");
+ }
if (conn->event.fde) {
event_remove_fd(conn->event.ctx, conn->event.fde);
@@ -201,13 +203,11 @@ static int server_destructor(void *ptr)
conn->event.idle = NULL;
}
- DLIST_REMOVE(conn->server_socket->connection_list, conn);
-
return 0;
}
struct server_connection *server_setup_connection(struct event_context *ev,
- struct server_socket *server_socket,
+ struct server_stream_socket *stream_socket,
struct socket_context *sock,
struct timeval t,
servid_t server_id)
@@ -216,7 +216,7 @@ struct server_connection *server_setup_connection(struct event_context *ev,
struct timed_event idle;
struct server_connection *srv_conn;
- srv_conn = talloc_p(server_socket, struct server_connection);
+ srv_conn = talloc_p(stream_socket, struct server_connection);
if (!srv_conn) {
DEBUG(0,("talloc_p(mem_ctx, struct server_connection) failed\n"));
return NULL;
@@ -238,20 +238,19 @@ struct server_connection *server_setup_connection(struct event_context *ev,
srv_conn->event.idle = &idle;
srv_conn->event.idle_time = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0);
- srv_conn->server_socket = server_socket;
- srv_conn->service = server_socket->service;
+ srv_conn->stream_socket = stream_socket;
srv_conn->socket = sock;
- srv_conn->server_id = server_id;
+ srv_conn->connection.id = server_id;
/* create a server context and add it to out event
handling */
- server_socket->service->ops->accept_connection(srv_conn);
+ stream_socket->stream.ops->accept_connection(srv_conn);
/* accpect_connection() of the service may changed idle.next_event */
srv_conn->event.fde = event_add_fd(ev,&fde);
srv_conn->event.idle = event_add_timed(ev,&idle);
- talloc_set_destructor(srv_conn, server_destructor);
+ talloc_set_destructor(srv_conn, server_connection_destructor);
if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) {
server_terminate_connection(srv_conn, "denied by access rules");
@@ -259,7 +258,11 @@ struct server_connection *server_setup_connection(struct event_context *ev,
}
/* setup to receive internal messages on this connection */
- srv_conn->messaging_ctx = messaging_init(srv_conn, srv_conn->server_id, ev);
+ srv_conn->messaging.ctx = messaging_init(srv_conn, srv_conn->connection.id, ev);
+ if (!srv_conn->messaging.ctx) {
+ server_terminate_connection(srv_conn, "messaging_init() failed");
+ return NULL;
+ }
return srv_conn;
}
@@ -270,7 +273,15 @@ struct server_connection *server_setup_connection(struct event_context *ev,
void server_terminate_connection(struct server_connection *srv_conn, const char *reason)
{
DEBUG(2,("server_terminate_connection\n"));
- srv_conn->service->model_ops->terminate_connection(srv_conn, reason);
+ srv_conn->stream_socket->service->server->model.ops->terminate_connection(srv_conn, reason);
+}
+
+void server_accept_handler(struct event_context *ev, struct fd_event *fde,
+ struct timeval t, uint16_t flags)
+{
+ struct server_stream_socket *stream_socket = fde->private;
+
+ stream_socket->service->server->model.ops->accept_connection(ev, fde, t, flags);
}
void server_io_handler(struct event_context *ev, struct fd_event *fde,
@@ -281,12 +292,12 @@ void server_io_handler(struct event_context *ev, struct fd_event *fde,
conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
if (flags & EVENT_FD_WRITE) {
- conn->service->ops->send_handler(conn, t, flags);
+ conn->stream_socket->stream.ops->send_handler(conn, t, flags);
return;
}
if (flags & EVENT_FD_READ) {
- conn->service->ops->recv_handler(conn, t, flags);
+ conn->stream_socket->stream.ops->recv_handler(conn, t, flags);
}
}
@@ -296,13 +307,34 @@ void server_idle_handler(struct event_context *ev, struct timed_event *idle,
{
struct server_connection *conn = idle->private;
- conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
-
/* Not all services provide an idle handler */
- if (conn->service->ops->idle_handler) {
- conn->service->ops->idle_handler(conn, t);
+ if (conn->stream_socket->stream.ops->idle_handler) {
+ conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
+ conn->stream_socket->stream.ops->idle_handler(conn, t);
}
}
+
+void server_terminate_task(struct server_task *task, const char *reason)
+{
+ task->service->server->model.ops->terminate_task(task, reason);
+ return;
+}
+
+void server_run_task(struct server_service *service, const struct server_task_ops *ops)
+{
+ struct server_task *task;
+
+ task = talloc_zero(service, struct server_task);
+ if (!task) {
+ return;
+ }
+ task->service = service;
+ task->task.ops = ops;
+
+ service->server->model.ops->create_task(task);
+ return;
+}
+
/*
return the operations structure for a named backend of the specified type
*/
@@ -326,25 +358,6 @@ NTSTATUS register_server_service_ops(const void *_ops)
}
/*
- close all listening sockets. This is called by process models that fork, to
- ensure that the listen sockets from the parent are closed
-*/
-void service_close_listening_sockets(struct server_context *srv_ctx)
-{
- struct server_service *svc;
- for (svc=srv_ctx->service_list;svc;svc=svc->next) {
- struct server_socket *sock;
- for (sock=svc->socket_list;sock;sock=sock->next) {
- event_remove_fd(sock->event.ctx, sock->event.fde);
- sock->event.fde = NULL;
- socket_destroy(sock->socket);
- sock->socket = NULL;
- }
- }
-}
-
-
-/*
cleanup temporary files. This is the new alternative to
TDB_CLEAR_IF_FIRST. Unfortunately TDB_CLEAR_IF_FIRST is not
efficient on unix systems due to the lack of scaling of the byte