summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/lib/socket/socket.c22
-rw-r--r--source4/smbd/process_standard.c9
-rw-r--r--source4/smbd/service.c21
3 files changed, 50 insertions, 2 deletions
diff --git a/source4/lib/socket/socket.c b/source4/lib/socket/socket.c
index dbbae5ea7e..892695f6eb 100644
--- a/source4/lib/socket/socket.c
+++ b/source4/lib/socket/socket.c
@@ -260,6 +260,28 @@ int socket_get_fd(struct socket_context *sock)
return sock->ops->get_fd(sock);
}
+/*
+ call dup() on a socket, and close the old fd. This is used to change
+ the fd to the lowest available number, to make select() more
+ efficient (select speed depends on the maxiumum fd number passed to
+ it)
+*/
+NTSTATUS socket_dup(struct socket_context *sock)
+{
+ int fd;
+ if (sock->fd == -1) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+ fd = dup(sock->fd);
+ if (fd == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ close(sock->fd);
+ sock->fd = fd;
+ return NT_STATUS_OK;
+
+}
+
const struct socket_ops *socket_getops_byname(const char *name, enum socket_type type)
{
if (strcmp("ip", name) == 0 ||
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index 106be77925..9b5547ce54 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -34,7 +34,8 @@ static void standard_model_startup(void)
/*
called when a listening socket becomes readable
*/
-static void standard_accept_connection(struct event_context *ev, struct fd_event *srv_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)
{
NTSTATUS status;
struct socket_context *sock;
@@ -63,7 +64,11 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event
/* Child code ... */
/* close all the listening sockets */
- event_remove_fd_all_handler(ev, standard_accept_connection);
+ service_close_listening_sockets(server_socket->service->srv_ctx);
+
+ /* we don't care if the dup fails, as its only a select()
+ speed optimisation */
+ socket_dup(sock);
/* tdb needs special fork handling */
if (tdb_reopen_all() == -1) {
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index ac46992261..ca5f5e7531 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -77,6 +77,8 @@ struct server_context *server_service_startup(const char *model)
/* TODO: service_init() should return a result */
service->ops->service_init(service, model_ops);
+
+ DLIST_ADD(srv_ctx->service_list, service);
}
return srv_ctx;
@@ -328,3 +330,22 @@ BOOL server_service_init(void)
DEBUG(3,("SERVER SERVICE subsystem version %d initialised\n", SERVER_SERVICE_VERSION));
return True;
}
+
+
+/*
+ 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;
+ }
+ }
+}