LTP GCOV extension - code coverage report
Current view: directory - and-httpd/src - cntl.c
Test: And-httpd coverage
Date: 2006-09-11 Instrumented lines: 458
Code covered: 75.8 % Executed lines: 347

       1                 : /*
       2                 :  *  Copyright (C) 2002, 2003, 2004, 2005, 2006  James Antill
       3                 :  *
       4                 :  *  This library is free software; you can redistribute it and/or
       5                 :  *  modify it under the terms of the GNU Lesser General Public
       6                 :  *  License as published by the Free Software Foundation; either
       7                 :  *  version 2 of the License, or (at your option) any later version.
       8                 :  *
       9                 :  *  This library is distributed in the hope that it will be useful,
      10                 :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12                 :  *  Lesser General Public License for more details.
      13                 :  *
      14                 :  *  You should have received a copy of the GNU Lesser General Public
      15                 :  *  License along with this library; if not, write to the Free Software
      16                 :  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17                 :  *
      18                 :  *  email: james@and.org
      19                 :  */
      20                 : /* controller channel for servers, also has code for multiple procs. at once */
      21                 : 
      22                 : #include "cntl.h"
      23                 : #include "opt_serv.h"
      24                 : #include <unistd.h>
      25                 : 
      26                 : #include <poll.h>
      27                 : #include <socket_poll.h>
      28                 : #include <sys/types.h>
      29                 : #include <sys/socket.h>
      30                 : #include <netinet/in.h>
      31                 : #include <signal.h>
      32                 : 
      33                 : #define EX_UTILS_NO_FUNCS  1
      34                 : #include "ex_utils.h"
      35                 : 
      36                 : #include "mk.h"
      37                 : 
      38                 : #include "bag.h"
      39                 : 
      40                 : struct Cntl_child_obj
      41                 : {
      42                 :  struct Evnt evnt[1];
      43                 :  pid_t pid;
      44                 : };
      45                 : 
      46                 : struct Cntl_waiter_obj
      47                 : {
      48                 :  struct Evnt *evnt;
      49                 :  unsigned int num;
      50                 : };
      51                 : 
      52                 : /* for simplicity */
      53                 : #define VEQ(vstr, p, l, cstr) vstr_cmp_cstr_eq(vstr, p, l, cstr)
      54                 : 
      55                 : static Vlg *vlg = NULL;
      56                 : static struct Evnt *acpt_cntl_evnt = NULL;
      57                 : static struct Evnt *acpt_pipe_evnt = NULL;
      58                 : 
      59                 : static Bag *childs  = NULL;
      60                 : static Bag *waiters = NULL;
      61                 : 
      62                 : static unsigned int potential_waiters = 0;
      63                 : 
      64                 : 
      65                 : static void cntl__fin(Vstr_base *out)
      66             250 : {
      67             250 :   size_t ns1 = 0;
      68             250 :   size_t ns2 = 0;
      69                 : 
      70             250 :   if (!(ns1 = vstr_add_netstr_beg(out, out->len)))
      71               0 :     return;
      72             250 :   if (!(ns2 = vstr_add_netstr_beg(out, out->len)))
      73               0 :     return;
      74             250 :   vstr_add_netstr_end(out, ns2, out->len);
      75             250 :   vstr_add_netstr_end(out, ns1, out->len);
      76                 : }
      77                 : 
      78                 : static struct Cntl_waiter_obj *cntl_waiter_get_first(void)
      79              58 : {
      80                 :   Bag_iter iter[1];
      81              58 :   const Bag_obj *obj = bag_iter_beg(waiters, iter);
      82                 : 
      83             134 :   while (obj)
      84                 :   {
      85              40 :     struct Cntl_waiter_obj *val = obj->val;
      86                 :       
      87              40 :     if (val->num)
      88              22 :       return (val);
      89                 :     
      90              18 :     obj = bag_iter_nxt(iter);
      91                 :   }
      92                 : 
      93              36 :   return (NULL);
      94                 : }
      95                 : 
      96                 : static int cntl_waiter_add(struct Evnt *evnt, size_t pos, size_t len, int *stop)
      97             250 : {
      98                 :   Bag_iter iter[1];
      99             250 :   const Bag_obj *obj = NULL;
     100             250 :   struct Cntl_waiter_obj *val = NULL;
     101             250 :   Bag *tmp = NULL;
     102                 :   
     103             125 :   ASSERT(stop);
     104                 :   
     105             250 :   if (!childs)
     106                 :   {
     107             232 :     cntl__fin(evnt->io_w);
     108             232 :     return (TRUE);
     109                 :   }
     110                 :   
     111              18 :   if (!(val = MK(sizeof(struct Cntl_waiter_obj))))
     112               0 :     return (FALSE);
     113                 :   
     114              18 :   if (!(tmp = bag_add_obj(waiters, NULL, val)))
     115                 :   {
     116               0 :     F(val);
     117               0 :     VLG_WARNNOMEM_RET(FALSE, (vlg, "%s: %m\n", "cntl waiters"));
     118                 :   }
     119                 :   
     120              18 :   waiters = tmp;
     121                 :   
     122              18 :   val->evnt = evnt;
     123              18 :   val->num  = childs->num;
     124                 :   
     125              18 :   obj = bag_iter_beg(childs, iter);
     126              54 :   while (obj)
     127                 :   {
     128              18 :     struct Cntl_child_obj *child = (void *)obj->val;
     129              18 :     Vstr_base *out = NULL;
     130                 : 
     131              18 :     if (!child)
     132               0 :       return (FALSE);
     133                 :     
     134              18 :     out = child->evnt->io_w;
     135                 :     
     136              18 :     if (!vstr_add_vstr(out, out->len, evnt->io_r, pos, len, VSTR_TYPE_ADD_DEF))
     137                 :     {
     138               0 :       out->conf->malloc_bad = FALSE;
     139               0 :       return (FALSE);
     140                 :     }
     141                 :     
     142              18 :     if (!evnt_send_add(child->evnt, FALSE, 32))
     143                 :     {
     144               0 :       evnt_close(child->evnt);
     145               0 :       return (FALSE);
     146                 :     }
     147                 :     
     148              18 :     evnt_put_pkt(child->evnt);
     149              18 :     obj = bag_iter_nxt(iter);
     150                 :   }
     151                 :   
     152              18 :   evnt_wait_cntl_del(evnt, POLLIN);
     153              18 :   *stop = TRUE;
     154                 :   
     155              18 :   return (TRUE);
     156                 : }
     157                 : 
     158                 : static void cntl_waiter_del(struct Evnt *child_evnt,
     159                 :                             struct Cntl_waiter_obj *val)
     160              18 : {
     161              18 :   evnt_got_pkt(child_evnt);
     162                 : 
     163              18 :   if (!--val->num)
     164                 :   {
     165              18 :     if (val->evnt)
     166                 :     {
     167              18 :       cntl__fin(val->evnt->io_w);
     168              18 :       if (!evnt_send_add(val->evnt, FALSE, 32))
     169               0 :         evnt_close(val->evnt);
     170                 :       else
     171              18 :         evnt_wait_cntl_add(val->evnt, POLLIN);
     172                 :     }
     173                 :     
     174              18 :     if (!cntl_waiter_get_first()) /* no more left... */
     175              18 :       bag_del_all(waiters);
     176                 :   }
     177              18 : }
     178                 : 
     179                 : static void cntl__ns_out_cstr_ptr(Vstr_base *out, const char *ptr)
     180            1380 : {
     181            1380 :   size_t ns = 0;
     182                 : 
     183            1380 :   if (!(ns = vstr_add_netstr_beg(out, out->len)))
     184               0 :     return;
     185                 :   
     186            1380 :   vstr_add_cstr_ptr(out, out->len, ptr);
     187                 :   
     188            1380 :   vstr_add_netstr_end(out, ns, out->len);
     189                 : }
     190                 : 
     191                 : static void cntl__ns_out_fmt(Vstr_base *out, const char *fmt, ...)
     192                 :    COMPILE_ATTR_FMT(2, 3);
     193                 : static void cntl__ns_out_fmt(Vstr_base *out, const char *fmt, ...)
     194            9378 : {
     195                 :   va_list ap;
     196            9378 :   size_t ns = 0;
     197                 : 
     198            9378 :   if (!(ns = vstr_add_netstr_beg(out, out->len)))
     199               0 :     return;
     200                 : 
     201            9378 :   va_start(ap, fmt);
     202            9378 :   vstr_add_vfmt(out, out->len, fmt, ap);
     203            9378 :   va_end(ap);
     204                 : 
     205            9378 :   vstr_add_netstr_end(out, ns, out->len);
     206                 : }
     207                 : 
     208                 : static void cntl__close(Vstr_base *out)
     209              44 : {
     210              44 :   struct Evnt *evnt = evnt_queue("accept");
     211                 : 
     212              44 :   if (!evnt)
     213               0 :     return;
     214                 :   
     215             232 :   while (evnt)
     216                 :   {
     217             166 :     size_t ns1 = 0;
     218                 :     
     219             166 :     if (!(ns1 = vstr_add_netstr_beg(out, out->len)))
     220               0 :       return;
     221                 : 
     222             166 :     cntl__ns_out_cstr_ptr(out, "CLOSE");
     223             166 :     cntl__ns_out_fmt(out, "from[$<sa:%p>]", EVNT_SA(evnt));
     224             166 :     cntl__ns_out_fmt(out, "ctime[%lu:%lu]",
     225                 :                      (unsigned long)evnt->ctime.tv_sec,
     226                 :                      (unsigned long)evnt->ctime.tv_usec);
     227             166 :     cntl__ns_out_fmt(out, "pid[%lu]", (unsigned long)getpid());
     228                 :     
     229             166 :     vstr_add_netstr_end(out, ns1, out->len);
     230                 : 
     231             166 :     vlg_dbg2(vlg, "evnt_close acpt %p\n", evnt);
     232             166 :     evnt_close(evnt);
     233                 : 
     234             166 :     evnt = evnt->next;
     235                 :   }
     236                 : 
     237              44 :   if (evnt_is_child())
     238               4 :     evnt_shutdown_r(acpt_cntl_evnt, FALSE);
     239                 : }
     240                 : 
     241                 : static void cntl__scan_events(Vstr_base *out, const char *tag, struct Evnt *beg)
     242             480 : {
     243             480 :   struct Evnt *ev = beg;
     244                 :   
     245            1517 :   while (ev)
     246                 :   {
     247             557 :     size_t ns = 0;
     248                 : 
     249             557 :     if (!(ns = vstr_add_netstr_beg(out, out->len)))
     250               0 :       return;
     251                 : 
     252             557 :     cntl__ns_out_fmt(out, "EVNT %s", tag);
     253             557 :     cntl__ns_out_fmt(out, "from[$<sa:%p>]", EVNT_SA(ev));
     254             557 :     if (EVNT_ACPT_EXISTS(ev))
     255             225 :       cntl__ns_out_fmt(out, "acpt[$<sa:%p>]", EVNT_ACPT_SA(ev));
     256             557 :     cntl__ns_out_fmt(out, "ctime[%lu:%lu]",
     257                 :                      (unsigned long)ev->ctime.tv_sec,
     258                 :                      (unsigned long)ev->ctime.tv_usec);
     259             557 :     cntl__ns_out_fmt(out, "mtime[%lu:%lu]",
     260                 :                      (unsigned long)ev->mtime.tv_sec,
     261                 :                      (unsigned long)ev->mtime.tv_usec);
     262             557 :     cntl__ns_out_fmt(out, "pid[%lu]", (unsigned long)getpid());
     263             557 :     cntl__ns_out_fmt(out, "req_got[%'u:%u]",
     264                 :                      ev->acct.req_got, ev->acct.req_got);
     265             557 :     cntl__ns_out_fmt(out, "req_put[%'u:%u]",
     266                 :                      ev->acct.req_put, ev->acct.req_put);
     267             557 :     cntl__ns_out_fmt(out, "recv[${BKMG.ju:%ju}:%ju]",
     268                 :                      ev->acct.bytes_r, ev->acct.bytes_r);
     269             557 :     cntl__ns_out_fmt(out, "send[${BKMG.ju:%ju}:%ju]",
     270                 :                      ev->acct.bytes_w, ev->acct.bytes_w);
     271                 : 
     272             557 :     vstr_add_netstr_end(out, ns, out->len);
     273                 :     
     274             557 :     ev = ev->next;
     275                 :   }
     276                 : }
     277                 : 
     278                 : static void cntl__status(Vstr_base *out)
     279             126 : {
     280             126 :   struct Evnt *evnt = evnt_queue("accept");
     281                 :   
     282            1466 :   while (evnt)
     283                 :   {
     284            1214 :     size_t ns1 = 0;
     285                 :     
     286            1214 :     if (!(ns1 = vstr_add_netstr_beg(out, out->len)))
     287               0 :       return;
     288                 : 
     289            1214 :     cntl__ns_out_cstr_ptr(out, "STATUS");
     290            1214 :     cntl__ns_out_fmt(out, "from[$<sa:%p>]", EVNT_SA(evnt));
     291            1214 :     cntl__ns_out_fmt(out, "ctime[%lu:%lu]",
     292                 :                      (unsigned long)evnt->ctime.tv_sec,
     293                 :                      (unsigned long)evnt->ctime.tv_usec);
     294                 :   
     295            1214 :     cntl__ns_out_fmt(out, "pid[%lu]", (unsigned long)getpid());
     296                 :   
     297            1214 :     vstr_add_netstr_end(out, ns1, out->len);
     298                 :     
     299            1214 :     evnt = evnt->next;
     300                 :   }
     301                 : }
     302                 : 
     303                 : static void cntl__dbg(Vstr_base *out)
     304               0 : {
     305               0 :   size_t ns1 = 0;
     306                 :   
     307               0 :   if (!(ns1 = vstr_add_netstr_beg(out, out->len)))
     308               0 :     return;
     309                 : 
     310               0 :   cntl__ns_out_cstr_ptr(out, "DBG");
     311               0 :   cntl__ns_out_fmt(out, "pid[%lu]", (unsigned long)getpid());
     312               0 :   cntl__ns_out_fmt(out, "dbg[%u]", (unsigned)vlg->out_dbg);
     313               0 :   vstr_add_netstr_end(out, ns1, out->len);
     314                 : }
     315                 : 
     316                 : static int cntl__srch_waiter_evnt(const Bag_obj *obj, const void *data)
     317               0 : {
     318               0 :   const struct Cntl_waiter_obj *val = obj->val;
     319               0 :   const struct Evnt *evnt = data;
     320                 : 
     321               0 :   return (val->evnt == evnt);
     322                 : }
     323                 : 
     324                 : static void cntl__cb_func_free(struct Evnt *evnt)
     325             232 : {
     326             232 :   opt_serv_sc_free_beg(evnt, "CNTL FREE");
     327                 : 
     328             232 :   if (waiters)
     329                 :   {
     330              18 :     const Bag_obj *obj = bag_srch_eq(waiters, cntl__srch_waiter_evnt, evnt);
     331                 :     
     332              18 :     if (obj)
     333                 :     {
     334               0 :       struct Cntl_waiter_obj *val = obj->val;
     335                 : 
     336               0 :       ASSERT(val->evnt == evnt);
     337               0 :       val->evnt = NULL;
     338                 :     }
     339                 :   }
     340                 :   
     341             232 :   F(evnt);
     342                 :   
     343             116 :   ASSERT(potential_waiters >= 1);
     344             232 :   --potential_waiters;
     345                 : 
     346             232 :   if (childs && !potential_waiters && !acpt_cntl_evnt)
     347               4 :     bag_del_all(childs);
     348             232 : }
     349                 : 
     350                 : static int cntl__cb_func_recv(struct Evnt *evnt)
     351             615 : {
     352             615 :   int ret = evnt_cb_func_recv(evnt);
     353             615 :   int stop = FALSE;
     354                 :   
     355             615 :   if (!ret)
     356             232 :     goto malloc_bad;
     357                 : 
     358             383 :   vlg_dbg2(vlg, "CNTL recv %zu\n", evnt->io_r->len);
     359                 : 
     360            1016 :   while (evnt->io_r->len && !stop)
     361                 :   {
     362             250 :     size_t pos  = 0;
     363             250 :     size_t len  = 0;
     364             250 :     size_t ns1  = 0;
     365             250 :     size_t cpos = 0;
     366             250 :     size_t clen = 0;
     367             250 :     size_t ns2  = 0;
     368                 :     
     369             250 :     if (!(ns1 = vstr_parse_netstr(evnt->io_r, 1, evnt->io_r->len, &pos, &len)))
     370                 :     {
     371               0 :       if (!(SOCKET_POLL_INDICATOR(evnt->ind)->events & POLLIN))
     372               0 :         return (FALSE);
     373               0 :       return (TRUE);
     374                 :     }
     375             250 :     if ((ns2 = vstr_parse_netstr(evnt->io_r, pos, len, &cpos, &clen)))
     376                 :     { /* double netstr ... might have arguments... */
     377              40 :       SWAP_TYPE(pos, cpos, size_t);
     378              40 :       SWAP_TYPE(len, clen, size_t);
     379                 :     }
     380                 :     
     381             250 :     evnt_got_pkt(evnt);
     382                 : 
     383                 :     if (0){ }
     384             250 :     else if (VEQ(evnt->io_r, pos, len, "CLOSE"))
     385                 :     { /* FIXME: if arg. ns2  ... search for that and close */
     386              44 :       cntl__close(evnt->io_w);
     387                 :       
     388              44 :       if (!cntl_waiter_add(evnt, 1, ns1, &stop))
     389               0 :         goto malloc_bad;
     390                 :     }
     391             206 :     else if (VEQ(evnt->io_r, pos, len, "DBG"))
     392                 :     {
     393               0 :       vlg_debug(vlg);
     394               0 :       cntl__dbg(evnt->io_w);
     395                 : 
     396               0 :       if (!cntl_waiter_add(evnt, 1, ns1, &stop))
     397               0 :         goto malloc_bad;
     398                 :     }
     399             206 :     else if (VEQ(evnt->io_r, pos, len, "UNDBG"))
     400                 :     {
     401               0 :       vlg_undbg(vlg);
     402               0 :       cntl__dbg(evnt->io_w);
     403                 : 
     404               0 :       if (!cntl_waiter_add(evnt, 1, ns1, &stop))
     405               0 :         goto malloc_bad;
     406                 :     }
     407             206 :     else if (VEQ(evnt->io_r, pos, len, "LIST"))
     408                 :     {
     409              80 :       cntl__scan_events(evnt->io_w, "CONNECT",   evnt_queue("connect"));
     410              80 :       cntl__scan_events(evnt->io_w, "ACCEPT",    evnt_queue("accept"));
     411              80 :       cntl__scan_events(evnt->io_w, "SEND/RECV", evnt_queue("send_recv"));
     412              80 :       cntl__scan_events(evnt->io_w, "RECV",      evnt_queue("recv"));
     413              80 :       cntl__scan_events(evnt->io_w, "NONE",      evnt_queue("none"));
     414              80 :       cntl__scan_events(evnt->io_w, "SEND_NOW",  evnt_queue("send_now"));
     415                 :       
     416              80 :       if (!cntl_waiter_add(evnt, 1, ns1, &stop))
     417               0 :         goto malloc_bad;
     418                 :     }
     419             126 :     else if (VEQ(evnt->io_r, pos, len, "STATUS"))
     420                 :     {
     421             126 :       cntl__status(evnt->io_w);
     422                 : 
     423             126 :       if (!cntl_waiter_add(evnt, 1, ns1, &stop))
     424               0 :         goto malloc_bad;
     425                 :     }
     426                 :     else
     427               0 :       return (FALSE);
     428                 :   
     429             250 :     if (evnt->io_w->conf->malloc_bad)
     430               0 :       goto malloc_bad;
     431                 :     
     432             250 :     evnt_put_pkt(evnt);
     433             250 :     if (!evnt_send_add(evnt, FALSE, 32))
     434               0 :       return (FALSE);
     435                 :   
     436             250 :     vstr_del(evnt->io_r, 1, ns1);
     437                 :   }
     438                 :   
     439             383 :   return (TRUE);
     440                 :   
     441             232 :  malloc_bad:
     442             232 :   evnt->io_r->conf->malloc_bad = FALSE;
     443             232 :   evnt->io_w->conf->malloc_bad = FALSE;
     444             232 :   return (FALSE);
     445                 : }
     446                 : 
     447                 : 
     448                 : static void cntl__cb_func_acpt_free(struct Evnt *evnt)
     449              40 : {
     450              40 :   Acpt_cntl_listener *acpt_listener = (Acpt_cntl_listener *)evnt;
     451              40 :   Acpt_data *acpt_data = acpt_listener->s->ref->ptr;
     452              40 :   Vstr_base *fname = acpt_listener->fname;
     453              40 :   const char *fname_cstr = NULL;
     454                 :   
     455              40 :   evnt_vlg_stats_info(evnt, "ACCEPT CNTL FREE");
     456                 :   
     457              20 :   ASSERT(acpt_cntl_evnt == evnt);
     458              40 :   acpt_cntl_evnt = NULL;
     459                 : 
     460              20 :   ASSERT(acpt_listener->fname);
     461                 :   
     462              40 :   acpt_data->evnt = NULL;
     463              40 :   vstr_ref_del(acpt_listener->s->ref);
     464              40 :   F(acpt_listener);
     465                 :   
     466              40 :   if (!(fname_cstr = vstr_export_cstr_ptr(fname, 1, fname->len)))
     467               0 :     vlg_warn(vlg, "export cntl file($<vstr.all:%p>): %m\n", fname);
     468              40 :   else if (unlink(fname_cstr) == -1)
     469               0 :     vlg_warn(vlg, "unlink cntl file($<vstr.all:%p>): %m\n", fname);
     470              40 :   vstr_free_base(fname);
     471                 :   
     472              40 :   evnt_acpt_close_all();
     473                 :   
     474              40 :   if (childs && !potential_waiters)
     475               0 :     bag_del_all(childs);
     476              40 : }
     477                 : 
     478                 : static struct Evnt *cntl__cb_func_accept(struct Evnt *from_evnt, int fd,
     479                 :                                          struct sockaddr *sa, socklen_t len)
     480             232 : {
     481             232 :   Acpt_listener *acpt_listener = (Acpt_listener *)from_evnt;
     482             232 :   struct Evnt *evnt = NULL;
     483                 :   
     484             116 :   ASSERT(acpt_cntl_evnt);
     485             116 :   ASSERT(acpt_cntl_evnt == from_evnt);
     486             116 :   ASSERT(from_evnt->sa_ref);
     487             116 :   ASSERT(len >= 2);
     488                 :   
     489             232 :   if (sa->sa_family != AF_LOCAL)
     490               0 :     goto valid_family_fail;
     491                 :   
     492             232 :   if (!(evnt = MK(sizeof(struct Evnt))))
     493               0 :     goto mk_acpt_fail;
     494             232 :   if (!evnt_make_acpt_ref(evnt, fd, from_evnt->sa_ref))
     495               0 :     goto make_acpt_fail;
     496                 : 
     497             116 :   assert(EVNT_SA_UN(evnt));
     498                 : 
     499             232 :   vlg_info(vlg, "CNTL CONNECT from[$<sa:%p>]\n", EVNT_SA(evnt));
     500                 : 
     501             232 :   evnt->cbs->cb_func_recv = cntl__cb_func_recv;
     502             232 :   evnt->cbs->cb_func_free = cntl__cb_func_free;
     503                 : 
     504             232 :   evnt->acpt_sa_ref = vstr_ref_add(acpt_listener->ref);
     505                 :   
     506             232 :   ++potential_waiters;
     507                 :   
     508             232 :   return (evnt);
     509                 :   
     510               0 :  make_acpt_fail:
     511               0 :   F(evnt);
     512               0 :   VLG_WARNNOMEM_RET(NULL, (vlg, "%s: %m\n", "accept"));
     513               0 :  mk_acpt_fail:
     514               0 :  valid_family_fail:
     515               0 :   VLG_WARN_RET(NULL, (vlg, "%s: %m\n", "accept"));
     516                 : }
     517                 : 
     518                 : static void cntl__sc_serv_make_acpt_data_cb(Vstr_ref *ref)
     519              44 : { /* FIXME: same as evnt__sc_serv_make_acpt_data_cb */
     520              44 :   struct Acpt_data *ptr = NULL;
     521                 :   
     522              44 :   if (!ref)
     523               0 :     return;
     524                 : 
     525              44 :   ptr = ref->ptr;
     526              44 :   vstr_ref_del(ptr->sa);
     527              44 :   F(ptr);
     528              44 :   free(ref);
     529                 : }
     530                 : 
     531                 : void cntl_make_file(Vlg *passed_vlg, const Vstr_base *fname)
     532              40 : {
     533              40 :   Acpt_listener *acpt_listener = NULL;
     534              40 :   Acpt_cntl_listener *acpt_cntl_listener = NULL;
     535              40 :   Acpt_data *acpt_data = NULL;
     536              40 :   struct Evnt *evnt = NULL;
     537              40 :   Vstr_ref *ref = NULL;
     538              40 :   unsigned int q_listen_len = 8;
     539              40 :   const char *fname_cstr = NULL;
     540                 :   
     541              20 :   ASSERT(!vlg && passed_vlg);
     542                 : 
     543              40 :   vlg = passed_vlg;
     544                 :   
     545              20 :   ASSERT(fname);
     546              20 :   ASSERT(!acpt_cntl_evnt);
     547                 :     
     548              40 :   if (!(fname_cstr = vstr_export_cstr_ptr(fname, 1, fname->len)))
     549               0 :     vlg_err(vlg, EXIT_FAILURE, "cntl file($<vstr.all:%p>): %m\n", fname);
     550                 : 
     551              40 :   if (!(acpt_cntl_listener = MK(sizeof(Acpt_cntl_listener))))
     552               0 :     VLG_ERRNOMEM((vlg, EXIT_FAILURE, "cntl file(%s): %m\n", fname_cstr));
     553              40 :   acpt_cntl_listener->fname = NULL;
     554              40 :   acpt_listener = acpt_cntl_listener->s;
     555              40 :   acpt_listener->max_connections = 0;
     556              40 :   acpt_listener->def_policy = NULL;
     557              40 :   evnt = acpt_listener->evnt;
     558                 :   
     559              40 :   if (!(acpt_cntl_listener->fname = vstr_dup_vstr(fname->conf,
     560                 :                                                   fname, 1, fname->len,
     561                 :                                                   VSTR_TYPE_ADD_DEF)))
     562               0 :     VLG_ERRNOMEM((vlg, EXIT_FAILURE, "cntl file(%s): %m\n", fname_cstr));
     563                 :   
     564              40 :   if (!(acpt_data = MK(sizeof(Acpt_data))))
     565               0 :     VLG_ERRNOMEM((vlg, EXIT_FAILURE, "cntl file(%s): %m\n", fname_cstr));
     566              40 :   acpt_data->evnt = NULL;
     567              40 :   acpt_data->sa   = NULL;
     568                 :   
     569              40 :   if (!(ref = vstr_ref_make_ptr(acpt_data, cntl__sc_serv_make_acpt_data_cb)))
     570               0 :     VLG_ERRNOMEM((vlg, EXIT_FAILURE, "make_bind(%s): %m\n", fname_cstr));
     571              40 :   acpt_listener->ref = ref;
     572                 : 
     573                 :   /* cp vstr for name */
     574              40 :   if (!evnt_make_bind_local(evnt, fname_cstr, q_listen_len))
     575               0 :     vlg_err(vlg, EXIT_FAILURE, "cntl file(%s): %m\n", fname_cstr);
     576              40 :   acpt_data->evnt = evnt;
     577              40 :   acpt_data->sa   = vstr_ref_add(evnt->sa_ref);
     578                 : 
     579              40 :   evnt->cbs->cb_func_accept = cntl__cb_func_accept;
     580              40 :   evnt->cbs->cb_func_free   = cntl__cb_func_acpt_free;
     581                 : 
     582              40 :   acpt_cntl_evnt = evnt;
     583              40 : }
     584                 : 
     585                 : static void cntl__cb_func_cntl_acpt_free(struct Evnt *evnt)
     586               4 : {
     587               4 :   Acpt_cntl_listener *acpt_listener = (Acpt_cntl_listener *)evnt;
     588               4 :   Acpt_data *acpt_data = acpt_listener->s->ref->ptr;
     589                 : 
     590               4 :   evnt_vlg_stats_info(evnt, "CHILD CNTL FREE");
     591                 :   
     592               2 :   ASSERT(acpt_cntl_evnt == evnt);
     593               4 :   acpt_cntl_evnt = NULL;
     594                 :   
     595               2 :   ASSERT(!acpt_listener->fname);
     596                 :   
     597               4 :   acpt_data->evnt = NULL;
     598               4 :   vstr_ref_del(acpt_listener->s->ref);
     599               4 :   vstr_ref_del(acpt_listener->s->def_policy);
     600               4 :   F(acpt_listener);
     601                 :   
     602               4 :   evnt_acpt_close_all();
     603               4 : }
     604                 : 
     605                 : static void cntl__cb_func_pipe_acpt_free(struct Evnt *evnt)
     606               0 : {
     607               0 :   evnt_vlg_stats_info(evnt, "CHILD PIPE FREE");
     608                 :   
     609               0 :   ASSERT(acpt_pipe_evnt == evnt);
     610               0 :   acpt_pipe_evnt = NULL;
     611                 : 
     612               0 :   F(evnt);
     613                 :   
     614               0 :   evnt_acpt_close_all();
     615               0 : }
     616                 : 
     617                 : /* used to get death sig or pass through cntl data */
     618                 : static void cntl_pipe_acpt_fds(Vlg *passed_vlg, int fd, int allow_pdeathsig)
     619               4 : {
     620               2 :   ASSERT(fd != -1);
     621                 : 
     622               4 :   if (acpt_cntl_evnt)
     623                 :   {
     624               4 :     int old_fd = SOCKET_POLL_INDICATOR(acpt_cntl_evnt->ind)->fd;
     625               4 :     Acpt_cntl_listener *acpt_listener = (Acpt_cntl_listener *)acpt_cntl_evnt;
     626                 :     
     627               2 :     ASSERT(vlg       == passed_vlg);
     628                 : 
     629               4 :     if (!evnt_poll_swap_accept_read(acpt_cntl_evnt, fd))
     630               0 :       vlg_abort(vlg, "%s: %m\n", "swap_acpt");
     631                 : 
     632               4 :     close(old_fd);
     633                 :     
     634               4 :     acpt_cntl_evnt->cbs->cb_func_recv = cntl__cb_func_recv;
     635               4 :     acpt_cntl_evnt->cbs->cb_func_free = cntl__cb_func_cntl_acpt_free;
     636                 : 
     637               4 :     vstr_free_base(acpt_listener->fname);
     638               4 :     acpt_listener->fname = NULL;
     639                 :     
     640               4 :     if (allow_pdeathsig && (PROC_CNTL_PDEATHSIG(SIGCHLD) == -1))
     641               0 :       vlg_warn(vlg, "prctl(%s, %s): %m\n", "PR_SET_PDEATHSIG", "SIGCHLD");
     642                 :   }
     643                 :   else
     644                 :   {
     645               0 :     if (!vlg)
     646               0 :       vlg = passed_vlg;
     647               0 :     ASSERT(vlg       == passed_vlg);
     648                 : 
     649               0 :     if (allow_pdeathsig)
     650                 :     {
     651               0 :       if (PROC_CNTL_PDEATHSIG(SIGCHLD) == -1)
     652               0 :         vlg_warn(vlg, "prctl(%s, %s): %m\n", "PR_SET_PDEATHSIG", "SIGCHLD");
     653                 :       else
     654                 :       {
     655               0 :         close(fd);
     656               0 :         return;
     657                 :       }
     658                 :     }
     659                 :     
     660               0 :     if (!(acpt_pipe_evnt = MK(sizeof(struct Evnt))))
     661               0 :       VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "pipe evnt"));
     662                 :     
     663               0 :     if (!evnt_make_custom(acpt_pipe_evnt, fd, 0, 0))
     664               0 :       vlg_err(vlg, EXIT_FAILURE, "%s: %m\n", "pipe evnt");
     665                 :     
     666               0 :     acpt_pipe_evnt->cbs->cb_func_free = cntl__cb_func_pipe_acpt_free;
     667                 :   }
     668                 : }
     669                 : 
     670                 : static void cntl__bag_cb_free_evnt(void *val)
     671               4 : {
     672               4 :   evnt_close(val);
     673               4 : }
     674                 : 
     675                 : static void cntl__bag_cb_free_F(void *val)
     676              18 : {
     677              18 :   F(val);
     678              18 : }
     679                 : 
     680                 : void cntl_child_make(unsigned int num)
     681               4 : {
     682               2 :   ASSERT(!childs && !waiters && acpt_cntl_evnt);
     683                 :   
     684               4 :   if (!(childs  = bag_make(num, bag_cb_free_nothing, cntl__bag_cb_free_evnt)))
     685               0 :     VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "cntl children"));
     686               4 :   if (!(waiters = bag_make(4,   bag_cb_free_nothing, cntl__bag_cb_free_F)))
     687               0 :     VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "cntl children"));
     688               4 : }
     689                 : 
     690                 : void cntl_child_free(void)
     691              48 : {
     692              48 :   bag_free(childs);  childs  = NULL;
     693              48 :   bag_free(waiters); waiters = NULL;
     694              48 : }
     695                 : 
     696                 : static int cntl__cb_func_child_recv(struct Evnt *evnt)
     697              22 : {
     698              22 :   struct Cntl_waiter_obj *val = cntl_waiter_get_first();
     699                 : 
     700              12 :   ASSERT(val);
     701                 :   
     702              22 :   if (!evnt_cb_func_recv(evnt))
     703               0 :     goto malloc_bad;
     704                 : 
     705              93 :   while (evnt->io_r->len)
     706                 :   {
     707              65 :     size_t ns1  = 0;
     708              65 :     size_t pos  = 0;
     709              65 :     size_t len  = 0;
     710              65 :     size_t vpos = 0;
     711              65 :     size_t vlen = 0;
     712              65 :     size_t nse2 = 0;
     713              65 :     int done = FALSE;
     714                 :     
     715              36 :     ASSERT(val);
     716                 :   
     717              65 :     if (!(ns1 = vstr_parse_netstr(evnt->io_r, 1, evnt->io_r->len, &pos, &len)))
     718                 :     {
     719               4 :       if (!(SOCKET_POLL_INDICATOR(evnt->ind)->events & POLLIN))
     720               0 :         return (FALSE);
     721               4 :       return (TRUE);
     722                 :     }
     723                 :     
     724             403 :     while ((nse2 = vstr_parse_netstr(evnt->io_r, pos, len, &vpos, &vlen)))
     725                 :     {
     726             332 :       if (!done && !vlen && (nse2 == len))
     727                 :       {
     728              18 :         cntl_waiter_del(evnt, val);
     729              18 :         vstr_del(evnt->io_r, 1, ns1);
     730              18 :         val = cntl_waiter_get_first();
     731              18 :         break;
     732                 :       }
     733                 :       
     734             314 :       done = TRUE;
     735             314 :       len -= nse2; pos += nse2;
     736                 :     }
     737              61 :     if (nse2)
     738              18 :       continue;
     739                 : 
     740              43 :     if (len)
     741               0 :       VLG_WARN_RET(FALSE, (vlg, "invalid entry\n"));
     742                 : 
     743              43 :     if (!val->evnt)
     744               0 :       vstr_del(evnt->io_r, 1, ns1);
     745                 :     else
     746                 :     {
     747              43 :       struct Evnt *out = val->evnt;
     748                 :       
     749              43 :       if (!vstr_mov(out->io_w, out->io_w->len, evnt->io_r, 1, ns1))
     750               0 :         goto malloc_bad;
     751                 :     }
     752                 :   }
     753                 : 
     754              18 :   return (TRUE);
     755                 :   
     756               0 :  malloc_bad:
     757               0 :   evnt_close(val->evnt);
     758               0 :   evnt->io_r->conf->malloc_bad = FALSE;
     759               0 :   evnt->io_w->conf->malloc_bad = FALSE;
     760               0 :   return (TRUE); /* this is "true" because the app. dies if we kill this con */
     761                 : }
     762                 : 
     763                 : static void cntl__cb_func_child_free(struct Evnt *evnt)
     764               4 : {
     765               4 :   if (childs)
     766                 :   {
     767               4 :     const Bag_obj *obj = bag_srch_eq(childs, bag_cb_srch_eq_val_ptr, evnt);
     768                 :     
     769               4 :     if (obj) /* FIXME: const cast */
     770               0 :       ((Bag_obj *)obj)->val = NULL;
     771                 :   }
     772                 :   
     773               4 :   F(evnt);
     774               4 : }
     775                 : 
     776                 : void cntl_child_pid(pid_t pid, int fd)
     777               4 : {
     778               4 :   struct Cntl_child_obj *obj = NULL;
     779                 : 
     780               2 :   ASSERT(acpt_cntl_evnt);
     781                 :     
     782               4 :   if (!(obj = MK(sizeof(struct Cntl_child_obj))))
     783               0 :     VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "cntl children"));
     784                 : 
     785               4 :   obj->pid = pid;
     786                 :   
     787               4 :   if (!evnt_make_custom(obj->evnt, fd, 0, POLLIN))
     788               0 :     vlg_err(vlg, EXIT_FAILURE, "%s: %m\n", "cntl children");
     789                 : 
     790               4 :   obj->evnt->cbs->cb_func_free = cntl__cb_func_child_free;
     791               4 :   obj->evnt->cbs->cb_func_recv = cntl__cb_func_child_recv;
     792                 :   
     793               4 :   if (!(childs = bag_add_obj(childs, NULL, obj)))
     794               0 :     VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "cntl children"));
     795               4 : }
     796                 : 
     797                 : /* Here we fork multiple procs. however:
     798                 :  *
     799                 :  *  If we have a cntl connection we keep two way communication open with the
     800                 :  * children.
     801                 :  *
     802                 :  *  If not we "leak" the writable side of the pipe() fd in the parent,
     803                 :  * which will cause an error on all the children's fd when the parent dies.
     804                 :  *
     805                 :  *  The children also kill themselves if the parent fd has an error.
     806                 :  */
     807                 : void cntl_sc_multiproc(Vlg *passed_vlg, 
     808                 :                        unsigned int num, int use_cntl, int allow_pdeathsig)
     809               4 : {
     810               4 :   int pfds[2] = {-1, -1};
     811                 :   
     812               4 :   if (!vlg)
     813               0 :     vlg = passed_vlg;
     814                 : 
     815               2 :   ASSERT(vlg == passed_vlg);
     816                 :   
     817               4 :   vlg_pid_set(vlg, TRUE);
     818                 :   
     819               4 :   if (!use_cntl && (pipe(pfds) == -1))
     820               0 :     vlg_err(vlg, EXIT_FAILURE, "pipe(): %m\n");
     821                 : 
     822               4 :   if (use_cntl)
     823               4 :     cntl_child_make(num - 1);
     824                 :   
     825              10 :   while (--num)
     826                 :   {
     827               4 :     pid_t cpid = -1;
     828                 :       
     829               4 :     if (use_cntl && (socketpair(PF_LOCAL, SOCK_STREAM, IPPROTO_IP, pfds) == -1))
     830               0 :       vlg_err(vlg, EXIT_FAILURE, "socketpair(): %m\n");
     831                 : 
     832               4 :     if ((cpid = evnt_make_child()) == -1)
     833               0 :       vlg_err(vlg, EXIT_FAILURE, "fork(): %m\n");
     834                 : 
     835              10 :     if (use_cntl && cpid) /* parent */
     836                 :     {
     837               4 :       close(pfds[0]);
     838               4 :       cntl_child_pid(cpid, pfds[1]);
     839                 :     }
     840               4 :     else if (!cpid)
     841                 :     { /* child */
     842               4 :       close(pfds[1]);
     843               4 :       cntl_child_free();
     844               4 :       cntl_pipe_acpt_fds(vlg, pfds[0], allow_pdeathsig);
     845                 :       
     846               4 :       evnt_scan_q_close();
     847               4 :       return;
     848                 :     }
     849                 :   }
     850                 : 
     851               4 :   if (!use_cntl)
     852               0 :     close(pfds[0]); /* close child pipe() */
     853                 :   
     854               4 :   evnt_scan_q_close();
     855                 : }
     856                 : 

Generated by: LTP GCOV extension version 1.4