xref: /freebsd/contrib/ntp/libntp/ntp_worker.c (revision 4990d495fcc77c51b3f46c91ba3a064b565afae0)
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