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 :
|