12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert * ntp_worker.c
32b15cb3dSCy Schubert */
42b15cb3dSCy Schubert #include <config.h>
52b15cb3dSCy Schubert #include "ntp_workimpl.h"
62b15cb3dSCy Schubert
72b15cb3dSCy Schubert #ifdef WORKER
82b15cb3dSCy Schubert
92b15cb3dSCy Schubert #include <stdio.h>
102b15cb3dSCy Schubert #include <ctype.h>
112b15cb3dSCy Schubert #include <signal.h>
122b15cb3dSCy Schubert
132b15cb3dSCy Schubert #include "iosignal.h"
142b15cb3dSCy Schubert #include "ntp_stdlib.h"
152b15cb3dSCy Schubert #include "ntp_malloc.h"
162b15cb3dSCy Schubert #include "ntp_syslog.h"
172b15cb3dSCy Schubert #include "ntpd.h"
182b15cb3dSCy Schubert #include "ntp_io.h"
192b15cb3dSCy Schubert #include "ntp_assert.h"
202b15cb3dSCy Schubert #include "ntp_unixtime.h"
212b15cb3dSCy Schubert #include "intreswork.h"
222b15cb3dSCy Schubert
232b15cb3dSCy Schubert
242b15cb3dSCy Schubert #define CHILD_MAX_IDLE (3 * 60) /* seconds, idle worker limit */
252b15cb3dSCy Schubert
262b15cb3dSCy Schubert blocking_child ** blocking_children;
272b15cb3dSCy Schubert size_t blocking_children_alloc;
282b15cb3dSCy Schubert int worker_per_query; /* boolean */
292b15cb3dSCy Schubert int intres_req_pending;
3068ba7e87SXin LI volatile u_int blocking_child_ready_seen;
3168ba7e87SXin LI volatile u_int blocking_child_ready_done;
322b15cb3dSCy Schubert
332b15cb3dSCy Schubert
342b15cb3dSCy Schubert #ifndef HAVE_IO_COMPLETION_PORT
352b15cb3dSCy Schubert /*
362b15cb3dSCy Schubert * pipe_socketpair()
372b15cb3dSCy Schubert *
382b15cb3dSCy Schubert * Provides an AF_UNIX socketpair on systems which have them, otherwise
392b15cb3dSCy Schubert * pair of unidirectional pipes.
402b15cb3dSCy Schubert */
412b15cb3dSCy Schubert int
pipe_socketpair(int caller_fds[2],int * is_pipe)422b15cb3dSCy Schubert pipe_socketpair(
432b15cb3dSCy Schubert int caller_fds[2],
442b15cb3dSCy Schubert int * is_pipe
452b15cb3dSCy Schubert )
462b15cb3dSCy Schubert {
472b15cb3dSCy Schubert int rc;
482b15cb3dSCy Schubert int fds[2];
492b15cb3dSCy Schubert int called_pipe;
502b15cb3dSCy Schubert
512b15cb3dSCy Schubert #ifdef HAVE_SOCKETPAIR
522b15cb3dSCy Schubert rc = socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]);
532b15cb3dSCy Schubert #else
542b15cb3dSCy Schubert rc = -1;
552b15cb3dSCy Schubert #endif
562b15cb3dSCy Schubert
572b15cb3dSCy Schubert if (-1 == rc) {
582b15cb3dSCy Schubert rc = pipe(&fds[0]);
592b15cb3dSCy Schubert called_pipe = TRUE;
602b15cb3dSCy Schubert } else {
612b15cb3dSCy Schubert called_pipe = FALSE;
622b15cb3dSCy Schubert }
632b15cb3dSCy Schubert
642b15cb3dSCy Schubert if (-1 == rc)
652b15cb3dSCy Schubert return rc;
662b15cb3dSCy Schubert
672b15cb3dSCy Schubert caller_fds[0] = fds[0];
682b15cb3dSCy Schubert caller_fds[1] = fds[1];
692b15cb3dSCy Schubert if (is_pipe != NULL)
702b15cb3dSCy Schubert *is_pipe = called_pipe;
712b15cb3dSCy Schubert
722b15cb3dSCy Schubert return 0;
732b15cb3dSCy Schubert }
742b15cb3dSCy Schubert
752b15cb3dSCy Schubert
762b15cb3dSCy Schubert /*
772b15cb3dSCy Schubert * close_all_except()
782b15cb3dSCy Schubert *
792b15cb3dSCy Schubert * Close all file descriptors except the given keep_fd.
802b15cb3dSCy Schubert */
812b15cb3dSCy Schubert void
close_all_except(int keep_fd)822b15cb3dSCy Schubert close_all_except(
832b15cb3dSCy Schubert int keep_fd
842b15cb3dSCy Schubert )
852b15cb3dSCy Schubert {
862b15cb3dSCy Schubert int fd;
872b15cb3dSCy Schubert
882b15cb3dSCy Schubert for (fd = 0; fd < keep_fd; fd++)
892b15cb3dSCy Schubert close(fd);
902b15cb3dSCy Schubert
912b15cb3dSCy Schubert close_all_beyond(keep_fd);
922b15cb3dSCy Schubert }
932b15cb3dSCy Schubert
942b15cb3dSCy Schubert
952b15cb3dSCy Schubert /*
962b15cb3dSCy Schubert * close_all_beyond()
972b15cb3dSCy Schubert *
982b15cb3dSCy Schubert * Close all file descriptors after the given keep_fd, which is the
992b15cb3dSCy Schubert * highest fd to keep open.
1002b15cb3dSCy Schubert */
1012b15cb3dSCy Schubert void
close_all_beyond(int keep_fd)1022b15cb3dSCy Schubert close_all_beyond(
1032b15cb3dSCy Schubert int keep_fd
1042b15cb3dSCy Schubert )
1052b15cb3dSCy Schubert {
1062b15cb3dSCy Schubert # ifdef HAVE_CLOSEFROM
1072b15cb3dSCy Schubert closefrom(keep_fd + 1);
1082b15cb3dSCy Schubert # elif defined(F_CLOSEM)
1092b15cb3dSCy Schubert /*
1102b15cb3dSCy Schubert * From 'Writing Reliable AIX Daemons,' SG24-4946-00,
1112b15cb3dSCy Schubert * by Eric Agar (saves us from doing 32767 system
1122b15cb3dSCy Schubert * calls)
1132b15cb3dSCy Schubert */
1142b15cb3dSCy Schubert if (fcntl(keep_fd + 1, F_CLOSEM, 0) == -1)
1152b15cb3dSCy Schubert msyslog(LOG_ERR, "F_CLOSEM(%d): %m", keep_fd + 1);
1162b15cb3dSCy Schubert # else /* !HAVE_CLOSEFROM && !F_CLOSEM follows */
1172b15cb3dSCy Schubert int fd;
1182b15cb3dSCy Schubert int max_fd;
1192b15cb3dSCy Schubert
1202b15cb3dSCy Schubert max_fd = GETDTABLESIZE();
1212b15cb3dSCy Schubert for (fd = keep_fd + 1; fd < max_fd; fd++)
1222b15cb3dSCy Schubert close(fd);
1232b15cb3dSCy Schubert # endif /* !HAVE_CLOSEFROM && !F_CLOSEM */
1242b15cb3dSCy Schubert }
1252b15cb3dSCy Schubert #endif /* HAVE_IO_COMPLETION_PORT */
1262b15cb3dSCy Schubert
1272b15cb3dSCy Schubert
1282b15cb3dSCy Schubert u_int
available_blocking_child_slot(void)1292b15cb3dSCy Schubert available_blocking_child_slot(void)
1302b15cb3dSCy Schubert {
1312b15cb3dSCy Schubert const size_t each = sizeof(blocking_children[0]);
1322b15cb3dSCy Schubert u_int slot;
1332b15cb3dSCy Schubert size_t prev_alloc;
1342b15cb3dSCy Schubert size_t new_alloc;
1352b15cb3dSCy Schubert size_t prev_octets;
1362b15cb3dSCy Schubert size_t octets;
1372b15cb3dSCy Schubert
1382b15cb3dSCy Schubert for (slot = 0; slot < blocking_children_alloc; slot++) {
1392b15cb3dSCy Schubert if (NULL == blocking_children[slot])
1402b15cb3dSCy Schubert return slot;
1412b15cb3dSCy Schubert if (blocking_children[slot]->reusable) {
1422b15cb3dSCy Schubert blocking_children[slot]->reusable = FALSE;
1432b15cb3dSCy Schubert return slot;
1442b15cb3dSCy Schubert }
1452b15cb3dSCy Schubert }
1462b15cb3dSCy Schubert
1472b15cb3dSCy Schubert prev_alloc = blocking_children_alloc;
1482b15cb3dSCy Schubert prev_octets = prev_alloc * each;
1492b15cb3dSCy Schubert new_alloc = blocking_children_alloc + 4;
1502b15cb3dSCy Schubert octets = new_alloc * each;
1512b15cb3dSCy Schubert blocking_children = erealloc_zero(blocking_children, octets,
1522b15cb3dSCy Schubert prev_octets);
1532b15cb3dSCy Schubert blocking_children_alloc = new_alloc;
1542b15cb3dSCy Schubert
1553311ff84SXin LI /* assume we'll never have enough workers to overflow u_int */
1563311ff84SXin LI return (u_int)prev_alloc;
1572b15cb3dSCy Schubert }
1582b15cb3dSCy Schubert
1592b15cb3dSCy Schubert
1602b15cb3dSCy Schubert int
queue_blocking_request(blocking_work_req rtype,void * req,size_t reqsize,blocking_work_callback done_func,void * context)1612b15cb3dSCy Schubert queue_blocking_request(
1622b15cb3dSCy Schubert blocking_work_req rtype,
1632b15cb3dSCy Schubert void * req,
1642b15cb3dSCy Schubert size_t reqsize,
1652b15cb3dSCy Schubert blocking_work_callback done_func,
1662b15cb3dSCy Schubert void * context
1672b15cb3dSCy Schubert )
1682b15cb3dSCy Schubert {
1692b15cb3dSCy Schubert static u_int intres_slot = UINT_MAX;
1702b15cb3dSCy Schubert u_int child_slot;
1712b15cb3dSCy Schubert blocking_child * c;
1722b15cb3dSCy Schubert blocking_pipe_header req_hdr;
1732b15cb3dSCy Schubert
1742b15cb3dSCy Schubert req_hdr.octets = sizeof(req_hdr) + reqsize;
1752b15cb3dSCy Schubert req_hdr.magic_sig = BLOCKING_REQ_MAGIC;
1762b15cb3dSCy Schubert req_hdr.rtype = rtype;
1772b15cb3dSCy Schubert req_hdr.done_func = done_func;
1782b15cb3dSCy Schubert req_hdr.context = context;
1792b15cb3dSCy Schubert
1802b15cb3dSCy Schubert child_slot = UINT_MAX;
1812b15cb3dSCy Schubert if (worker_per_query || UINT_MAX == intres_slot ||
1822b15cb3dSCy Schubert blocking_children[intres_slot]->reusable)
1832b15cb3dSCy Schubert child_slot = available_blocking_child_slot();
1842b15cb3dSCy Schubert if (!worker_per_query) {
1852b15cb3dSCy Schubert if (UINT_MAX == intres_slot)
1862b15cb3dSCy Schubert intres_slot = child_slot;
1872b15cb3dSCy Schubert else
1882b15cb3dSCy Schubert child_slot = intres_slot;
1892b15cb3dSCy Schubert if (0 == intres_req_pending)
1902b15cb3dSCy Schubert intres_timeout_req(0);
1912b15cb3dSCy Schubert }
1922b15cb3dSCy Schubert intres_req_pending++;
1932b15cb3dSCy Schubert INSIST(UINT_MAX != child_slot);
1942b15cb3dSCy Schubert c = blocking_children[child_slot];
1952b15cb3dSCy Schubert if (NULL == c) {
1962b15cb3dSCy Schubert c = emalloc_zero(sizeof(*c));
1972b15cb3dSCy Schubert #ifdef WORK_FORK
1982b15cb3dSCy Schubert c->req_read_pipe = -1;
1992b15cb3dSCy Schubert c->req_write_pipe = -1;
2002b15cb3dSCy Schubert #endif
2012b15cb3dSCy Schubert #ifdef WORK_PIPE
2022b15cb3dSCy Schubert c->resp_read_pipe = -1;
2032b15cb3dSCy Schubert c->resp_write_pipe = -1;
2042b15cb3dSCy Schubert #endif
2052b15cb3dSCy Schubert blocking_children[child_slot] = c;
2062b15cb3dSCy Schubert }
2072b15cb3dSCy Schubert req_hdr.child_idx = child_slot;
2082b15cb3dSCy Schubert
2092b15cb3dSCy Schubert return send_blocking_req_internal(c, &req_hdr, req);
2102b15cb3dSCy Schubert }
2112b15cb3dSCy Schubert
2122b15cb3dSCy Schubert
queue_blocking_response(blocking_child * c,blocking_pipe_header * resp,size_t respsize,const blocking_pipe_header * req)2132b15cb3dSCy Schubert int queue_blocking_response(
2142b15cb3dSCy Schubert blocking_child * c,
2152b15cb3dSCy Schubert blocking_pipe_header * resp,
2162b15cb3dSCy Schubert size_t respsize,
2172b15cb3dSCy Schubert const blocking_pipe_header * req
2182b15cb3dSCy Schubert )
2192b15cb3dSCy Schubert {
2202b15cb3dSCy Schubert resp->octets = respsize;
2212b15cb3dSCy Schubert resp->magic_sig = BLOCKING_RESP_MAGIC;
2222b15cb3dSCy Schubert resp->rtype = req->rtype;
2232b15cb3dSCy Schubert resp->context = req->context;
2242b15cb3dSCy Schubert resp->done_func = req->done_func;
2252b15cb3dSCy Schubert
2262b15cb3dSCy Schubert return send_blocking_resp_internal(c, resp);
2272b15cb3dSCy Schubert }
2282b15cb3dSCy Schubert
2292b15cb3dSCy Schubert
2302b15cb3dSCy Schubert void
process_blocking_resp(blocking_child * c)2312b15cb3dSCy Schubert process_blocking_resp(
2322b15cb3dSCy Schubert blocking_child * c
2332b15cb3dSCy Schubert )
2342b15cb3dSCy Schubert {
2352b15cb3dSCy Schubert blocking_pipe_header * resp;
2362b15cb3dSCy Schubert void * data;
2372b15cb3dSCy Schubert
2382b15cb3dSCy Schubert /*
2392b15cb3dSCy Schubert * On Windows send_blocking_resp_internal() may signal the
2402b15cb3dSCy Schubert * blocking_response_ready event multiple times while we're
2412b15cb3dSCy Schubert * processing a response, so always consume all available
2422b15cb3dSCy Schubert * responses before returning to test the event again.
2432b15cb3dSCy Schubert */
2442b15cb3dSCy Schubert #ifdef WORK_THREAD
2452b15cb3dSCy Schubert do {
2462b15cb3dSCy Schubert #endif
2472b15cb3dSCy Schubert resp = receive_blocking_resp_internal(c);
2482b15cb3dSCy Schubert if (NULL != resp) {
2492b15cb3dSCy Schubert DEBUG_REQUIRE(BLOCKING_RESP_MAGIC ==
2502b15cb3dSCy Schubert resp->magic_sig);
2512b15cb3dSCy Schubert data = (char *)resp + sizeof(*resp);
2522b15cb3dSCy Schubert intres_req_pending--;
2532b15cb3dSCy Schubert (*resp->done_func)(resp->rtype, resp->context,
2542b15cb3dSCy Schubert resp->octets - sizeof(*resp),
2552b15cb3dSCy Schubert data);
2562b15cb3dSCy Schubert free(resp);
2572b15cb3dSCy Schubert }
2582b15cb3dSCy Schubert #ifdef WORK_THREAD
2592b15cb3dSCy Schubert } while (NULL != resp);
2602b15cb3dSCy Schubert #endif
2612b15cb3dSCy Schubert if (!worker_per_query && 0 == intres_req_pending)
2622b15cb3dSCy Schubert intres_timeout_req(CHILD_MAX_IDLE);
2632b15cb3dSCy Schubert else if (worker_per_query)
2642b15cb3dSCy Schubert req_child_exit(c);
2652b15cb3dSCy Schubert }
2662b15cb3dSCy Schubert
26768ba7e87SXin LI void
harvest_blocking_responses(void)26868ba7e87SXin LI harvest_blocking_responses(void)
26968ba7e87SXin LI {
270*4990d495SXin LI size_t idx;
27168ba7e87SXin LI blocking_child* cp;
27268ba7e87SXin LI u_int scseen, scdone;
27368ba7e87SXin LI
27468ba7e87SXin LI scseen = blocking_child_ready_seen;
27568ba7e87SXin LI scdone = blocking_child_ready_done;
27668ba7e87SXin LI if (scdone != scseen) {
27768ba7e87SXin LI blocking_child_ready_done = scseen;
27868ba7e87SXin LI for (idx = 0; idx < blocking_children_alloc; idx++) {
27968ba7e87SXin LI cp = blocking_children[idx];
28068ba7e87SXin LI if (NULL == cp)
28168ba7e87SXin LI continue;
28268ba7e87SXin LI scseen = cp->resp_ready_seen;
28368ba7e87SXin LI scdone = cp->resp_ready_done;
28468ba7e87SXin LI if (scdone != scseen) {
28568ba7e87SXin LI cp->resp_ready_done = scseen;
28668ba7e87SXin LI process_blocking_resp(cp);
28768ba7e87SXin LI }
28868ba7e87SXin LI }
28968ba7e87SXin LI }
29068ba7e87SXin LI }
29168ba7e87SXin LI
2922b15cb3dSCy Schubert
2932b15cb3dSCy Schubert /*
2942b15cb3dSCy Schubert * blocking_child_common runs as a forked child or a thread
2952b15cb3dSCy Schubert */
2962b15cb3dSCy Schubert int
blocking_child_common(blocking_child * c)2972b15cb3dSCy Schubert blocking_child_common(
2982b15cb3dSCy Schubert blocking_child *c
2992b15cb3dSCy Schubert )
3002b15cb3dSCy Schubert {
3012b15cb3dSCy Schubert int say_bye;
3022b15cb3dSCy Schubert blocking_pipe_header *req;
3032b15cb3dSCy Schubert
3042b15cb3dSCy Schubert say_bye = FALSE;
3052b15cb3dSCy Schubert while (!say_bye) {
3062b15cb3dSCy Schubert req = receive_blocking_req_internal(c);
3072b15cb3dSCy Schubert if (NULL == req) {
3082b15cb3dSCy Schubert say_bye = TRUE;
3099034852cSGleb Smirnoff continue;
3102b15cb3dSCy Schubert }
3112b15cb3dSCy Schubert
3122b15cb3dSCy Schubert DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == req->magic_sig);
3132b15cb3dSCy Schubert
3142b15cb3dSCy Schubert switch (req->rtype) {
3152b15cb3dSCy Schubert case BLOCKING_GETADDRINFO:
3162b15cb3dSCy Schubert if (blocking_getaddrinfo(c, req))
3172b15cb3dSCy Schubert say_bye = TRUE;
3182b15cb3dSCy Schubert break;
3192b15cb3dSCy Schubert
3202b15cb3dSCy Schubert case BLOCKING_GETNAMEINFO:
3212b15cb3dSCy Schubert if (blocking_getnameinfo(c, req))
3222b15cb3dSCy Schubert say_bye = TRUE;
3232b15cb3dSCy Schubert break;
3242b15cb3dSCy Schubert
3252b15cb3dSCy Schubert default:
3262b15cb3dSCy Schubert msyslog(LOG_ERR, "unknown req %d to blocking worker", req->rtype);
3272b15cb3dSCy Schubert say_bye = TRUE;
3282b15cb3dSCy Schubert }
3292b15cb3dSCy Schubert
3302b15cb3dSCy Schubert free(req);
3312b15cb3dSCy Schubert }
3322b15cb3dSCy Schubert
3332b15cb3dSCy Schubert return 0;
3342b15cb3dSCy Schubert }
3352b15cb3dSCy Schubert
3362b15cb3dSCy Schubert
3372b15cb3dSCy Schubert /*
3382b15cb3dSCy Schubert * worker_idle_timer_fired()
3392b15cb3dSCy Schubert *
3402b15cb3dSCy Schubert * The parent starts this timer when the last pending response has been
3412b15cb3dSCy Schubert * received from the child, making it idle, and clears the timer when a
3422b15cb3dSCy Schubert * request is dispatched to the child. Once the timer expires, the
3432b15cb3dSCy Schubert * child is sent packing.
3442b15cb3dSCy Schubert *
3452b15cb3dSCy Schubert * This is called when worker_idle_timer is nonzero and less than or
3462b15cb3dSCy Schubert * equal to current_time.
3472b15cb3dSCy Schubert */
3482b15cb3dSCy Schubert void
worker_idle_timer_fired(void)3492b15cb3dSCy Schubert worker_idle_timer_fired(void)
3502b15cb3dSCy Schubert {
3512b15cb3dSCy Schubert u_int idx;
3522b15cb3dSCy Schubert blocking_child * c;
3532b15cb3dSCy Schubert
3542b15cb3dSCy Schubert DEBUG_REQUIRE(0 == intres_req_pending);
3552b15cb3dSCy Schubert
3562b15cb3dSCy Schubert intres_timeout_req(0);
3572b15cb3dSCy Schubert for (idx = 0; idx < blocking_children_alloc; idx++) {
3582b15cb3dSCy Schubert c = blocking_children[idx];
3592b15cb3dSCy Schubert if (NULL == c)
3602b15cb3dSCy Schubert continue;
3612b15cb3dSCy Schubert req_child_exit(c);
3622b15cb3dSCy Schubert }
3632b15cb3dSCy Schubert }
3642b15cb3dSCy Schubert
3652b15cb3dSCy Schubert
3662b15cb3dSCy Schubert #else /* !WORKER follows */
3672b15cb3dSCy Schubert int ntp_worker_nonempty_compilation_unit;
3682b15cb3dSCy Schubert #endif
369