LCOV - code coverage report
Current view: top level - source3/lib - server_prefork.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 189 316 59.8 %
Date: 2021-09-23 10:06:22 Functions: 11 21 52.4 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Common server globals
       4             : 
       5             :    Copyright (C) Simo Sorce <idra@samba.org> 2011
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "serverid.h"
      23             : #include "messages.h"
      24             : #include "system/time.h"
      25             : #include "system/shmem.h"
      26             : #include "system/filesys.h"
      27             : #include "server_prefork.h"
      28             : #include "../lib/util/samba_util.h"
      29             : #include "../lib/util/tevent_unix.h"
      30             : 
      31             : struct prefork_pool {
      32             :         int listen_fd_size;
      33             :         struct pf_listen_fd *listen_fds;
      34             : 
      35             :         prefork_main_fn_t *main_fn;
      36             :         void *private_data;
      37             : 
      38             :         int pool_size;
      39             :         struct pf_worker_data *pool;
      40             : 
      41             :         int allowed_clients;
      42             : 
      43             :         prefork_sigchld_fn_t *sigchld_fn;
      44             :         void *sigchld_data;
      45             : };
      46             : 
      47             : static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
      48             :                                             struct prefork_pool *pfp);
      49             : 
      50           0 : static int prefork_pool_destructor(struct prefork_pool *pfp)
      51             : {
      52           0 :         anonymous_shared_free(pfp->pool);
      53           0 :         return 0;
      54             : }
      55             : 
      56          17 : bool prefork_create_pool(TALLOC_CTX *mem_ctx,
      57             :                          struct tevent_context *ev_ctx,
      58             :                          struct messaging_context *msg_ctx,
      59             :                          int listen_fd_size, struct pf_listen_fd *listen_fds,
      60             :                          int min_children, int max_children,
      61             :                          prefork_main_fn_t *main_fn, void *private_data,
      62             :                          struct prefork_pool **pf_pool)
      63             : {
      64          17 :         struct prefork_pool *pfp = NULL;
      65             :         pid_t pid;
      66          17 :         time_t now = time(NULL);
      67             :         size_t data_size;
      68             :         int ret;
      69             :         int i;
      70             :         bool ok;
      71             : 
      72          17 :         pfp = talloc_zero(mem_ctx, struct prefork_pool);
      73          17 :         if (!pfp) {
      74           0 :                 DEBUG(1, ("Out of memory!\n"));
      75           0 :                 goto fail;
      76             :         }
      77          17 :         pfp->listen_fd_size = listen_fd_size;
      78          17 :         pfp->listen_fds = talloc_array(pfp, struct pf_listen_fd,
      79             :                                        listen_fd_size);
      80          17 :         if (!pfp->listen_fds) {
      81           0 :                 DEBUG(1, ("Out of memory!\n"));
      82           0 :                 goto fail;
      83             :         }
      84         129 :         for (i = 0; i < listen_fd_size; i++) {
      85         112 :                 pfp->listen_fds[i] = listen_fds[i];
      86             :                 /* force sockets in non-blocking mode */
      87         112 :                 ret = set_blocking(listen_fds[i].fd, false);
      88         112 :                 if (ret < 0) {
      89           0 :                         DBG_WARNING("Failed to set sockets to non-blocking!\n");
      90           0 :                         goto fail;
      91             :                 }
      92             :         }
      93          17 :         pfp->main_fn = main_fn;
      94          17 :         pfp->private_data = private_data;
      95             : 
      96          17 :         pfp->pool_size = max_children;
      97          17 :         data_size = sizeof(struct pf_worker_data) * max_children;
      98             : 
      99          17 :         pfp->pool = (struct pf_worker_data *)anonymous_shared_allocate(
     100             :                 data_size);
     101          17 :         if (pfp->pool == NULL) {
     102           0 :                 DEBUG(1, ("Failed to mmap memory for prefork pool!\n"));
     103           0 :                 goto fail;
     104             :         }
     105          17 :         talloc_set_destructor(pfp, prefork_pool_destructor);
     106             : 
     107         100 :         for (i = 0; i < min_children; i++) {
     108             : 
     109          85 :                 pfp->pool[i].allowed_clients = 1;
     110          85 :                 pfp->pool[i].started = now;
     111             : 
     112          85 :                 pid = fork();
     113          96 :                 switch (pid) {
     114           0 :                 case -1:
     115           0 :                         DEBUG(1, ("Failed to prefork child n. %d !\n", i));
     116           0 :                         break;
     117             : 
     118          13 :                 case 0: /* THE CHILD */
     119             : 
     120          13 :                         pfp->pool[i].status = PF_WORKER_ALIVE;
     121          26 :                         ret = pfp->main_fn(ev_ctx, msg_ctx,
     122          13 :                                            &pfp->pool[i], i + 1,
     123             :                                            pfp->listen_fd_size,
     124             :                                            pfp->listen_fds,
     125             :                                            pfp->private_data);
     126           0 :                         exit(ret);
     127             : 
     128          83 :                 default: /* THE PARENT */
     129          83 :                         pfp->pool[i].pid = pid;
     130          83 :                         break;
     131             :                 }
     132             :         }
     133             : 
     134          15 :         ok = prefork_setup_sigchld_handler(ev_ctx, pfp);
     135          15 :         if (!ok) {
     136           0 :                 DEBUG(1, ("Failed to setup SIGCHLD Handler!\n"));
     137           0 :                 goto fail;
     138             :         }
     139             : 
     140          15 :         *pf_pool = pfp;
     141          15 :         return true;
     142           0 : fail:
     143           0 :         TALLOC_FREE(pfp);
     144           0 :         return false;
     145             : }
     146             : 
     147             : /* Provide the new max children number in new_max
     148             :  * (must be larger than current max).
     149             :  * Returns: 0 if all fine
     150             :  *          ENOSPC if mremap fails to expand
     151             :  *          EINVAL if new_max is invalid
     152             :  */
     153           0 : int prefork_expand_pool(struct prefork_pool *pfp, int new_max)
     154             : {
     155           0 :         struct prefork_pool *pool = NULL;
     156             :         size_t old_size;
     157             :         size_t new_size;
     158             :         int ret;
     159             : 
     160           0 :         if (new_max <= pfp->pool_size) {
     161           0 :                 return EINVAL;
     162             :         }
     163             : 
     164           0 :         old_size = sizeof(struct pf_worker_data) * pfp->pool_size;
     165           0 :         new_size = sizeof(struct pf_worker_data) * new_max;
     166             : 
     167           0 :         pool = (struct prefork_pool *)anonymous_shared_resize(
     168           0 :                 &pfp->pool, new_size, false);
     169           0 :         if (pool == NULL) {
     170           0 :                 ret = errno;
     171           0 :                 DEBUG(3, ("Failed to mremap memory (%d: %s)!\n",
     172             :                           ret, strerror(ret)));
     173           0 :                 return ret;
     174             :         }
     175             : 
     176           0 :         memset(&pool[pfp->pool_size], 0, new_size - old_size);
     177             : 
     178           0 :         pfp->pool_size = new_max;
     179             : 
     180           0 :         return 0;
     181             : }
     182             : 
     183          21 : int prefork_add_children(struct tevent_context *ev_ctx,
     184             :                          struct messaging_context *msg_ctx,
     185             :                          struct prefork_pool *pfp,
     186             :                          int num_children)
     187             : {
     188             :         pid_t pid;
     189          21 :         time_t now = time(NULL);
     190             :         int ret;
     191             :         int i, j;
     192             : 
     193         272 :         for (i = 0, j = 0; i < pfp->pool_size && j < num_children; i++) {
     194             : 
     195         266 :                 if (pfp->pool[i].status != PF_WORKER_NONE) {
     196         161 :                         continue;
     197             :                 }
     198             : 
     199         105 :                 pfp->pool[i].allowed_clients = 1;
     200         105 :                 pfp->pool[i].started = now;
     201             : 
     202         105 :                 pid = fork();
     203         133 :                 switch (pid) {
     204           0 :                 case -1:
     205           0 :                         DEBUG(1, ("Failed to prefork child n. %d !\n", j));
     206           0 :                         break;
     207             : 
     208          43 :                 case 0: /* THE CHILD */
     209             : 
     210          43 :                         pfp->pool[i].status = PF_WORKER_ALIVE;
     211          86 :                         ret = pfp->main_fn(ev_ctx, msg_ctx,
     212          43 :                                            &pfp->pool[i], i + 1,
     213             :                                            pfp->listen_fd_size,
     214             :                                            pfp->listen_fds,
     215             :                                            pfp->private_data);
     216             : 
     217           0 :                         pfp->pool[i].status = PF_WORKER_EXITING;
     218           0 :                         exit(ret);
     219             : 
     220          90 :                 default: /* THE PARENT */
     221          90 :                         pfp->pool[i].pid = pid;
     222          90 :                         j++;
     223          90 :                         break;
     224             :                 }
     225             :         }
     226             : 
     227           6 :         DEBUG(5, ("Added %d children!\n", j));
     228             : 
     229           6 :         return j;
     230             : }
     231             : 
     232             : struct prefork_oldest {
     233             :         int num;
     234             :         time_t started;
     235             : };
     236             : 
     237             : /* sort in inverse order */
     238        4939 : static int prefork_sort_oldest(const void *ap, const void *bp)
     239             : {
     240        4939 :         const struct prefork_oldest *a = (const struct prefork_oldest *)ap;
     241        4939 :         const struct prefork_oldest *b = (const struct prefork_oldest *)bp;
     242             : 
     243        4939 :         if (a->started == b->started) {
     244        2119 :                 return 0;
     245             :         }
     246        2820 :         if (a->started < b->started) {
     247        2820 :                 return 1;
     248             :         }
     249           0 :         return -1;
     250             : }
     251             : 
     252          72 : int prefork_retire_children(struct messaging_context *msg_ctx,
     253             :                             struct prefork_pool *pfp,
     254             :                             int num_children, time_t age_limit)
     255             : {
     256          72 :         const DATA_BLOB ping = data_blob_null;
     257          72 :         time_t now = time(NULL);
     258          72 :         struct prefork_oldest *oldest = NULL;
     259             :         int i, j;
     260             : 
     261          72 :         oldest = talloc_array(pfp, struct prefork_oldest, pfp->pool_size);
     262          72 :         if (!oldest) {
     263           0 :                 return -1;
     264             :         }
     265             : 
     266        1872 :         for (i = 0; i < pfp->pool_size; i++) {
     267        1800 :                 oldest[i].num = i;
     268        3154 :                 if (pfp->pool[i].status == PF_WORKER_ALIVE ||
     269        1354 :                     pfp->pool[i].status == PF_WORKER_ACCEPTING) {
     270        1269 :                         oldest[i].started = pfp->pool[i].started;
     271             :                 } else {
     272         531 :                         oldest[i].started = now;
     273             :                 }
     274             :         }
     275             : 
     276          72 :         qsort(oldest, pfp->pool_size,
     277             :                 sizeof(struct prefork_oldest),
     278             :                 prefork_sort_oldest);
     279             : 
     280        1872 :         for (i = 0, j = 0; i < pfp->pool_size && j < num_children; i++) {
     281        2246 :                 if (((pfp->pool[i].status == PF_WORKER_ALIVE) &&
     282         446 :                      (pfp->pool[i].num_clients < 1)) &&
     283           0 :                     (pfp->pool[i].started <= age_limit)) {
     284             :                         /* tell the child it's time to give up */
     285           0 :                         DEBUG(5, ("Retiring pid %u!\n", (unsigned int)pfp->pool[i].pid));
     286           0 :                         pfp->pool[i].cmds = PF_SRV_MSG_EXIT;
     287           0 :                         messaging_send(msg_ctx,
     288           0 :                                         pid_to_procid(pfp->pool[i].pid),
     289             :                                         MSG_PREFORK_PARENT_EVENT, &ping);
     290           0 :                         j++;
     291             :                 }
     292             :         }
     293             : 
     294          72 :         return j;
     295             : }
     296             : 
     297        5785 : int prefork_count_children(struct prefork_pool *pfp, int *active)
     298             : {
     299             :         int i, a, t;
     300             : 
     301        5785 :         a = 0;
     302        5785 :         t = 0;
     303      150410 :         for (i = 0; i < pfp->pool_size; i++) {
     304      144625 :                 if (pfp->pool[i].status == PF_WORKER_NONE) {
     305       96290 :                         continue;
     306             :                 }
     307             : 
     308       48335 :                 t++;
     309             : 
     310       96670 :                 if ((pfp->pool[i].status == PF_WORKER_EXITING) ||
     311       48335 :                     (pfp->pool[i].num_clients <= 0)) {
     312       37476 :                         continue;
     313             :                 }
     314             : 
     315       10859 :                 a++;
     316             :         }
     317             : 
     318        5785 :         if (active) {
     319           0 :                 *active = a;
     320             :         }
     321        5785 :         return t;
     322             : }
     323             : 
     324           0 : static void prefork_cleanup_loop(struct prefork_pool *pfp)
     325             : {
     326             :         int status;
     327             :         pid_t pid;
     328             :         int i;
     329             : 
     330             :         /* TODO: should we use a process group id wait instead of looping ? */
     331           0 :         for (i = 0; i < pfp->pool_size; i++) {
     332           0 :                 if (pfp->pool[i].status == PF_WORKER_NONE ||
     333           0 :                     pfp->pool[i].pid == 0) {
     334           0 :                         continue;
     335             :                 }
     336             : 
     337           0 :                 pid = waitpid(pfp->pool[i].pid, &status, WNOHANG);
     338           0 :                 if (pid > 0) {
     339             : 
     340           0 :                         if (pfp->pool[i].status != PF_WORKER_EXITING) {
     341           0 :                                 DEBUG(3, ("Child (%d) terminated abnormally:"
     342             :                                           " %d\n", (int)pid, status));
     343             :                         } else {
     344           0 :                                 DEBUG(10, ("Child (%d) terminated with status:"
     345             :                                            " %d\n", (int)pid, status));
     346             :                         }
     347             : 
     348             :                         /* reset all fields,
     349             :                          * this makes status = PF_WORK_NONE */
     350           0 :                         memset(&pfp->pool[i], 0,
     351             :                                 sizeof(struct pf_worker_data));
     352             :                 }
     353             :         }
     354             : 
     355           0 : }
     356             : 
     357        5785 : int prefork_count_allowed_connections(struct prefork_pool *pfp)
     358             : {
     359             :         int c;
     360             :         int i;
     361             : 
     362        5785 :         c = 0;
     363      150410 :         for (i = 0; i < pfp->pool_size; i++) {
     364      192960 :                 if (pfp->pool[i].status == PF_WORKER_NONE ||
     365       48335 :                     pfp->pool[i].status == PF_WORKER_EXITING) {
     366       96290 :                         continue;
     367             :                 }
     368             : 
     369       48335 :                 if (pfp->pool[i].num_clients < 0) {
     370           0 :                         continue;
     371             :                 }
     372             : 
     373       48335 :                 c += pfp->pool[i].allowed_clients - pfp->pool[i].num_clients;
     374             :         }
     375             : 
     376        5785 :         return c;
     377             : }
     378             : 
     379           0 : void prefork_increase_allowed_clients(struct prefork_pool *pfp, int max)
     380             : {
     381             :         int i;
     382             : 
     383           0 :         for (i = 0; i < pfp->pool_size; i++) {
     384           0 :                 if (pfp->pool[i].status == PF_WORKER_NONE ||
     385           0 :                     pfp->pool[i].status == PF_WORKER_EXITING) {
     386           0 :                         continue;
     387             :                 }
     388             : 
     389           0 :                 if (pfp->pool[i].num_clients < 0) {
     390           0 :                         continue;
     391             :                 }
     392             : 
     393           0 :                 if (pfp->pool[i].allowed_clients < max) {
     394           0 :                         pfp->pool[i].allowed_clients++;
     395             :                 }
     396             :         }
     397           0 : }
     398             : 
     399           0 : void prefork_decrease_allowed_clients(struct prefork_pool *pfp)
     400             : {
     401             :         int i;
     402             : 
     403           0 :         for (i = 0; i < pfp->pool_size; i++) {
     404           0 :                 if (pfp->pool[i].status == PF_WORKER_NONE ||
     405           0 :                     pfp->pool[i].status == PF_WORKER_EXITING) {
     406           0 :                         continue;
     407             :                 }
     408             : 
     409           0 :                 if (pfp->pool[i].num_clients < 0) {
     410           0 :                         continue;
     411             :                 }
     412             : 
     413           0 :                 if (pfp->pool[i].allowed_clients > 1) {
     414           0 :                         pfp->pool[i].allowed_clients--;
     415             :                 }
     416             :         }
     417           0 : }
     418             : 
     419           0 : void prefork_reset_allowed_clients(struct prefork_pool *pfp)
     420             : {
     421             :         int i;
     422             : 
     423           0 :         for (i = 0; i < pfp->pool_size; i++) {
     424           0 :                 pfp->pool[i].allowed_clients = 1;
     425             :         }
     426           0 : }
     427             : 
     428           0 : void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num)
     429             : {
     430             :         int i;
     431             : 
     432           0 :         for (i = 0; i < pfp->pool_size; i++) {
     433           0 :                 if (pfp->pool[i].status == PF_WORKER_NONE) {
     434           0 :                         continue;
     435             :                 }
     436             : 
     437           0 :                 kill(pfp->pool[i].pid, signal_num);
     438             :         }
     439           0 : }
     440             : 
     441           0 : void prefork_warn_active_children(struct messaging_context *msg_ctx,
     442             :                                   struct prefork_pool *pfp)
     443             : {
     444           0 :         const DATA_BLOB ping = data_blob_null;
     445             :         int i;
     446             : 
     447           0 :         for (i = 0; i < pfp->pool_size; i++) {
     448           0 :                 if (pfp->pool[i].status == PF_WORKER_NONE) {
     449           0 :                         continue;
     450             :                 }
     451             : 
     452           0 :                 messaging_send(msg_ctx,
     453           0 :                                 pid_to_procid(pfp->pool[i].pid),
     454             :                                 MSG_PREFORK_PARENT_EVENT, &ping);
     455             :         }
     456           0 : }
     457             : 
     458           0 : static void prefork_sigchld_handler(struct tevent_context *ev_ctx,
     459             :                                     struct tevent_signal *se,
     460             :                                     int signum, int count,
     461             :                                     void *siginfo, void *pvt)
     462             : {
     463           0 :         struct prefork_pool *pfp = talloc_get_type_abort(
     464             :                 pvt, struct prefork_pool);
     465             : 
     466             :         /* run the cleanup function to make sure all dead children are
     467             :          * properly and timely retired. */
     468           0 :         prefork_cleanup_loop(pfp);
     469             : 
     470           0 :         if (pfp->sigchld_fn) {
     471           0 :                 pfp->sigchld_fn(ev_ctx, pfp, pfp->sigchld_data);
     472             :         }
     473           0 : }
     474             : 
     475          15 : static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
     476             :                                           struct prefork_pool *pfp)
     477             : {
     478          15 :         struct tevent_signal *se = NULL;
     479             : 
     480          15 :         se = tevent_add_signal(ev_ctx, pfp, SIGCHLD, 0,
     481             :                                 prefork_sigchld_handler, pfp);
     482          15 :         if (!se) {
     483           0 :                 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
     484           0 :                 return false;
     485             :         }
     486             : 
     487          15 :         return true;
     488             : }
     489             : 
     490          15 : void prefork_set_sigchld_callback(struct prefork_pool *pfp,
     491             :                                   prefork_sigchld_fn_t *sigchld_fn,
     492             :                                   void *private_data)
     493             : {
     494          15 :         pfp->sigchld_fn = sigchld_fn;
     495          15 :         pfp->sigchld_data = private_data;
     496          15 : }
     497             : 
     498             : /* ==== Functions used by children ==== */
     499             : 
     500             : struct pf_listen_state {
     501             :         struct tevent_context *ev;
     502             :         struct pf_worker_data *pf;
     503             : 
     504             :         int listen_fd_size;
     505             :         struct pf_listen_fd *listen_fds;
     506             : 
     507             :         struct pf_listen_fd accept;
     508             : 
     509             :         struct tsocket_address *srv_addr;
     510             :         struct tsocket_address *cli_addr;
     511             : 
     512             :         int error;
     513             : };
     514             : 
     515             : struct pf_listen_ctx {
     516             :         TALLOC_CTX *fde_ctx;
     517             :         struct tevent_req *req;
     518             :         int listen_fd;
     519             :         void *listen_fd_data;
     520             : };
     521             : 
     522             : static void prefork_listen_accept_handler(struct tevent_context *ev,
     523             :                                           struct tevent_fd *fde,
     524             :                                           uint16_t flags, void *pvt);
     525             : 
     526        2802 : struct tevent_req *prefork_listen_send(TALLOC_CTX *mem_ctx,
     527             :                                         struct tevent_context *ev,
     528             :                                         struct pf_worker_data *pf,
     529             :                                         int listen_fd_size,
     530             :                                         struct pf_listen_fd *listen_fds)
     531             : {
     532        2802 :         struct tevent_req *req = NULL;
     533        2802 :         struct pf_listen_state *state = NULL;
     534        2802 :         struct pf_listen_ctx *ctx = NULL;
     535        2802 :         struct tevent_fd *fde = NULL;
     536        2802 :         TALLOC_CTX *fde_ctx = NULL;
     537             :         int i;
     538             : 
     539        2802 :         req = tevent_req_create(mem_ctx, &state, struct pf_listen_state);
     540        2802 :         if (!req) {
     541           0 :                 return NULL;
     542             :         }
     543             : 
     544        2802 :         state->ev = ev;
     545        2802 :         state->pf = pf;
     546        2802 :         state->listen_fd_size = listen_fd_size;
     547        2802 :         state->listen_fds = listen_fds;
     548        2802 :         state->accept.fd = -1;
     549        2802 :         state->accept.fd_data = NULL;
     550        2802 :         state->error = 0;
     551             : 
     552        2802 :         fde_ctx = talloc_new(state);
     553        2802 :         if (tevent_req_nomem(fde_ctx, req)) {
     554           0 :                 return tevent_req_post(req, ev);
     555             :         }
     556             : 
     557             :         /* race on accept */
     558       27897 :         for (i = 0; i < state->listen_fd_size; i++) {
     559       25095 :                 ctx = talloc(fde_ctx, struct pf_listen_ctx);
     560       25095 :                 if (tevent_req_nomem(ctx, req)) {
     561           0 :                         return tevent_req_post(req, ev);
     562             :                 }
     563       25095 :                 ctx->fde_ctx = fde_ctx;
     564       25095 :                 ctx->req = req;
     565       25095 :                 ctx->listen_fd = state->listen_fds[i].fd;
     566       25095 :                 ctx->listen_fd_data = state->listen_fds[i].fd_data;
     567             : 
     568       25095 :                 fde = tevent_add_fd(state->ev, fde_ctx,
     569             :                                     ctx->listen_fd, TEVENT_FD_READ,
     570             :                                     prefork_listen_accept_handler, ctx);
     571       25095 :                 if (tevent_req_nomem(fde, req)) {
     572           0 :                         return tevent_req_post(req, ev);
     573             :                 }
     574             :         }
     575             : 
     576        2802 :         pf->status = PF_WORKER_ACCEPTING;
     577             : 
     578        2802 :         return req;
     579             : }
     580             : 
     581        2798 : static void prefork_listen_accept_handler(struct tevent_context *ev,
     582             :                                           struct tevent_fd *fde,
     583             :                                           uint16_t flags, void *pvt)
     584             : {
     585        2798 :         struct pf_listen_ctx *ctx = talloc_get_type_abort(
     586             :                 pvt, struct pf_listen_ctx);
     587        2798 :         struct tevent_req *req = ctx->req;
     588        2798 :         struct pf_listen_state *state = tevent_req_data(
     589             :                 ctx->req, struct pf_listen_state);
     590        2798 :         struct sockaddr_storage addr = { .ss_family = 0 };
     591        2798 :         socklen_t addrlen = sizeof(addr);
     592        2798 :         int soerr = 0;
     593        2798 :         socklen_t solen = sizeof(soerr);
     594        2798 :         int sd = -1;
     595             :         int ret;
     596             : 
     597        2798 :         if ((state->pf->cmds == PF_SRV_MSG_EXIT) &&
     598           0 :             (state->pf->num_clients <= 0)) {
     599             :                 /* We have been asked to exit, so drop here and the next
     600             :                  * child will pick it up */
     601           0 :                 state->pf->status = PF_WORKER_EXITING;
     602           0 :                 state->error = EINTR;
     603           0 :                 goto done;
     604             :         }
     605             : 
     606             :         /* before proceeding check that the listening fd is ok */
     607        2798 :         ret = getsockopt(ctx->listen_fd, SOL_SOCKET, SO_ERROR, &soerr, &solen);
     608        2798 :         if (ret == -1) {
     609             :                 /* this is a fatal error, we cannot continue listening */
     610           0 :                 state->error = EBADF;
     611           0 :                 goto done;
     612             :         }
     613        2798 :         if (soerr != 0) {
     614             :                 /* this is a fatal error, we cannot continue listening */
     615           0 :                 state->error = soerr;
     616           0 :                 goto done;
     617             :         }
     618             : 
     619        2798 :         sd = accept(ctx->listen_fd, (struct sockaddr *)&addr, &addrlen);
     620        2798 :         if (sd == -1) {
     621        1722 :                 state->error = errno;
     622        1722 :                 DEBUG(6, ("Accept failed! (%d, %s)\n",
     623             :                           state->error, strerror(state->error)));
     624        1722 :                 goto done;
     625             :         }
     626        1076 :         smb_set_close_on_exec(sd);
     627             : 
     628        1076 :         state->accept.fd = sd;
     629        1076 :         state->accept.fd_data = ctx->listen_fd_data;
     630             : 
     631        1076 :         ret = tsocket_address_bsd_from_sockaddr(state,
     632             :                                         (struct sockaddr *)(void *)&addr,
     633             :                                         addrlen, &state->cli_addr);
     634        1076 :         if (ret < 0) {
     635           0 :                 state->error = errno;
     636           0 :                 goto done;
     637             :         }
     638             : 
     639        1076 :         ZERO_STRUCT(addr);
     640        1076 :         addrlen = sizeof(addr);
     641        1076 :         ret = getsockname(sd, (struct sockaddr *)(void *)&addr, &addrlen);
     642        1076 :         if (ret < 0) {
     643           0 :                 state->error = errno;
     644           0 :                 goto done;
     645             :         }
     646             : 
     647        1076 :         ret = tsocket_address_bsd_from_sockaddr(state,
     648             :                                         (struct sockaddr *)(void *)&addr,
     649             :                                         addrlen, &state->srv_addr);
     650        1076 :         if (ret < 0) {
     651           0 :                 state->error = errno;
     652           0 :                 goto done;
     653             :         }
     654             : 
     655        3874 : done:
     656             :         /* do not track the listen fds anymore */
     657        2798 :         talloc_free(ctx->fde_ctx);
     658        2798 :         tevent_req_done(req);
     659        2798 : }
     660             : 
     661        2798 : int prefork_listen_recv(struct tevent_req *req,
     662             :                         TALLOC_CTX *mem_ctx, int *fd,
     663             :                         void **fd_data,
     664             :                         struct tsocket_address **srv_addr,
     665             :                         struct tsocket_address **cli_addr)
     666             : {
     667        2798 :         struct pf_listen_state *state = tevent_req_data(
     668             :                 req, struct pf_listen_state);
     669        2798 :         int ret = 0;
     670             : 
     671        2798 :         if (state->error) {
     672        1722 :                 ret = state->error;
     673             :         } else {
     674        1076 :                 if (!tevent_req_is_unix_error(req, &ret)) {
     675        1076 :                         ret = 0;
     676             :                 }
     677             :         }
     678             : 
     679        2798 :         if (ret) {
     680        1722 :                 if (state->accept.fd != -1) {
     681           0 :                         close(state->accept.fd);
     682             :                 }
     683             :         } else {
     684        1076 :                 *fd = state->accept.fd;
     685        1076 :                 if (fd_data != NULL) {
     686        1076 :                         *fd_data = state->accept.fd_data;
     687             :                 }
     688        1076 :                 *srv_addr = talloc_move(mem_ctx, &state->srv_addr);
     689        1076 :                 *cli_addr = talloc_move(mem_ctx, &state->cli_addr);
     690        1076 :                 state->pf->num_clients++;
     691             :         }
     692        2798 :         if (state->pf->status == PF_WORKER_ACCEPTING) {
     693        2798 :                 state->pf->status = PF_WORKER_ALIVE;
     694             :         }
     695             : 
     696        2798 :         tevent_req_received(req);
     697        2798 :         return ret;
     698             : }

Generated by: LCOV version 1.13