build: avoid util.h as a public header name due to conflict with MacOS
[ira/wip.git] / source3 / lib / server_prefork.c
index 71441c3303bbea0eaef1577ec2e33a675718d1b2..89600aaa2ac5ff47e1f070d6a285967263247193 100644 (file)
 */
 
 #include "includes.h"
+#include "serverid.h"
+#include "messages.h"
 #include "system/time.h"
 #include "system/shmem.h"
 #include "system/filesys.h"
 #include "server_prefork.h"
-#include "../lib/util/util.h"
+#include "../lib/util/samba_util.h"
 #include "../lib/util/tevent_unix.h"
 
 struct prefork_pool {
@@ -81,6 +83,8 @@ bool prefork_create_pool(TALLOC_CTX *mem_ctx,
        }
        for (i = 0; i < listen_fd_size; i++) {
                pfp->listen_fds[i] = listen_fds[i];
+               /* force sockets in non-blocking mode */
+               set_blocking(listen_fds[i], false);
        }
        pfp->main_fn = main_fn;
        pfp->private_data = private_data;
@@ -238,9 +242,11 @@ static int prefork_sort_oldest(const void *ap, const void *bp)
        return -1;
 }
 
-int prefork_retire_children(struct prefork_pool *pfp,
+int prefork_retire_children(struct messaging_context *msg_ctx,
+                           struct prefork_pool *pfp,
                            int num_children, time_t age_limit)
 {
+       const DATA_BLOB ping = data_blob_null;
        time_t now = time(NULL);
        struct prefork_oldest *oldest;
        int i, j;
@@ -265,13 +271,15 @@ int prefork_retire_children(struct prefork_pool *pfp,
                prefork_sort_oldest);
 
        for (i = 0, j = 0; i < pfp->pool_size && j < num_children; i++) {
-               if ((pfp->pool[i].status == PF_WORKER_ALIVE ||
-                    pfp->pool[i].status == PF_WORKER_ACCEPTING) &&
-                   pfp->pool[i].started <= age_limit) {
+               if (((pfp->pool[i].status == PF_WORKER_ALIVE) &&
+                    (pfp->pool[i].num_clients < 1)) &&
+                   (pfp->pool[i].started <= age_limit)) {
                        /* tell the child it's time to give up */
                        DEBUG(5, ("Retiring pid %d!\n", pfp->pool[i].pid));
                        pfp->pool[i].cmds = PF_SRV_MSG_EXIT;
-                       kill(pfp->pool[i].pid, SIGHUP);
+                       messaging_send(msg_ctx,
+                                       pid_to_procid(pfp->pool[i].pid),
+                                       MSG_PREFORK_PARENT_EVENT, &ping);
                        j++;
                }
        }
@@ -279,7 +287,7 @@ int prefork_retire_children(struct prefork_pool *pfp,
        return j;
 }
 
-int prefork_count_active_children(struct prefork_pool *pfp, int *total)
+int prefork_count_children(struct prefork_pool *pfp, int *active)
 {
        int i, a, t;
 
@@ -292,15 +300,18 @@ int prefork_count_active_children(struct prefork_pool *pfp, int *total)
 
                t++;
 
-               if (pfp->pool[i].num_clients <= 0) {
+               if ((pfp->pool[i].status == PF_WORKER_EXITING) ||
+                   (pfp->pool[i].num_clients <= 0)) {
                        continue;
                }
 
                a++;
        }
 
-       *total = t;
-       return a;
+       if (active) {
+               *active = a;
+       }
+       return t;
 }
 
 static void prefork_cleanup_loop(struct prefork_pool *pfp)
@@ -420,6 +431,23 @@ void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num)
        }
 }
 
+void prefork_warn_active_children(struct messaging_context *msg_ctx,
+                                 struct prefork_pool *pfp)
+{
+       const DATA_BLOB ping = data_blob_null;
+       int i;
+
+       for (i = 0; i < pfp->pool_size; i++) {
+               if (pfp->pool[i].status == PF_WORKER_NONE) {
+                       continue;
+               }
+
+               messaging_send(msg_ctx,
+                               pid_to_procid(pfp->pool[i].pid),
+                               MSG_PREFORK_PARENT_EVENT, &ping);
+       }
+}
+
 static void prefork_sigchld_handler(struct tevent_context *ev_ctx,
                                    struct tevent_signal *se,
                                    int signum, int count,
@@ -550,7 +578,8 @@ static void prefork_listen_accept_handler(struct tevent_context *ev,
        struct pf_listen_ctx *ctx;
        struct sockaddr_storage addr;
        socklen_t addrlen;
-       int err = 0;
+       int soerr = 0;
+       socklen_t solen = sizeof(soerr);
        int sd = -1;
        int ret;
 
@@ -558,7 +587,8 @@ static void prefork_listen_accept_handler(struct tevent_context *ev,
        req = ctx->req;
        state = tevent_req_data(ctx->req, struct pf_listen_state);
 
-       if (state->pf->cmds == PF_SRV_MSG_EXIT) {
+       if ((state->pf->cmds == PF_SRV_MSG_EXIT) &&
+           (state->pf->num_clients <= 0)) {
                /* We have been asked to exit, so drop here and the next
                 * child will pick it up */
                state->pf->status = PF_WORKER_EXITING;
@@ -566,19 +596,26 @@ static void prefork_listen_accept_handler(struct tevent_context *ev,
                goto done;
        }
 
+       /* before proceeding check that the listening fd is ok */
+       ret = getsockopt(ctx->listen_fd, SOL_SOCKET, SO_ERROR, &soerr, &solen);
+       if (ret == -1) {
+               /* this is a fatal error, we cannot continue listening */
+               state->error = EBADF;
+               goto done;
+       }
+       if (soerr != 0) {
+               /* this is a fatal error, we cannot continue listening */
+               state->error = soerr;
+               goto done;
+       }
+
        ZERO_STRUCT(addr);
        addrlen = sizeof(addr);
        sd = accept(ctx->listen_fd, (struct sockaddr *)&addr, &addrlen);
        if (sd == -1) {
-               err = errno;
-               DEBUG(6, ("Accept failed! (%d, %s)\n", err, strerror(err)));
-       }
-
-       /* do not track the listen fds anymore */
-       talloc_free(ctx->fde_ctx);
-       ctx = NULL;
-       if (err) {
-               state->error = err;
+               state->error = errno;
+               DEBUG(6, ("Accept failed! (%d, %s)\n",
+                         state->error, strerror(state->error)));
                goto done;
        }
 
@@ -609,6 +646,8 @@ static void prefork_listen_accept_handler(struct tevent_context *ev,
        }
 
 done:
+       /* do not track the listen fds anymore */
+       talloc_free(ctx->fde_ctx);
        tevent_req_done(req);
 }