summaryrefslogtreecommitdiff
path: root/source4/smbd/service.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2005-01-30 00:54:57 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:09:22 -0500
commit55d4d36993293fee914a009f1d8f05810e347f2b (patch)
tree587a9bafd1c8df901aad8766acb0fe9ef4c3d8c0 /source4/smbd/service.c
parent5540449f1cd9d9a6efab59f2bf47be4e1487ffc2 (diff)
downloadsamba-55d4d36993293fee914a009f1d8f05810e347f2b.tar.gz
samba-55d4d36993293fee914a009f1d8f05810e347f2b.tar.bz2
samba-55d4d36993293fee914a009f1d8f05810e347f2b.zip
r5102: This is a major simplification of the logic for controlling top level
servers in smbd. The old code still contained a fairly bit of legacy from the time when smbd was only handling SMB connection. The new code gets rid of all of the smb_server specific code in smbd/, and creates a much simpler infrastructures for new server code. Major changes include: - simplified the process model code a lot. - got rid of the top level server and service structures completely. The top level context is now the event_context. This got rid of service.h and server.h completely (they were the most confusing parts of the old code) - added service_stream.[ch] for the helper functions that are specific to stream type services (services that handle streams, and use a logically separate process per connection) - got rid of the builtin idle_handler code in the service logic, as none of the servers were using it, and it can easily be handled by a server in future by adding its own timed_event to the event context. - fixed some major memory leaks in the rpc server code. - added registration of servers, rather than hard coding our list of possible servers. This allows for servers as modules in the future. - temporarily disabled the winbind code until I add the helper functions for that type of server - added error checking on service startup. If a configured server fails to startup then smbd doesn't startup. - cleaned up the command line handling in smbd, removing unused options (This used to be commit cf6a46c3cbde7b1eb1b86bd3882b953a2de3a42e)
Diffstat (limited to 'source4/smbd/service.c')
-rw-r--r--source4/smbd/service.c394
1 files changed, 47 insertions, 347 deletions
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index 2d532b638d..ab377dc29b 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -3,7 +3,7 @@
SERVER SERVICE code
- Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Tridgell 2003-2005
Copyright (C) Stefan (metze) Metzmacher 2004
This program is free software; you can redistribute it and/or modify
@@ -22,377 +22,77 @@
*/
#include "includes.h"
-#include "events.h"
-#include "system/dir.h"
#include "dlinklist.h"
#include "process_model.h"
-struct server_context *server_service_startup(const char *model, const char **server_services)
-{
- int i;
- struct server_context *server;
-
- if (!server_services) {
- DEBUG(0,("server_service_startup: no endpoint servers configured\n"));
- return NULL;
- }
-
- server = talloc_zero(NULL, struct server_context);
- if (!server) {
- return NULL;
- }
-
- server->model.ops = process_model_startup(server, model);
- if (!server->model.ops) {
- DEBUG(0,("process_model_startup('%s') failed\n", model));
- return NULL;
- }
-
- server->event.ctx = event_context_init(server);
- if (!server->event.ctx) {
- DEBUG(0,("event_context_init() failed\n"));
- return NULL;
- }
-
- for (i=0;server_services[i];i++) {
- 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;
- }
-
- service = talloc_zero(server, struct server_service);
- if (!service) {
- return NULL;
- }
-
- service->service.ops = service_ops;
- service->server = server;
-
- /* TODO: service_init() should return a result */
- service->service.ops->service_init(service);
-
- DLIST_ADD(server->service_list, service);
- }
-
- 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_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_stream_socket *stream_socket;
- struct socket_context *sock;
- struct fd_event fde;
- int i;
-
- 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;
- }
-
- /* ready to listen */
- 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(sock);
- return 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(sock);
- return NULL;
- }
-
- /* TODO: set socket ACL's here when they're implemented */
-
- if (*port == 0) {
- for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) {
- status = socket_listen(sock, sock_addr, i, SERVER_LISTEN_BACKLOG, 0);
- if (NT_STATUS_IS_OK(status)) {
- *port = i;
- break;
- }
- }
- } else {
- 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(sock);
- return NULL;
- }
-
- stream_socket = talloc_zero(service, struct server_stream_socket);
- if (!stream_socket) {
- DEBUG(0,("talloc(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(sock);
- fde.flags = EVENT_FD_READ;
- 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, stream_socket);
- if (!stream_socket->event.fde) {
- socket_destroy(sock);
- return NULL;
- }
-
- talloc_steal(stream_socket, 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_connection_destructor(void *ptr)
-{
- struct server_connection *conn = ptr;
-
- 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");
- }
-
- return 0;
-}
-
-struct server_connection *server_setup_connection(struct event_context *ev,
- struct server_stream_socket *stream_socket,
- struct socket_context *sock,
- struct timeval t,
- servid_t server_id)
-{
- struct fd_event fde;
- struct timed_event idle;
- struct server_connection *srv_conn;
-
- srv_conn = talloc(stream_socket, struct server_connection);
- if (!srv_conn) {
- DEBUG(0,("talloc(mem_ctx, struct server_connection) failed\n"));
- return NULL;
- }
-
- ZERO_STRUCTP(srv_conn);
-
- fde.private = srv_conn;
- fde.fd = socket_get_fd(sock);
- fde.flags = EVENT_FD_READ;
- fde.handler = server_io_handler;
-
- idle.private = srv_conn;
- idle.next_event = timeval_add(&t, SERVER_DEFAULT_IDLE_TIME, 0);
- idle.handler = server_idle_handler;
-
- srv_conn->event.ctx = ev;
- srv_conn->event.fde = &fde;
- srv_conn->event.idle = &idle;
- srv_conn->event.idle_time = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0);
-
- srv_conn->stream_socket = stream_socket;
- srv_conn->socket = sock;
- srv_conn->connection.id = server_id;
-
- /* create a server context and add it to out event
- handling */
- 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);
- srv_conn->event.idle = event_add_timed(ev, &idle, srv_conn);
-
- 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");
- return NULL;
- }
-
- /* setup to receive internal messages on this connection */
- 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;
-}
+ a linked list of registered servers
+*/
+static struct registered_server {
+ struct registered_server *next, *prev;
+ const char *service_name;
+ NTSTATUS (*service_init)(struct event_context *, const struct model_ops *);
+} *registered_servers;
/*
- close the socket and shutdown a server_context
+ register a server service.
*/
-void server_terminate_connection(struct server_connection *srv_conn, const char *reason)
-{
- DEBUG(2,("server_terminate_connection\n"));
- 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)
+NTSTATUS register_server_service(const char *name,
+ NTSTATUS (*service_init)(struct event_context *, const struct model_ops *))
{
- struct server_stream_socket *stream_socket = talloc_get_type(fde->private,
- struct server_stream_socket);
-
- stream_socket->service->server->model.ops->accept_connection(ev, fde, t, flags);
+ struct registered_server *srv;
+ srv = talloc(talloc_autofree_context(), struct registered_server);
+ NT_STATUS_HAVE_NO_MEMORY(srv);
+ srv->service_name = name;
+ srv->service_init = service_init;
+ DLIST_ADD_END(registered_servers, srv, struct registered_server *);
+ return NT_STATUS_OK;
}
-void server_io_handler(struct event_context *ev, struct fd_event *fde,
- struct timeval t, uint16_t flags)
-{
- struct server_connection *conn = talloc_get_type(fde->private,
- struct server_connection);
-
- conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
-
- if (flags & EVENT_FD_WRITE) {
- conn->stream_socket->stream.ops->send_handler(conn, t, flags);
- return;
- }
-
- if (flags & EVENT_FD_READ) {
- conn->stream_socket->stream.ops->recv_handler(conn, t, flags);
- }
-
-}
-
-void server_idle_handler(struct event_context *ev, struct timed_event *idle,
- struct timeval t)
-{
- struct server_connection *conn = talloc_get_type(idle->private,
- struct server_connection);
-
- /* Not all services provide an idle handler */
- 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
+ initialise a server service
*/
-const struct server_service_ops *server_service_byname(const char *name)
+static NTSTATUS server_service_init(const char *name,
+ struct event_context *event_ctx,
+ const struct model_ops *model_ops)
{
- if (strcmp("smb",name)==0) {
- return smbsrv_get_ops();
- }
- if (strcmp("rpc",name)==0) {
- return dcesrv_get_ops();
- }
- if (strcmp("ldap",name)==0) {
- return ldapsrv_get_ops();
- }
- if (strcmp("winbind",name)==0) {
- return winbind_get_ops();
- }
- if (strcmp("winbind_task",name)==0) {
- return winbind_task_get_ops();
+ struct registered_server *srv;
+ for (srv=registered_servers; srv; srv=srv->next) {
+ if (strcasecmp(name, srv->service_name) == 0) {
+ return srv->service_init(event_ctx, model_ops);
+ }
}
- return NULL;
+ return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
-NTSTATUS register_server_service_ops(const void *_ops)
-{
- return NT_STATUS_NOT_IMPLEMENTED;
-}
/*
- 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
- range locking system. So instead of putting the burden on tdb to
- cleanup tmp files, this function deletes them.
+ startup all of our server services
*/
-void service_cleanup_tmp_files(void)
+NTSTATUS server_service_startup(struct event_context *event_ctx,
+ const char *model, const char **server_services)
{
- char *path;
- DIR *dir;
- struct dirent *de;
- TALLOC_CTX *mem_ctx = talloc_init("service_cleanup_tmp_files");
+ int i;
+ const struct model_ops *model_ops;
- path = smbd_tmp_path(mem_ctx, NULL);
+ if (!server_services) {
+ DEBUG(0,("server_service_startup: no endpoint servers configured\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
- dir = opendir(path);
- if (!dir) {
- talloc_free(mem_ctx);
- return;
+ model_ops = process_model_startup(event_ctx, model);
+ if (!model_ops) {
+ DEBUG(0,("process_model_startup('%s') failed\n", model));
+ return NT_STATUS_INTERNAL_ERROR;
}
- for (de=readdir(dir);de;de=readdir(dir)) {
- char *fname = talloc_asprintf(mem_ctx, "%s/%s", path, de->d_name);
- int ret = unlink(fname);
- if (ret == -1 &&
- errno != ENOENT &&
- errno != EISDIR &&
- errno != EISDIR) {
- DEBUG(0,("Unabled to delete '%s' - %s\n",
- fname, strerror(errno)));
- smb_panic("unable to cleanup tmp files");
- }
- talloc_free(fname);
+ for (i=0;server_services[i];i++) {
+ NTSTATUS status;
+
+ status = server_service_init(server_services[i], event_ctx, model_ops);
+ NT_STATUS_NOT_OK_RETURN(status);
}
- closedir(dir);
- talloc_free(mem_ctx);
+ return NT_STATUS_OK;
}