[Git][NTPsec/ntpsec][master] Big DNS cleanup

Hal Murray gitlab at mg.gitlab.com
Fri Apr 14 04:58:35 UTC 2017


Hal Murray pushed to branch master at NTPsec / ntpsec


Commits:
1d40226e by Hal Murray at 2017-04-13T21:51:51-07:00
Big DNS cleanup

- - - - -


20 changed files:

- devel/ifdex-ignores
- − include/intreswork.h
- include/ntp.h
- + include/ntp_dns.h
- − include/ntp_intres.h
- include/ntp_io.h
- − include/ntp_worker.h
- − include/ntp_workimpl.h
- include/ntpd.h
- − libntp/ntp_intres.c
- − libntp/ntp_worker.c
- − libntp/work_thread.c
- libntp/wscript
- ntpd/ntp_config.c
- ntpd/ntp_io.c
- ntpd/ntp_peer.c
- ntpd/ntp_proto.c
- ntpd/ntp_sandbox.c
- ntpd/ntp_timer.c
- ntpd/ntpd.c


Changes:

=====================================
devel/ifdex-ignores
=====================================
--- a/devel/ifdex-ignores
+++ b/devel/ifdex-ignores
@@ -157,11 +157,6 @@ USE_SCM_BINTIME		# to grab timestamp for recv packet
 USE_SCM_TIMESTAMP	# "
 USE_SCM_TIMESTAMPNS	# "
 
-USE_WORKER		# Asynchronous DNS available, needs pthreads
-USE_WORK_PIPE		# Set in ntp_workimpl.h
-USE_WORK_THREAD
-
-
 USE_IPV6_MULTICAST_SUPPORT
 USE_LIFC_FAMILY
 USE_LIFC_FLAGS


=====================================
include/intreswork.h deleted
=====================================
--- a/include/intreswork.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * intreswork.h -- declarations private to ntp_intres.c, ntp_worker.c.
- */
-#ifndef GUARD_INTRESWORK_H
-#define GUARD_INTRESWORK_H
-
-#include "ntp_worker.h"
-
-#ifdef USE_WORKER
-
-extern int blocking_getaddrinfo(blocking_child *,
-				blocking_pipe_header *);
-extern int blocking_getnameinfo(blocking_child *,
-				blocking_pipe_header *);
-
-#endif	/* USE_WORKER */
-
-#endif	/* GUARD_INTRESWORK_H */


=====================================
include/ntp.h
=====================================
--- a/include/ntp.h
+++ b/include/ntp.h
@@ -232,8 +232,6 @@ struct peer {
 	struct peer *ilink;	/* list of peers for interface */
 	sockaddr_u srcadr;	/* address of remote host */
 	char *	hostname;	/* if non-NULL, remote name */
-	struct addrinfo *addrs;	/* hostname query result */
-	struct addrinfo *ai;	/* position within addrs */
 	endpt *	dstadr;		/* local address */
 	associd_t associd;	/* association ID */
 	uint8_t	version;	/* version number */
@@ -359,6 +357,7 @@ struct peer {
  * MODE_BROADCAST and MODE_BCLIENT appear in the transition
  * function. MODE_CONTROL and MODE_PRIVATE can appear in packets,
  * but those never survive to the translation function.
+ * See MATCH_ASSOC in ntp_peer.
  */
 #define	MODE_UNSPEC	0	/* unspecified (old version) */
 #define	MODE_ACTIVE	1	/* symmetric active mode */
@@ -370,8 +369,8 @@ struct peer {
 /*
  * These can appear in packets
  */
-#define	MODE_CONTROL	6	/* control mode */
-#define	MODE_PRIVATE	7	/* Dead: private mode, ntpdc */
+#define	MODE_CONTROL	6	/* control mode, ntpq*/
+#define	MODE_PRIVATE	7	/* Dead: private mode, was ntpdc */
 /*
  * This is a madeup mode for broadcast client.  No longer used by ntpd.
  */
@@ -404,6 +403,7 @@ struct peer {
 #define	FLAG_IBURST	0x0100	/* initial burst mode */
 #define	FLAG_NOSELECT	0x0200	/* never select */
 #define	FLAG_TRUE	0x0400	/* force truechimer */
+#define	FLAG_DNS	0x0800	/* needs DNS lookup */
 #define FLAG_TSTAMP_PPS	0x4cd000	/* PPS source provides absolute timestamp */
 
 
@@ -646,11 +646,11 @@ struct mon_data {
  * only MDF_UCAST and MDF_BCAST.
  */
 #define	MDF_UCAST	0x01	/* unicast client */
-#define	MDF_MCAST	0x02	/* multicast server (not used) */
+/* #define MDF_MCAST	0x02	** multicast server (not used) */
 #define	MDF_BCAST	0x04	/* broadcast server */
 #define	MDF_POOL	0x08	/* pool client solicitor */
-#define MDF_ACAST	0x10	/* manycast client solicitor (not used) */
-#define	MDF_BCLNT	0x20	/* eph. broadcast/multicast client (not used) */
+/* #define MDF_ACAST	0x10	** manycast client solicitor (not used) */
+#define	MDF_BCLNT	0x20	/* eph. broadcast/multicast client */
 #define MDF_UCLNT	0x40	/* preemptible manycast or pool client */
 /*
  * In the context of struct peer in ntpd, one cast_flags bit


=====================================
include/ntp_dns.h
=====================================
--- /dev/null
+++ b/include/ntp_dns.h
@@ -0,0 +1,26 @@
+/*
+ * ntp_dns.h - client interface to DNS name resolution.
+ */
+#ifndef GUARD_NTP_DNS_H
+#define GUARD_NTP_DNS_H
+
+/* Get addrinfo */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+
+#define	INITIAL_DNS_RETRY	2	/* seconds between queries */
+
+/* start DNS query (unless busy) */
+extern bool dns_probe(struct peer*);
+
+/* Process answers */
+extern void server_take_dns(struct peer*, struct addrinfo*);
+extern void pool_take_dns(struct peer*, struct addrinfo*);
+
+extern void dns_check(void);	/* called by main thread */
+extern void dns_cancel(struct peer*);
+extern void dns_new_interface(void);
+
+#endif	/* GUARD_NTP_DNS_H */


=====================================
include/ntp_intres.h deleted
=====================================
--- a/include/ntp_intres.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * ntp_intres.h - client interface to blocking-worker name resolution.
- */
-#ifndef GUARD_NTP_INTRES_H
-#define GUARD_NTP_INTRES_H
-
-#include "ntp_worker.h"
-#include "ntp_malloc.h"
-
-struct addrinfo *copy_addrinfo_impl(const struct addrinfo *
-#ifdef EREALLOC_CALLSITE	/* from ntp_malloc.h */
-							   ,
-				    const char *, int
-#endif
-					 );
-struct addrinfo *copy_addrinfo_list_impl(const struct addrinfo *
-#ifdef EREALLOC_CALLSITE	/* from ntp_malloc.h */
-								,
-					 const char *, int
-#endif
-					 );
-#ifdef EREALLOC_CALLSITE
-# define copy_addrinfo(l) \
-	 copy_addrinfo_impl((l), __FILE__, __LINE__)
-# define copy_addrinfo_list(l) \
-	 copy_addrinfo_list_impl((l), __FILE__, __LINE__)
-#else
-# define copy_addrinfo(l)	copy_addrinfo_impl(l)
-# define copy_addrinfo_list(l)	copy_addrinfo_list_impl(l)
-#endif
-
-#ifdef USE_WORKER
-#define	INITIAL_DNS_RETRY	2	/* seconds between queries */
-
-/*
- * you call getaddrinfo_sometime(name, service, &hints, retry, callback_func, context);
- * later (*callback_func)(rescode, gai_errno, context, name, service, hints, ai_result) is called.
- */
-typedef void	(*gai_sometime_callback)
-		    (int, int, void *, const char *, const char *,
-		     const struct addrinfo *, const struct addrinfo *);
-extern int	getaddrinfo_sometime(const char *, const char *,
-				     const struct addrinfo *, int,
-				     gai_sometime_callback, void *);
-/*
- * In gai_sometime_callback routines, the resulting addrinfo list is
- * only available until the callback returns.  To hold on to the list
- * of addresses after the callback returns, use copy_addrinfo_list():
- *
- * struct addrinfo *copy_addrinfo_list(const struct addrinfo *);
- */
-
-
-/*
- * you call getnameinfo_sometime(sockaddr, namelen, servlen, flags, callback_func, context);
- * later (*callback_func)(rescode, gni_errno, sockaddr, flags, name, service, context) is called.
- */
-typedef void	(*gni_sometime_callback)
-		    (int, int, sockaddr_u *, int, const char *,
-		     const char *, void *);
-extern int getnameinfo_sometime(sockaddr_u *, size_t, size_t, int,
-				gni_sometime_callback, void *);
-#endif	/* USE_WORKER */
-
-/* intres_timeout_req() is provided by the client, ntpd or ntpdig. */
-extern void intres_timeout_req(u_int);
-
-#endif	/* GUARD_NTP_INTRES_H */


=====================================
include/ntp_io.h
=====================================
--- a/include/ntp_io.h
+++ b/include/ntp_io.h
@@ -1,8 +1,6 @@
 #ifndef GUARD_NTP_IO_H
 #define GUARD_NTP_IO_H
 
-#include "ntp_workimpl.h"
-
 /*
  * POSIX says use <fnctl.h> to get O_* symbols and
  * SEEK_SET symbol form <unistd.h>.
@@ -43,7 +41,6 @@ extern void	sau_from_netaddr(sockaddr_u *, const isc_netaddr_t *);
 extern void	add_nic_rule(nic_rule_match match_type,
 			     const char *if_name, int prefixlen,
 			     nic_rule_action action);
-extern	void	maintain_activefds(int fd, int closing);
 extern void	make_socket_nonblocking( SOCKET fd );
 extern SOCKET	move_fd( SOCKET fd );
 


=====================================
include/ntp_worker.h deleted
=====================================
--- a/include/ntp_worker.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * ntp_worker.h
- */
-
-#ifndef GUARD_NTP_WORKER_H
-#define GUARD_NTP_WORKER_H
-
-#include "ntp_workimpl.h"
-
-/* XXX: Why does OpenBSD need pthread.h here? */
-#ifdef PLATFORM_OPENBSD
-#include <pthread.h>
-#endif
-
-#ifdef USE_WORKER
-# if defined(USE_WORK_THREAD) && defined(USE_WORK_PIPE)
-#  ifdef HAVE_SEMAPHORE_H
-#   include <semaphore.h>
-#  endif
-# endif
-#include "ntp_stdlib.h"
-
-typedef enum blocking_work_req_tag {
-	BLOCKING_GETNAMEINFO,
-	BLOCKING_GETADDRINFO,
-} blocking_work_req;
-
-typedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *);
-
-typedef enum blocking_magic_sig_e {
-	BLOCKING_REQ_MAGIC  = 0x510c7ecf,
-	BLOCKING_RESP_MAGIC = 0x510c7e54,
-} blocking_magic_sig;
-
-/*
- * The same header is used for both requests to and responses from
- * the child.  In the child, done_func and context are opaque.
- */
-typedef struct blocking_pipe_header_tag {
-	size_t			octets;
-	blocking_magic_sig	magic_sig;
-	blocking_work_req	rtype;
-	u_int			child_idx;
-	blocking_work_callback	done_func;
-	void *			context;
-} blocking_pipe_header;
-
-# ifdef USE_WORK_THREAD
-#  ifdef USE_WORK_PIPE
-typedef pthread_t *	thr_ref;
-#    ifdef __MACH__
-#include <mach/task.h>
-#include <mach/semaphore.h>
-typedef semaphore_t* sem_ref;
-#    else /* !__MACH__ */
-typedef sem_t *		sem_ref;
-#    endif /* !__MACH__ */
-#  else
-typedef HANDLE		thr_ref;
-typedef HANDLE		sem_ref;
-#  endif
-# endif
-
-#ifdef USE_WORK_THREAD
-typedef struct blocking_child_tag {
-/*
- * blocking workitems and blocking_responses are dynamically-sized
- * one-dimensional arrays of pointers to blocking worker requests and
- * responses.
- */
-	int			reusable;
-	thr_ref			thread_ref;
-	u_int			thread_id;
-	blocking_pipe_header * volatile * volatile 
-				workitems;
-	volatile size_t		workitems_alloc;
-	size_t			next_workitem;	 /* parent */
-	size_t			next_workeritem; /* child */
-	blocking_pipe_header * volatile * volatile 
-				responses;
-	volatile size_t		responses_alloc;
-	size_t			next_response;	/* child */
-	size_t			next_workresp;	/* parent */
-	/* event handles / sem_t pointers */
-	/* sem_ref		child_is_blocking; */
-	sem_ref			blocking_req_ready;
-	sem_ref			wake_scheduled_sleep;
-#ifdef USE_WORK_PIPE
-	int			resp_read_pipe;	/* parent */
-	int			resp_write_pipe;/* child */
-	int			ispipe;
-	void *			resp_read_ctx;	/* child */
-#else
-	sem_ref			blocking_response_ready;
-#endif
-} blocking_child;
-
-#endif	/* USE_WORK_THREAD */
-
-extern	blocking_child **	blocking_children;
-extern	size_t			blocking_children_alloc;
-extern	int			worker_per_query;	/* boolean */
-extern	int			intres_req_pending;
-
-extern	u_int	available_blocking_child_slot(void);
-extern	int	queue_blocking_request(blocking_work_req, void *,
-				       size_t, blocking_work_callback,
-				       void *);
-extern	int	queue_blocking_response(blocking_child *, 
-					blocking_pipe_header *, size_t,
-					const blocking_pipe_header *);
-extern	void	process_blocking_resp(blocking_child *);
-extern	int	send_blocking_req_internal(blocking_child *,
-					   blocking_pipe_header *,
-					   void *);
-extern	int	send_blocking_resp_internal(blocking_child *,
-					    blocking_pipe_header *);
-extern	blocking_pipe_header *
-		receive_blocking_req_internal(blocking_child *);
-extern	blocking_pipe_header *
-		receive_blocking_resp_internal(blocking_child *);
-extern	int	blocking_child_common(blocking_child *);
-extern	void	exit_worker(int)
-			__attribute__ ((__noreturn__));
-extern	int	worker_sleep(blocking_child *, time_t);
-extern	void	worker_idle_timer_fired(void);
-extern	void	interrupt_worker_sleep(void);
-extern	int	req_child_exit(blocking_child *);
-extern	int	pipe_socketpair(int fds[2], bool *is_pipe);
-extern	void	kill_asyncio	(int);
-
-# ifdef USE_WORK_PIPE
-typedef	void	(*addremove_io_fd_func)(int, int, int);
-extern	addremove_io_fd_func		addremove_io_fd;
-# else
-extern	void	handle_blocking_resp_sem(void *);
-typedef	void	(*addremove_io_semaphore_func)(sem_ref, int);
-extern	addremove_io_semaphore_func	addremove_io_semaphore;
-# endif
-
-#endif	/* USE_WORKER */
-
-#endif	/* GUARD_NTP_WORKER_H */


=====================================
include/ntp_workimpl.h deleted
=====================================
--- a/include/ntp_workimpl.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * ntp_workimpl.h - selects worker child implementation
- */
-#ifndef GUARD_NTP_WORKIMPL_H
-#define GUARD_NTP_WORKIMPL_H
-
-/*
- * Some systems do not support fork() and don't have an alternate
- * threads implementation of ntp_intres.  Such systems are limited
- * to using numeric IP addresses.
- */
-#define USE_WORK_THREAD
-#define USE_WORK_PIPE
-
-#if defined(USE_WORK_THREAD)
-/* Guards are not strictly necessary, but keep them as documentation */
-# define USE_WORKER
-#endif
-
-#endif	/* !GUARD_NTP_WORKIMPL_H */


=====================================
include/ntpd.h
=====================================
--- a/include/ntpd.h
+++ b/include/ntpd.h
@@ -16,7 +16,6 @@
 #include "ntp_malloc.h"
 #include "ntp_refclock.h"
 #include "ntp_control.h"
-#include "ntp_intres.h"
 #include "recvbuff.h"
 
 /*
@@ -154,6 +153,7 @@ extern	struct peer *newpeer	(sockaddr_u *, const char *,
 				 endpt *, uint8_t, uint8_t,
 				 uint8_t, uint8_t, u_int, uint8_t, uint32_t,
 				 keyid_t, const bool);
+extern	void	peer_update_hash (struct peer *);
 extern	void	peer_all_reset	(void);
 extern	void	peer_clr_stats	(void);
 extern	void	peer_reset	(struct peer *);
@@ -236,6 +236,11 @@ extern l_fp	fetch_packetstamp(struct recvbuf *, struct msghdr *, l_fp);
 #define MOREDEBUGSIG	SIGUSR1
 #define LESSDEBUGSIG	SIGUSR2
 
+/* Signal we use for DNS completion
+ * No (forked) children so this should be unused.
+ */
+#define SIGDNS	SIGCHLD
+
 /*
  * Last half: ntpd variables
  * -------------------------
@@ -417,6 +422,7 @@ extern u_long	use_stattime;		/* time since reset */
 /* Signalling */
 extern volatile bool sawALRM;
 extern volatile bool sawHUP;
+extern volatile bool sawDNS;
 extern volatile bool sawQuit;		/* SIGQUIT, SIGINT, SIGTERM */
 extern sigset_t blockMask;
 


=====================================
libntp/ntp_intres.c deleted
=====================================
--- a/libntp/ntp_intres.c
+++ /dev/null
@@ -1,1196 +0,0 @@
-/*
- * ntp_intres.c - Implements a generic blocking worker thread,
- *		  initially to provide a nonblocking solution for DNS
- *		  name to address lookups available with getaddrinfo().
- *
- * This is a new implementation as of 2009 sharing the filename and
- * very little else with the prior implementation, which used a
- * temporary file to receive a single set of requests from the parent,
- * and a NTP mode 7 authenticated request to push back responses.
- *
- * A primary goal in rewriting this code was the need to support the
- * pool configuration directive's requirement to retrieve multiple
- * addresses resolving a single name, which has previously been
- * satisfied with blocking resolver calls from the ntpd mainline code.
- *
- * A secondary goal is to provide a generic mechanism for other
- * blocking operations to be delegated to a worker using a common
- * model for all OS ports.  ntp_worker.c and work_thread.c
- * implement the generic mechanism.  This file implements the two 
- * current consumers, getaddrinfo_sometime() and the presently unused 
- * getnameinfo_sometime().
- *
- * Both routines deliver results to a callback and manage memory
- * allocation, meaning there is no freeaddrinfo_sometime().
- *
- * The code uses arrays of pointers to queue requests and responses.
- * The main thread schedules sleeps between retries.  The code mallocs
- * a copy of the request to hand off to the worker via the queueing
- * array.  The resulting request buffer is free()d by
- * platform-independent code.  A wrinkle is the request needs to be
- * available to the requestor during response processing.
- */
-#include "config.h"
-
-#include "ntp_workimpl.h"
-
-#ifdef USE_WORKER
-
-#include <stdio.h>
-#include <ctype.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#if defined(HAVE_RESOLV_H) && defined(HAVE_RES_INIT)
-# ifdef HAVE_ARPA_NAMESER_H
-#  include <arpa/nameser.h> /* DNS HEADER struct */
-# endif
-# include <netdb.h>
-# include <resolv.h>
-#endif
-
-#include "ntp.h"
-#include "ntp_debug.h"
-#include "ntp_malloc.h"
-#include "ntp_syslog.h"
-#include "ntp_intres.h"
-#include "intreswork.h"
-
-
-/*
- * Following are implementations of getaddrinfo_sometime() and
- * getnameinfo_sometime().  Each is implemented in three routines:
- *
- * getaddrinfo_sometime()		getnameinfo_sometime()
- * blocking_getaddrinfo()		blocking_getnameinfo()
- * getaddrinfo_sometime_complete()	getnameinfo_sometime_complete()
- *
- * The first runs in the parent and marshalls (or serializes) request
- * parameters into a request blob which is processed in the child by
- * the second routine, blocking_*(), which serializes the results into
- * a response blob unpacked by the third routine, *_complete(), which
- * calls the callback routine provided with the request and frees
- * _request_ memory allocated by the first routine.  Response memory
- * is managed by the code which calls the *_complete routines.
- */
-
-/* === typedefs === */
-typedef struct blocking_gai_req_tag {	/* marshalled args */
-	size_t			octets;
-	u_int			dns_idx;
-	time_t			scheduled;
-	time_t			earliest;
-	struct addrinfo		hints;
-	int			retry;
-	gai_sometime_callback	callback;
-	void *			context;
-	size_t			nodesize;
-	size_t			servsize;
-} blocking_gai_req;
-
-typedef struct blocking_gai_resp_tag {
-	size_t			octets;
-	int			retcode;
-	int			retry;
-	int			gai_errno; /* for EAI_SYSTEM case */
-	int			ai_count;
-	/*
-	 * Followed by ai_count struct addrinfo and then ai_count
-	 * sockaddr_u and finally the canonical name strings.
-	 */
-} blocking_gai_resp;
-
-typedef struct blocking_gni_req_tag {
-	size_t			octets;
-	u_int			dns_idx;
-	time_t			scheduled;
-	time_t			earliest;
-	int			retry;
-	size_t			hostoctets;
-	size_t			servoctets;
-	int			flags;
-	gni_sometime_callback	callback;
-	void *			context;
-	sockaddr_u		socku;
-} blocking_gni_req;
-
-typedef struct blocking_gni_resp_tag {
-	size_t			octets;
-	int			retcode;
-	int			gni_errno; /* for EAI_SYSTEM case */
-	int			retry;
-	size_t			hostoctets;
-	size_t			servoctets;
-	/*
-	 * Followed by hostoctets bytes of null-terminated host,
-	 * then servoctets bytes of null-terminated service.
-	 */
-} blocking_gni_resp;
-
-/* per-DNS-worker state in parent */
-typedef struct dnschild_ctx_tag {
-	u_int	index;
-	time_t	next_dns_timeslot;
-} dnschild_ctx;
-
-/* per-DNS-worker state in worker */
-typedef struct dnsworker_ctx_tag {
-	blocking_child *	c;
-	time_t			ignore_scheduled_before;
-#ifdef HAVE_RES_INIT
-	time_t	next_res_init;
-#endif
-} dnsworker_ctx;
-
-
-/* === variables === */
-static dnschild_ctx **	dnschild_contexts;		/* parent */
-static u_int		dnschild_contexts_alloc;
-static dnsworker_ctx **	dnsworker_contexts;		/* child */
-static u_int		dnsworker_contexts_alloc;
-
-#ifdef HAVE_RES_INIT
-static	time_t		next_res_init;
-#endif
-
-
-/* === forward declarations === */
-static	u_int		reserve_dnschild_ctx(void);
-static	u_int		get_dnschild_ctx(void);
-static	void		alloc_dnsworker_context(u_int);
-/* static	void		free_dnsworker_context(u_int); */
-static	dnsworker_ctx *	get_worker_context(blocking_child *, u_int);
-static	void		scheduled_sleep(time_t, time_t,
-					dnsworker_ctx *);
-static	void		manage_dns_retry_interval(time_t *, time_t *,
-						  int *,
-						  time_t *);
-static	bool		should_retry_dns(int, int);
-#ifdef HAVE_RES_INIT
-static	void		reload_resolv_conf(dnsworker_ctx *);
-#else
-# define		reload_resolv_conf(wc)		\
-	do {						\
-		(void)(wc);				\
-	} while (false)
-#endif
-static	void		getaddrinfo_sometime_complete(blocking_work_req,
-						      void *, size_t,
-						      void *);
-static	void		getnameinfo_sometime_complete(blocking_work_req,
-						      void *, size_t,
-						      void *);
-
-
-/* === functions === */
-/*
- * getaddrinfo_sometime - uses blocking child to call getaddrinfo then
- *			  invokes provided callback completion function.
- */
-int
-getaddrinfo_sometime(
-	const char *		node,
-	const char *		service,
-	const struct addrinfo *	hints,
-	int			retry,
-	gai_sometime_callback	callback,
-	void *			context
-	)
-{
-	blocking_gai_req *	gai_req;
-	u_int			idx;
-	dnschild_ctx *		child_ctx;
-	size_t			req_size;
-	size_t			nodesize;
-	size_t			servsize;
-	time_t			now;
-	
-	NTP_REQUIRE(NULL != node);
-	if (NULL != hints) {
-		NTP_REQUIRE(0 == hints->ai_addrlen);
-		NTP_REQUIRE(NULL == hints->ai_addr);
-		NTP_REQUIRE(NULL == hints->ai_canonname);
-		NTP_REQUIRE(NULL == hints->ai_next);
-	}
-
-	idx = get_dnschild_ctx();
-	child_ctx = dnschild_contexts[idx];
-
-	nodesize = strlen(node) + 1;
-	servsize = strlen(service) + 1;
-	req_size = sizeof(*gai_req) + nodesize + servsize;
-
-	gai_req = emalloc_zero(req_size);
-
-	gai_req->octets = req_size;
-	gai_req->dns_idx = idx;
-	now = time(NULL);
-	gai_req->scheduled = now;
-	gai_req->earliest = max(now, child_ctx->next_dns_timeslot);
-	child_ctx->next_dns_timeslot = gai_req->earliest;
-	if (hints != NULL)
-		gai_req->hints = *hints;
-	gai_req->retry = retry;
-	gai_req->callback = callback;
-	gai_req->context = context;
-	gai_req->nodesize = nodesize;
-	gai_req->servsize = servsize;
-
-	memcpy((char *)gai_req + sizeof(*gai_req), node, nodesize);
-	memcpy((char *)gai_req + sizeof(*gai_req) + nodesize, service,
-	       servsize);
-
-	if (queue_blocking_request(
-		BLOCKING_GETADDRINFO,
-		gai_req,
-		req_size, 
-		&getaddrinfo_sometime_complete, 
-		gai_req)) {
-
-		msyslog(LOG_ERR, "unable to queue getaddrinfo request");
-		errno = EFAULT;
-		return -1;
-	}
-
-	return 0;
-}
-
-int
-blocking_getaddrinfo(
-	blocking_child *	c,
-	blocking_pipe_header *	req
-	)
-{
-	blocking_gai_req *	gai_req;
-	dnsworker_ctx *		worker_ctx;
-	blocking_pipe_header *	resp;
-	blocking_gai_resp *	gai_resp;
-	char *			node;
-	char *			service;
-	struct addrinfo *	ai_res;
-	struct addrinfo *	ai;
-	struct addrinfo *	serialized_ai;
-	size_t			canons_octets;
-	size_t			this_octets;
-	size_t			resp_octets;
-	char *			cp;
-	time_t			time_now;
-
-	gai_req = (void *)((char *)req + sizeof(*req));
-	node = (char *)gai_req + sizeof(*gai_req);
-	service = node + gai_req->nodesize;
-
-	worker_ctx = get_worker_context(c, gai_req->dns_idx);
-	scheduled_sleep(gai_req->scheduled, gai_req->earliest,
-			worker_ctx);
-	reload_resolv_conf(worker_ctx);
-
-	/*
-	 * Take a shot at the final size, better to overestimate
-	 * at first and then realloc to a smaller size.
-	 */
-
-	resp_octets = sizeof(*resp) + sizeof(*gai_resp) +
-		      16 * (sizeof(struct addrinfo) +
-			    sizeof(sockaddr_u)) +
-		      256;
-	resp = emalloc_zero(resp_octets);
-	gai_resp = (void *)(resp + 1);
-
-	TRACE(2, 
-            ("blocking_getaddrinfo given node %s serv %s fam %d flags %x\n", 
-	     node, service, gai_req->hints.ai_family,
-	     (unsigned)gai_req->hints.ai_flags));
-#ifdef DEBUG
-	if (debug >= 2)
-		fflush(stdout);
-#endif	
-	ai_res = NULL;
-	gai_resp->retcode = getaddrinfo(node, service, &gai_req->hints,
-					&ai_res);
-	gai_resp->retry = gai_req->retry;
-#ifdef EAI_SYSTEM
-	if (EAI_SYSTEM == gai_resp->retcode) {
-	    if (EAGAIN == errno) {
-		msyslog(LOG_ERR, "EAI_SYSTEM/EAGAIN from getaddrinfo, probably out of (locked) memory");
-		exit(1);
-	    }
-	    gai_resp->gai_errno = errno;
-	}
-#endif
-	canons_octets = 0;
-
-	if (0 == gai_resp->retcode) {
-		ai = ai_res;
-		while (NULL != ai) {
-			gai_resp->ai_count++;
-			if (ai->ai_canonname)
-				canons_octets += strlen(ai->ai_canonname) + 1;
-			ai = ai->ai_next;
-		}
-		/*
-		 * If this query succeeded only after retrying, DNS may have
-		 * just become responsive.  Ignore previously-scheduled
-		 * retry sleeps once for each pending request, similar to
-		 * the way scheduled_sleep() does when its worker_sleep()
-		 * is interrupted.
-		 */
-		if (gai_resp->retry > INITIAL_DNS_RETRY) {
-			time_now = time(NULL);
-			worker_ctx->ignore_scheduled_before = time_now;
-			TRACE(1, ("DNS success after retry, ignoring sleeps scheduled before now (%s)\n",
-				  humantime(time_now)));
-		}
-	}
-
-	/*
-	 * Our response consists of a header, followed by ai_count 
-	 * addrinfo structs followed by ai_count sockaddr_storage 
-	 * structs followed by the canonical names.
-	 */
-	gai_resp->octets = sizeof(*gai_resp)
-			    + (unsigned int)gai_resp->ai_count
-				* (sizeof(gai_req->hints)
-				   + sizeof(sockaddr_u))
-			    + canons_octets;
-
-	resp_octets = sizeof(*resp) + gai_resp->octets;
-	resp = erealloc(resp, resp_octets);
-	gai_resp = (void *)(resp + 1);
-
-	/* cp serves as our current pointer while serializing */
-	cp = (void *)(gai_resp + 1);
-	canons_octets = 0;
-
-	if (0 == gai_resp->retcode) {
-		ai = ai_res;
-		while (NULL != ai) {
-			memcpy(cp, ai, sizeof(*ai));
-			serialized_ai = (void *)cp;
-			cp += sizeof(*ai);
-
-			/* transform ai_canonname into offset */
-			if (NULL != serialized_ai->ai_canonname) {
-				serialized_ai->ai_canonname = (char *)canons_octets;
-				canons_octets += strlen(ai->ai_canonname) + 1;
-			}
-			
-			/* leave fixup of ai_addr pointer for receiver */
-
-			ai = ai->ai_next;
-		}
-
-		ai = ai_res;
-		while (NULL != ai) {
-			NTP_INSIST(ai->ai_addrlen <= sizeof(sockaddr_u));
-			memcpy(cp, ai->ai_addr, ai->ai_addrlen);
-			cp += sizeof(sockaddr_u);
-
-			ai = ai->ai_next;
-		}
-
-		ai = ai_res;
-		while (NULL != ai) {
-			if (NULL != ai->ai_canonname) {
-				this_octets = strlen(ai->ai_canonname) + 1;
-				memcpy(cp, ai->ai_canonname, this_octets);
-				cp += this_octets;
-			}
-
-			ai = ai->ai_next;
-		}
-		freeaddrinfo(ai_res);
-	}
-
-	/*
-	 * make sure our walk and earlier calc match
-	 */
-	DEBUG_INSIST((size_t)(cp - (char *)resp) == resp_octets);
-
-	if (queue_blocking_response(c, resp, resp_octets, req)) {
-		msyslog(LOG_ERR, "blocking_getaddrinfo can not queue response");
-		return -1;
-	}
-
-	/* FIXME: might be a real resource leak, not a Coverity false positive */
-	/* coverity[leaked_storage] */
-	return 0;
-}
-
-
-static void
-getaddrinfo_sometime_complete(
-	blocking_work_req	rtype,
-	void *			context,
-	size_t			respsize,
-	void *			resp
-	)
-{
-	blocking_gai_req *	gai_req;
-	blocking_gai_resp *	gai_resp;
-	dnschild_ctx *		child_ctx;
-	struct addrinfo *	ai;
-	struct addrinfo *	next_ai;
-	sockaddr_u *		psau;
-	char *			node;
-	char *			service;
-	char *			canon_start;
-	time_t			time_now;
-	bool			again;
-	int			af;
-	const char *		fam_spec;
-	int			i;
-
-	UNUSED_ARG(context);
-	UNUSED_ARG(rtype);
-	UNUSED_ARG(respsize);
-
-	gai_req = context;
-	gai_resp = resp;
-
-	DEBUG_REQUIRE(BLOCKING_GETADDRINFO == rtype);
-	DEBUG_REQUIRE(respsize == gai_resp->octets);
-
-	node = (char *)gai_req + sizeof(*gai_req);
-	service = node + gai_req->nodesize;
-
-	child_ctx = dnschild_contexts[gai_req->dns_idx];
-
-	if (0 == gai_resp->retcode) {
-		/*
-		 * If this query succeeded only after retrying, DNS may have
-		 * just become responsive.
-		 */
-		if (gai_resp->retry > INITIAL_DNS_RETRY) {
-			time_now = time(NULL);
-			child_ctx->next_dns_timeslot = time_now;
-			TRACE(1, ("DNS success after retry, %u next_dns_timeslot reset (%s)\n",
-				  gai_req->dns_idx, humantime(time_now)));
-		}
-	} else {
-		again = should_retry_dns(gai_resp->retcode,
-					 gai_resp->gai_errno);
-		/*
-		 * exponential backoff of DNS retries to 64s
-		 */
-		if (gai_req->retry > 0 && again) {
-			/* log the first retry only */
-			if (INITIAL_DNS_RETRY == gai_req->retry)
-				NLOG(NLOG_SYSINFO) {
-					af = gai_req->hints.ai_family;
-					fam_spec = (AF_INET6 == af)
-						       ? " (AAAA)"
-						       : (AF_INET == af)
-							     ? " (A)"
-							     : "";
-#ifdef EAI_SYSTEM
-					if (EAI_SYSTEM == gai_resp->retcode) {
-						errno = gai_resp->gai_errno;
-						msyslog(LOG_INFO,
-							"retrying DNS %s%s: EAI_SYSTEM %d: %m",
-							node, fam_spec,
-							gai_resp->gai_errno);
-					} else
-#endif
-						msyslog(LOG_INFO,
-							"retrying DNS %s%s: %s (%d)",
-							node, fam_spec,
-							gai_strerror(gai_resp->retcode),
-							gai_resp->retcode);
-				}
-			manage_dns_retry_interval(&gai_req->scheduled,
-			    &gai_req->earliest, &gai_req->retry,
-			    &child_ctx->next_dns_timeslot);
-			if (!queue_blocking_request(
-					BLOCKING_GETADDRINFO,
-					gai_req,
-					gai_req->octets,
-					&getaddrinfo_sometime_complete,
-					gai_req))
-				return;
-			else
-				msyslog(LOG_ERR,
-					"unable to retry hostname %s",
-					node);
-		}
-	}
-
-	/*
-	 * fixup pointers in returned addrinfo array
-	 */
-	ai = (void *)((char *)gai_resp + sizeof(*gai_resp));
-	next_ai = NULL;
-	for (i = gai_resp->ai_count - 1; i >= 0; i--) {
-		ai[i].ai_next = next_ai;
-		next_ai = &ai[i];
-	}
-
-	psau = (void *)((char *)ai + gai_resp->ai_count * (int)sizeof(*ai));
-	canon_start = (char *)psau + gai_resp->ai_count * (int)sizeof(*psau);
-
-	for (i = 0; i < gai_resp->ai_count; i++) {
-		if (NULL != ai[i].ai_addr)
-			ai[i].ai_addr = &psau->sa;
-		psau++;
-		if (NULL != ai[i].ai_canonname)
-			ai[i].ai_canonname += (size_t)canon_start;
-	}
-
-	NTP_ENSURE((char *)psau == canon_start);
-
-	if (!gai_resp->ai_count)
-		ai = NULL;
-	
-	(*gai_req->callback)(gai_resp->retcode, gai_resp->gai_errno,
-			     gai_req->context, node, service, 
-			     &gai_req->hints, ai);
-
-	free(gai_req);
-	/* gai_resp is part of block freed by process_blocking_resp() */
-}
-
-
-int
-getnameinfo_sometime(
-	sockaddr_u *		psau,
-	size_t			hostoctets,
-	size_t			servoctets,
-	int			flags,
-	gni_sometime_callback	callback,
-	void *			context
-	)
-{
-	blocking_gni_req *	gni_req;
-	u_int			idx;
-	dnschild_ctx *		child_ctx;
-	time_t			time_now;
-	
-	NTP_REQUIRE(hostoctets);
-	NTP_REQUIRE(hostoctets + servoctets < 1024);
-
-	idx = get_dnschild_ctx();
-	child_ctx = dnschild_contexts[idx];
-
-	gni_req = emalloc_zero(sizeof(*gni_req));
-
-	gni_req->octets = sizeof(*gni_req);
-	gni_req->dns_idx = idx;
-	time_now = time(NULL);
-	gni_req->scheduled = time_now;
-	gni_req->earliest = max(time_now, child_ctx->next_dns_timeslot);
-	child_ctx->next_dns_timeslot = gni_req->earliest;
-	memcpy(&gni_req->socku, psau, SOCKLEN(psau));
-	gni_req->hostoctets = hostoctets;
-	gni_req->servoctets = servoctets;
-	gni_req->flags = flags;
-	gni_req->retry = INITIAL_DNS_RETRY;
-	gni_req->callback = callback;
-	gni_req->context = context;
-
-	if (queue_blocking_request(
-		BLOCKING_GETNAMEINFO,
-		gni_req,
-		sizeof(*gni_req), 
-		&getnameinfo_sometime_complete, 
-		gni_req)) {
-
-		msyslog(LOG_ERR, "unable to queue getnameinfo request");
-		errno = EFAULT;
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int
-blocking_getnameinfo(
-	blocking_child *	c,
-	blocking_pipe_header *	req
-	)
-{
-	blocking_gni_req *	gni_req;
-	dnsworker_ctx *		worker_ctx;
-	blocking_pipe_header *	resp;
-	blocking_gni_resp *	gni_resp;
-	size_t			octets;
-	size_t			resp_octets;
-	char *			service;
-	char *			cp;
-	int			rc;
-	time_t			time_now;
-	char			host[1024];
-
-	gni_req = (void *)((char *)req + sizeof(*req));
-
-	octets = gni_req->hostoctets + gni_req->servoctets;
-
-	/*
-	 * Some alloca() implementations are fragile regarding
-	 * large allocations.  We only need room for the host
-	 * and service names.
-	 */
-	NTP_REQUIRE(octets < sizeof(host));
-	service = host + gni_req->hostoctets;
-
-	worker_ctx = get_worker_context(c, gni_req->dns_idx);
-	scheduled_sleep(gni_req->scheduled, gni_req->earliest,
-			worker_ctx);
-	reload_resolv_conf(worker_ctx);
-
-	/*
-	 * Take a shot at the final size, better to overestimate
-	 * then realloc to a smaller size.
-	 */
-
-	resp_octets = sizeof(*resp) + sizeof(*gni_resp) + octets;
-	resp = emalloc_zero(resp_octets);
-	gni_resp = (void *)((char *)resp + sizeof(*resp));
-
-	TRACE(2, 
-          ("blocking_getnameinfo addr %s flags 0x%x hostlen %lu servlen %lu\n",
-	  socktoa(&gni_req->socku), (unsigned)gni_req->flags,
-	  (u_long)gni_req->hostoctets, (u_long)gni_req->servoctets));
-	
-	gni_resp->retcode = getnameinfo(&gni_req->socku.sa,
-					SOCKLEN(&gni_req->socku),
-					host,
-					gni_req->hostoctets,
-					service,
-					gni_req->servoctets,
-					gni_req->flags);
-	gni_resp->retry = gni_req->retry;
-#ifdef EAI_SYSTEM
-	if (EAI_SYSTEM == gni_resp->retcode)
-		gni_resp->gni_errno = errno;
-#endif
-
-	if (0 != gni_resp->retcode) {
-		gni_resp->hostoctets = 0;
-		gni_resp->servoctets = 0;
-	} else {
-		gni_resp->hostoctets = strlen(host) + 1;
-		gni_resp->servoctets = strlen(service) + 1;
-		/*
-		 * If this query succeeded only after retrying, DNS may have
-		 * just become responsive.  Ignore previously-scheduled
-		 * retry sleeps once for each pending request, similar to
-		 * the way scheduled_sleep() does when its worker_sleep()
-		 * is interrupted.
-		 */
-		if (gni_req->retry > INITIAL_DNS_RETRY) {
-			time_now = time(NULL);
-			worker_ctx->ignore_scheduled_before = time_now;
-			TRACE(1, ("DNS success after retrying, ignoring sleeps scheduled before now (%s)\n",
-				humantime(time_now)));
-		}
-	}
-	octets = gni_resp->hostoctets + gni_resp->servoctets;
-	/*
-	 * Our response consists of a header, followed by the host and
-	 * service strings, each null-terminated.
-	 */
-	resp_octets = sizeof(*resp) + sizeof(*gni_resp) + octets;
-
-	resp = erealloc(resp, resp_octets);
-	gni_resp = (void *)(resp + 1);
-
-	gni_resp->octets = sizeof(*gni_resp) + octets;
-
-	/* cp serves as our current pointer while serializing */
-	cp = (void *)(gni_resp + 1);
-
-	if (0 == gni_resp->retcode) {
-		memcpy(cp, host, gni_resp->hostoctets);
-		cp += gni_resp->hostoctets;
-		memcpy(cp, service, gni_resp->servoctets);
-		cp += gni_resp->servoctets;
-	}
-
-	NTP_INSIST((size_t)(cp - (char *)resp) == resp_octets);
-	NTP_INSIST(resp_octets - sizeof(*resp) == gni_resp->octets);
-
-	rc = queue_blocking_response(c, resp, resp_octets, req);
-	if (rc)
-		msyslog(LOG_ERR, "blocking_getnameinfo unable to queue response");
-	return rc;
-}
-
-
-static void
-getnameinfo_sometime_complete(
-	blocking_work_req	rtype,
-	void *			context,
-	size_t			respsize,
-	void *			resp
-	)
-{
-	blocking_gni_req *	gni_req;
-	blocking_gni_resp *	gni_resp;
-	dnschild_ctx *		child_ctx;
-	char *			host;
-	char *			service;
-	time_t			time_now;
-	bool			again;
-
-	UNUSED_ARG(rtype);
-	UNUSED_ARG(respsize);
-
-	gni_req = context;
-	gni_resp = resp;
-
-	DEBUG_REQUIRE(BLOCKING_GETNAMEINFO == rtype);
-	DEBUG_REQUIRE(respsize == gni_resp->octets);
-
-	child_ctx = dnschild_contexts[gni_req->dns_idx];
-
-	if (0 == gni_resp->retcode) {
-		/*
-		 * If this query succeeded only after retrying, DNS may have
-		 * just become responsive.
-		 */
-		if (gni_resp->retry > INITIAL_DNS_RETRY) {
-			time_now = time(NULL);
-			child_ctx->next_dns_timeslot = time_now;
-			TRACE(1, ("DNS success after retry, %u next_dns_timeslot reset (%s)\n",
-				  gni_req->dns_idx, humantime(time_now)));
-		}
-	} else {
-		again = should_retry_dns(gni_resp->retcode, gni_resp->gni_errno);
-		/*
-		 * exponential backoff of DNS retries to 64s
-		 */
-		if (gni_req->retry > 0)
-			manage_dns_retry_interval(&gni_req->scheduled,
-			    &gni_req->earliest, &gni_req->retry,
-			    &child_ctx->next_dns_timeslot);
-
-		if (gni_req->retry > 0 && again) {
-			if (!queue_blocking_request(
-				BLOCKING_GETNAMEINFO,
-				gni_req,
-				gni_req->octets, 
-				&getnameinfo_sometime_complete, 
-				gni_req))
-				return;
-
-			msyslog(LOG_ERR, "unable to retry reverse lookup of %s", socktoa(&gni_req->socku));
-		}
-	}
-
-	if (!gni_resp->hostoctets) {
-		host = NULL;
-		service = NULL;
-	} else {
-		host = (char *)gni_resp + sizeof(*gni_resp);
-		service = (gni_resp->servoctets) 
-			      ? host + gni_resp->hostoctets
-			      : NULL;
-	}
-
-	(*gni_req->callback)(gni_resp->retcode, gni_resp->gni_errno,
-			     &gni_req->socku, gni_req->flags, host,
-			     service, gni_req->context);
-
-	free(gni_req);
-	/* gni_resp is part of block freed by process_blocking_resp() */
-}
-
-
-#ifdef HAVE_RES_INIT
-static void
-reload_resolv_conf(
-	dnsworker_ctx *	worker_ctx
-	)
-{
-	time_t	time_now;
-
-	/*
-	 * This is ad-hoc.  Reload /etc/resolv.conf once per minute
-	 * to pick up on changes from the DHCP client.  [Bug 1226]
-	 * When using threads for the workers, this needs to happen
-	 * only once per minute process-wide.
-	 */
-	time_now = time(NULL);
-# ifdef USE_WORK_THREAD
-	worker_ctx->next_res_init = next_res_init;
-# endif
-	if (worker_ctx->next_res_init <= time_now) {
-		if (worker_ctx->next_res_init != 0)
-			res_init();
-		worker_ctx->next_res_init = time_now + 60;
-# ifdef USE_WORK_THREAD
-		next_res_init = worker_ctx->next_res_init;
-# endif
-	}
-}
-#endif	/* HAVE_RES_INIT */
-
-
-static u_int
-reserve_dnschild_ctx(void)
-{
-	const size_t	ps = sizeof(dnschild_contexts[0]);
-	const size_t	cs = sizeof(*dnschild_contexts[0]);
-	u_int		c;
-	u_int		new_alloc;
-	size_t		octets;
-	size_t		new_octets;
-
-	c = 0;
-	while (true) {
-		for ( ; c < dnschild_contexts_alloc; c++) {
-			if (NULL == dnschild_contexts[c]) {
-				dnschild_contexts[c] = emalloc_zero(cs);
-
-				return c;
-			}
-		}
-		new_alloc = dnschild_contexts_alloc + 20;
-		new_octets = new_alloc * ps;
-		octets = dnschild_contexts_alloc * ps;
-		dnschild_contexts = erealloc_zero(dnschild_contexts,
-						  new_octets, octets);
-		dnschild_contexts_alloc = new_alloc;
-	}
-}
-
-
-static u_int
-get_dnschild_ctx(void)
-{
-	static u_int	shared_ctx = UINT_MAX;
-
-	if (worker_per_query)
-		return reserve_dnschild_ctx();
-
-	if (UINT_MAX == shared_ctx)
-		shared_ctx = reserve_dnschild_ctx();
-
-	return shared_ctx;
-}
-
-
-static void
-alloc_dnsworker_context(
-	u_int idx
-	)
-{
-	const size_t worker_context_sz = sizeof(*dnsworker_contexts[0]);
-
-	REQUIRE(NULL == dnsworker_contexts[idx]);
-	dnsworker_contexts[idx] = emalloc_zero(worker_context_sz);
-}
-
-
-static dnsworker_ctx *
-get_worker_context(
-	blocking_child *	c,
-	u_int			idx
-	)
-{
-	static size_t	ps = sizeof(dnsworker_contexts[0]);
-	u_int	min_new_alloc;
-	u_int	new_alloc;
-	size_t	octets;
-	size_t	new_octets;
-
-	if (dnsworker_contexts_alloc <= idx) {
-		min_new_alloc = 1 + idx;
-		/* round new_alloc up to nearest multiple of 4 */
-		new_alloc = (min_new_alloc + 4) & (unsigned int)~(4 - 1);
-		new_octets = new_alloc * ps;
-		octets = dnsworker_contexts_alloc * ps;
-		dnsworker_contexts = erealloc_zero(dnsworker_contexts,
-						   new_octets, octets);
-		dnsworker_contexts_alloc = new_alloc;
-	}
-
-	if (NULL == dnsworker_contexts[idx])
-		alloc_dnsworker_context(idx);
-	ZERO(*dnsworker_contexts[idx]);
-	dnsworker_contexts[idx]->c = c;
-
-	return dnsworker_contexts[idx];
-}
-
-
-static void
-scheduled_sleep(
-	time_t		scheduled,
-	time_t		earliest,
-	dnsworker_ctx *	worker_ctx
-	)
-{
-	time_t now;
-
-	if (scheduled < worker_ctx->ignore_scheduled_before) {
-		TRACE(1, ("ignoring sleep until %s scheduled at %s (before %s)\n",
-			  humantime(earliest), humantime(scheduled),
-			  humantime(worker_ctx->ignore_scheduled_before)));
-		return;
-	}
-
-	now = time(NULL);
-
-	if (now < earliest) {
-		TRACE(1, ("sleep until %s scheduled at %s (>= %s)\n",
-			  humantime(earliest), humantime(scheduled),
-			  humantime(worker_ctx->ignore_scheduled_before)));
-		if (-1 == worker_sleep(worker_ctx->c, earliest - now)) {
-			/* our sleep was interrupted */
-			now = time(NULL);
-			worker_ctx->ignore_scheduled_before = now;
-#ifdef HAVE_RES_INIT
-			worker_ctx->next_res_init = now + 60;
-			next_res_init = worker_ctx->next_res_init;
-			res_init();
-#endif
-			TRACE(1, ("sleep interrupted by daemon, ignoring sleeps scheduled before now (%s)\n",
-				  humantime(worker_ctx->ignore_scheduled_before)));
-		}
-	}
-}
-
-
-/*
- * manage_dns_retry_interval is a helper used by
- * getaddrinfo_sometime_complete and getnameinfo_sometime_complete
- * to calculate the new retry interval and schedule the next query.
- */
-static void
-manage_dns_retry_interval(
-	time_t *	pscheduled,
-	time_t *	pwhen,
-	int *		pretry,
-	time_t *	pnext_timeslot
-	)
-{
-	time_t	now;
-	time_t	when;
-	int	retry;
-		
-	now = time(NULL);
-	retry = *pretry;
-	when = max(now + retry, *pnext_timeslot);
-	*pnext_timeslot = when;
-	retry = min(64, retry << 1);
-
-	*pscheduled = now;
-	*pwhen = when;
-	*pretry = retry;
-}
-
-/*
- * should_retry_dns is a helper used by getaddrinfo_sometime_complete
- * and getnameinfo_sometime_complete which implements ntpd's DNS retry
- * policy.
- */
-static bool
-should_retry_dns(
-	int	rescode,
-	int	res_errno
-	)
-{
-	static bool	eai_again_seen;
-	bool		again;
-#if defined (EAI_SYSTEM) && defined(DEBUG)
-	char		msg[256];
-#endif
-
-	UNUSED_ARG(res_errno);
-
-	/*
-	 * If the resolver failed, see if the failure is
-	 * temporary. If so, return success.
-	 */
-	again = false;
-
-	switch (rescode) {
-
-	case EAI_FAIL:
-		again = true;
-		break;
-
-	case EAI_AGAIN:
-		again = true;
-		eai_again_seen = true;		/* [Bug 1178] */
-		break;
-
-	case EAI_NONAME:
-#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
-	case EAI_NODATA:
-#endif
-		again = !eai_again_seen;	/* [Bug 1178] */
-		break;
-
-#ifdef EAI_SYSTEM
-	case EAI_SYSTEM:
-		/* 
-		 * EAI_SYSTEM means the real error is in errno.  We should be more
-		 * discriminating about which errno values require retrying, but
-		 * this matches existing behavior.
-		 */
-		again = true;
-# ifdef DEBUG
-		errno_to_str(res_errno, msg, sizeof(msg));
-		TRACE(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n",
-			  res_errno, msg));
-# endif
-		break;
-#endif
-        default:
-                /* huh? */
-                break;
-	}
-
-	TRACE(2, ("intres: resolver returned: %s (%d), %sretrying\n",
-		  gai_strerror(rescode), rescode, again ? "" : "not "));
-
-	return again;
-}
-
-/*
- * copy_addrinfo()	- copy a single addrinfo to malloc()'d block.
- * copy_addrinfo_list() - copy an addrinfo list to malloc()'d block.
- *
- * Copies an addrinfo list and its associated data to a contiguous block
- * of storage from emalloc().  Callback routines invoked via
- * getaddrinfo_sometime() have access to the resulting addrinfo list
- * only until they return.  This routine provides an easy way to make a
- * persistent copy.  Although the list provided to gai_sometime_callback
- * routines is similarly contiguous, to keep this code usable in any
- * context where we might want to duplicate an addrinfo list, it does
- * not require the input list be contiguous.
- *
- * The returned list head pointer is passed to free() to release the
- * entire list.
- *
- * In keeping with the rest of the NTP distribution, sockaddr_u is used
- * in preference to struct sockaddr_storage, which is a member of the
- * former union and so compatible.
- */
-struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int
-#ifdef EREALLOC_CALLSITE
-								   ,
-				       const char *, int
-#endif
-				       );
-
-
-struct addrinfo *
-copy_addrinfo_impl(
-	const struct addrinfo *	src
-#ifdef EREALLOC_CALLSITE
-				   ,
-	const char *		caller_file,
-	int			caller_line
-#endif
-	)
-{
-	return copy_addrinfo_common(src, true
-#ifdef EREALLOC_CALLSITE
-					      ,
-				    caller_file, caller_line
-#endif
-				    );
-}
-
-
-struct addrinfo *
-copy_addrinfo_list_impl(
-	const struct addrinfo *	src
-#ifdef EREALLOC_CALLSITE
-				   ,
-	const char *		caller_file,
-	int			caller_line
-#endif
-	)
-{
-	return copy_addrinfo_common(src, false
-#ifdef EREALLOC_CALLSITE
-					      ,
-				    caller_file, caller_line
-#endif
-				    );
-}
-
-
-struct addrinfo *
-copy_addrinfo_common(
-	const struct addrinfo *	src,
-	int			just_one
-#ifdef EREALLOC_CALLSITE
-					,
-	const char *		caller_file,
-	int			caller_line
-#endif
-	)
-{
-	const struct addrinfo *	ai_src;
-	const struct addrinfo *	ai_nxt;
-	struct addrinfo *	ai_cpy;
-	struct addrinfo *	dst;
-	sockaddr_u *		psau;
-	char *			pcanon;
-	u_int			elements;
-	size_t			octets;
-	size_t			canons_octets;
-	size_t			str_octets;
-
-	elements = 0;
-	canons_octets = 0;
-
-	for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
-		if (just_one)
-			ai_nxt = NULL;
-		else
-			ai_nxt = ai_src->ai_next;
-		++elements;
-		if (NULL != ai_src->ai_canonname)
-			canons_octets += 1 + strlen(ai_src->ai_canonname);
-	}
-
-	octets = elements * (sizeof(*ai_cpy) + sizeof(*psau));
-	octets += canons_octets;
-
-	dst = erealloczsite(NULL, octets, 0, true, caller_file,
-			    caller_line);
-	ai_cpy = dst;
-	psau = (void *)(ai_cpy + elements);
-	pcanon = (void *)(psau + elements);
-
-	for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
-		if (just_one)
-			ai_nxt = NULL;
-		else
-			ai_nxt = ai_src->ai_next;
-		*ai_cpy = *ai_src;
-		REQUIRE(ai_src->ai_addrlen <= sizeof(sockaddr_u));
-		memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
-		ai_cpy->ai_addr = &psau->sa;
-		++psau;
-		if (NULL != ai_cpy->ai_canonname) {
-			ai_cpy->ai_canonname = pcanon;
-			str_octets = 1 + strlen(ai_src->ai_canonname);
-			memcpy(pcanon, ai_src->ai_canonname, str_octets);
-			pcanon += str_octets;
-		}
-		if (NULL != ai_cpy->ai_next) {
-			if (just_one)
-				ai_cpy->ai_next = NULL;
-			else
-				ai_cpy->ai_next = ai_cpy + 1;
-		}
-		++ai_cpy;
-	}
-	NTP_ENSURE(pcanon == ((char *)dst + octets));
-
-	return dst;
-}
-
-#else	/* !USE_WORKER follows */
-int ntp_intres_nonempty_compilation_unit;
-#endif


=====================================
libntp/ntp_worker.c deleted
=====================================
--- a/libntp/ntp_worker.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * ntp_worker.c
- */
-#include "config.h"
-#include "ntp_workimpl.h"
-
-#ifdef USE_WORKER
-
-#include <stdio.h>
-#include <ctype.h>
-#include <signal.h>
-
-#include "ntp_stdlib.h"
-#include "ntp_malloc.h"
-#include "ntp_syslog.h"
-#include "ntpd.h"
-#include "ntp_io.h"
-#include "ntp_assert.h"
-#include "intreswork.h"
-
-
-#define CHILD_MAX_IDLE	(3 * 60)	/* seconds, idle worker limit */
-
-blocking_child **	blocking_children;
-size_t			blocking_children_alloc;
-int			worker_per_query;	/* boolean */
-int			intres_req_pending;
-
-
-/*
- * pipe_socketpair()
- *
- * Provides an AF_UNIX socketpair on systems which have them, otherwise
- * pair of unidirectional pipes.
- */
-int
-pipe_socketpair(
-	int	caller_fds[2],
-	bool *	is_pipe
-	)
-{
-	int	rc;
-	int	fds[2];
-	bool	called_pipe;
-
-	rc = socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]);
-
-	if (-1 == rc) {
-		rc = pipe(&fds[0]);
-		called_pipe = true;
-	} else {
-		called_pipe = false;
-	}
-
-	if (-1 == rc)
-		return rc;
-
-	caller_fds[0] = fds[0];
-	caller_fds[1] = fds[1];
-	if (is_pipe != NULL)
-		*is_pipe = called_pipe;
-
-	return 0;
-}
-
-
-u_int
-available_blocking_child_slot(void)
-{
-	const size_t	each = sizeof(blocking_children[0]);
-	u_int		slot;
-	size_t		prev_alloc;
-	size_t		new_alloc;
-	size_t		prev_octets;
-	size_t		octets;
-
-	for (slot = 0; slot < blocking_children_alloc; slot++) {
-		if (NULL == blocking_children[slot])
-			return slot;
-		if (blocking_children[slot]->reusable) {
-			blocking_children[slot]->reusable = false;
-			return slot;
-		}
-	}
-
-	prev_alloc = blocking_children_alloc;
-	prev_octets = prev_alloc * each;
-	new_alloc = blocking_children_alloc + 4;
-	octets = new_alloc * each;
-	blocking_children = erealloc_zero(blocking_children, octets,
-					  prev_octets);
-	blocking_children_alloc = new_alloc;
-
-	return prev_alloc;
-}
-
-
-int
-queue_blocking_request(
-	blocking_work_req	rtype,
-	void *			req,
-	size_t			reqsize,
-	blocking_work_callback	done_func,
-	void *			context
-	)
-{
-	static u_int		intres_slot = UINT_MAX;
-	u_int			child_slot;
-	blocking_child *	c;
-	blocking_pipe_header	req_hdr;
-
-	req_hdr.octets = sizeof(req_hdr) + reqsize;
-	req_hdr.magic_sig = BLOCKING_REQ_MAGIC;
-	req_hdr.rtype = rtype;
-	req_hdr.done_func = done_func;
-	req_hdr.context = context;
-
-	child_slot = UINT_MAX;
-	if (worker_per_query || UINT_MAX == intres_slot ||
-	    blocking_children[intres_slot]->reusable)
-		child_slot = available_blocking_child_slot();
-	if (!worker_per_query) {
-		if (UINT_MAX == intres_slot)
-			intres_slot = child_slot;
-		else
-			child_slot = intres_slot;
-		if (0 == intres_req_pending)
-			intres_timeout_req(0);
-	}
-	intres_req_pending++;
-	INSIST(UINT_MAX != child_slot);
-	c = blocking_children[child_slot];
-	if (NULL == c) {
-		c = emalloc_zero(sizeof(*c));
-#ifdef USE_WORK_PIPE
-		c->resp_read_pipe = -1;
-		c->resp_write_pipe = -1;
-#endif
-		blocking_children[child_slot] = c;
-	}
-	req_hdr.child_idx = child_slot;
-
-	return send_blocking_req_internal(c, &req_hdr, req);
-}
-
-
-int queue_blocking_response(
-	blocking_child *		c,
-	blocking_pipe_header *		resp,
-	size_t				respsize,
-	const blocking_pipe_header *	req
-	)
-{
-	resp->octets = respsize;
-	resp->magic_sig = BLOCKING_RESP_MAGIC;
-	resp->rtype = req->rtype;
-	resp->context = req->context;
-	resp->done_func = req->done_func;
-
-	return send_blocking_resp_internal(c, resp);
-}
-
-
-void
-process_blocking_resp(
-	blocking_child *	c
-	)
-{
-	blocking_pipe_header *	resp;
-	void *			data;
-
-#ifdef USE_WORK_THREAD
-	do {
-#endif
-		resp = receive_blocking_resp_internal(c);
-		if (NULL != resp) {
-			DEBUG_REQUIRE(BLOCKING_RESP_MAGIC ==
-				      resp->magic_sig);
-			data = (char *)resp + sizeof(*resp);
-			intres_req_pending--;
-			(*resp->done_func)(resp->rtype, resp->context,
-					   resp->octets - sizeof(*resp),
-					   data);
-			free(resp);
-		}
-#ifdef USE_WORK_THREAD
-	} while (NULL != resp);
-#endif
-	if (!worker_per_query && 0 == intres_req_pending)
-		intres_timeout_req(CHILD_MAX_IDLE);
-	else if (worker_per_query)
-		req_child_exit(c);
-}
-
-
-/*
- * blocking_child_common runs as a forked child or a thread
- */
-int
-blocking_child_common(
-	blocking_child	*c
-	)
-{
-	bool say_bye;
-	blocking_pipe_header *req;
-
-	say_bye = false;
-	while (!say_bye) {
-		req = receive_blocking_req_internal(c);
-		if (NULL == req) {
-			break;
-		}
-
-		DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == req->magic_sig);
-
-		switch (req->rtype) {
-		case BLOCKING_GETADDRINFO:
-			if (blocking_getaddrinfo(c, req))
-				say_bye = true;
-			break;
-
-		case BLOCKING_GETNAMEINFO:
-			if (blocking_getnameinfo(c, req))
-				say_bye = true;
-			break;
-
-		default:
-			msyslog(LOG_ERR, "unknown req %u to blocking worker",
-                                req->rtype);
-			say_bye = true;
-		}
-
-		free(req);
-	}
-
-	return 0;
-}
-
-
-/*
- * worker_idle_timer_fired()
- *
- * The parent starts this timer when the last pending response has been
- * received from the child, making it idle, and clears the timer when a
- * request is dispatched to the child.  Once the timer expires, the
- * child is sent packing.
- *
- * This is called when worker_idle_timer is nonzero and less than or
- * equal to current_time.
- */
-void
-worker_idle_timer_fired(void)
-{
-	u_int			idx;
-	blocking_child *	c;
-
-	DEBUG_REQUIRE(0 == intres_req_pending);
-
-	intres_timeout_req(0);
-	for (idx = 0; idx < blocking_children_alloc; idx++) {
-		c = blocking_children[idx];
-		if (NULL == c)
-			continue;
-		req_child_exit(c);
-	}
-}
-
-
-#else	/* !USE_WORKER follows */
-int ntp_worker_nonempty_compilation_unit;
-#endif


=====================================
libntp/work_thread.c deleted
=====================================
--- a/libntp/work_thread.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * work_thread.c - threads implementation for blocking worker child.
- */
-#include "config.h"
-#include "ntp_workimpl.h"
-
-#ifdef USE_WORK_THREAD
-
-#include <stdio.h>
-#include <ctype.h>
-#include <signal.h>
-#include <pthread.h>
-
-#include "ntp_stdlib.h"
-#include "ntp_malloc.h"
-#include "ntp_syslog.h"
-#include "ntpd.h"
-#include "ntp_io.h"
-#include "ntp_assert.h"
-#include "timespecops.h"
-#include "ntp_worker.h"
-
-#define CHILD_EXIT_REQ	((blocking_pipe_header *)(intptr_t)-1)
-#define CHILD_GONE_RESP	CHILD_EXIT_REQ
-#define WORKITEMS_ALLOC_INC	64
-#define RESPONSES_ALLOC_INC	16
-
-#ifdef OVERRIDE_THREAD_MINSTACKSIZE
-#define THREAD_MINSTACKSIZE OVERRIDE_THREAD_MINSTACKSIZE
-#else
-#define THREAD_MINSTACKSIZE	(64U * 1024)
-#endif
-
-#ifndef DEVOLATILE
-#define DEVOLATILE(type, var) ((type)(uintptr_t)(volatile void *)(var))
-#endif
-
-#ifdef __MACH__
-#include <mach/clock.h>
-#include <mach/mach.h>
-#undef sem_init
-#define sem_init(s,p,c) semaphore_create(mach_task_self(),s,SYNC_POLICY_FIFO,c)
-#undef sem_destroy
-#define sem_destroy(s) semaphore_destroy(mach_task_self(),*s)
-#undef sem_wait
-#define sem_wait(s) semaphore_wait(*s)
-#undef sem_post
-#define sem_post(s) semaphore_signal(*s)
-#undef sem_timedwait
-static int sem_timedwait_osx(sem_ref sem, const struct timespec *abs_timeout)
-{
-	mach_timespec_t wait_time;
-	wait_time.tv_sec = abs_timeout->tv_sec;
-	wait_time.tv_nsec = abs_timeout->tv_nsec;
-	return semaphore_timedwait(*sem, wait_time);
-}
-#define sem_timedwait sem_timedwait_osx
-#endif
-
-#define thread_exit(c)	pthread_exit((void*)(size_t)(c))
-
-#ifdef USE_WORK_PIPE
-addremove_io_fd_func		addremove_io_fd;
-#else
-addremove_io_semaphore_func	addremove_io_semaphore;
-#endif
-
-static	void	start_blocking_thread(blocking_child *);
-static	void	start_blocking_thread_internal(blocking_child *);
-static	void	prepare_child_sems(blocking_child *);
-static	int	wait_for_sem(sem_ref, struct timespec *);
-static	void	ensure_workitems_empty_slot(blocking_child *);
-static	void	ensure_workresp_empty_slot(blocking_child *);
-static	int	queue_req_pointer(blocking_child *, blocking_pipe_header *);
-static	void	cleanup_after_child(blocking_child *);
-void *		blocking_thread(void *);
-static	void	block_thread_signals(sigset_t *);
-
-
-void
-exit_worker(
-	int	exitcode
-	)
-{
-	thread_exit(exitcode);	/* see #define thread_exit */
-}
-
-int
-worker_sleep(
-	blocking_child *	c,
-	time_t			seconds
-	)
-{
-	struct timespec	until;
-	int		rc;
-
-	if (0 != clock_gettime(CLOCK_REALTIME, &until)) {
-		msyslog(LOG_ERR, "worker_sleep: clock_gettime() failed: %m");
-		return -1;
-	}
-	until.tv_sec += seconds;
-	do {
-		rc = wait_for_sem(c->wake_scheduled_sleep, &until);
-	} while (-1 == rc && EINTR == errno);
-	if (0 == rc)
-		return -1;
-	if (-1 == rc && ETIMEDOUT == errno)
-		return 0;
-	msyslog(LOG_ERR, "worker_sleep: sem_timedwait: %m");
-	return -1;
-}
-
-
-void
-interrupt_worker_sleep(void)
-{
-	u_int			idx;
-	blocking_child *	c;
-
-	for (idx = 0; idx < blocking_children_alloc; idx++) {
-		c = blocking_children[idx];
-		if (NULL == c || NULL == c->wake_scheduled_sleep)
-			continue;
-		sem_post(c->wake_scheduled_sleep);
-	}
-}
-
-
-static void
-ensure_workitems_empty_slot(
-	blocking_child *c
-	)
-{
-	const size_t	each = sizeof(blocking_children[0]->workitems[0]);
-	size_t		new_alloc;
-	size_t		old_octets;
-	size_t		new_octets;
-	void *		nonvol_workitems;
-
-
-	if (c->workitems != NULL &&
-	    NULL == c->workitems[c->next_workitem])
-		return;
-
-	new_alloc = c->workitems_alloc + WORKITEMS_ALLOC_INC;
-	old_octets = c->workitems_alloc * each;
-	new_octets = new_alloc * each;
-	nonvol_workitems = DEVOLATILE(void *, c->workitems);
-	c->workitems = erealloc_zero(nonvol_workitems, new_octets,
-				     old_octets);
-	if (0 == c->next_workitem)
-		c->next_workitem = c->workitems_alloc;
-	c->workitems_alloc = new_alloc;
-}
-
-
-static void
-ensure_workresp_empty_slot(
-	blocking_child *c
-	)
-{
-	const size_t	each = sizeof(blocking_children[0]->responses[0]);
-	size_t		new_alloc;
-	size_t		old_octets;
-	size_t		new_octets;
-	void *		nonvol_responses;
-
-	if (c->responses != NULL &&
-	    NULL == c->responses[c->next_response])
-		return;
-
-	new_alloc = c->responses_alloc + RESPONSES_ALLOC_INC;
-	old_octets = c->responses_alloc * each;
-	new_octets = new_alloc * each;
-	nonvol_responses = DEVOLATILE(void *, c->responses);
-	c->responses = erealloc_zero(nonvol_responses, new_octets,
-				     old_octets);
-	if (0 == c->next_response)
-		c->next_response = c->responses_alloc;
-	c->responses_alloc = new_alloc;
-}
-
-
-/*
- * queue_req_pointer() - append a work item or idle exit request to
- *			 blocking_workitems[].
- */
-static int
-queue_req_pointer(
-	blocking_child	*	c,
-	blocking_pipe_header *	hdr
-	)
-{
-	c->workitems[c->next_workitem] = hdr;
-	c->next_workitem = (1 + c->next_workitem) % c->workitems_alloc;
-
-	/*
-	 * We only want to signal the wakeup event if the child is
-	 * blocking on it, which is indicated by setting the blocking
-	 * event.  Wait with zero timeout to test.
-	 */
-	/* !!!! if (WAIT_OBJECT_0 == WaitForSingleObject(c->child_is_blocking, 0)) */
-		sem_post(c->blocking_req_ready);
-
-	return 0;
-}
-
-
-int
-send_blocking_req_internal(
-	blocking_child *	c,
-	blocking_pipe_header *	hdr,
-	void *			data
-	)
-{
-	blocking_pipe_header *	threadcopy;
-	size_t			payload_octets;
-
-	REQUIRE(hdr != NULL);
-	REQUIRE(data != NULL);
-	DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == hdr->magic_sig);
-
-	if (hdr->octets <= sizeof(*hdr))
-		return 1;	/* failure */
-	payload_octets = hdr->octets - sizeof(*hdr);
-
-	ensure_workitems_empty_slot(c);
-	if (NULL == c->thread_ref) {
-		ensure_workresp_empty_slot(c);
-		start_blocking_thread(c);
-	}
-
-	threadcopy = emalloc(hdr->octets);
-	memcpy(threadcopy, hdr, sizeof(*hdr));
-	memcpy((char *)threadcopy + sizeof(*hdr), data, payload_octets);
-
-	return queue_req_pointer(c, threadcopy);
-}
-
-
-blocking_pipe_header *
-receive_blocking_req_internal(
-	blocking_child *	c
-	)
-{
-	blocking_pipe_header *	req;
-	int			rc;
-
-	/*
-	 * Child blocks here when idle.  SysV semaphores maintain a
-	 * count and release from sem_wait() only when it reaches 0.
-	 */
-	do {
-		rc = wait_for_sem(c->blocking_req_ready, NULL);
-	} while (-1 == rc && EINTR == errno);
-	INSIST(0 == rc);
-
-	req = c->workitems[c->next_workeritem];
-	INSIST(NULL != req);
-	c->workitems[c->next_workeritem] = NULL;
-	c->next_workeritem = (1 + c->next_workeritem) %
-				c->workitems_alloc;
-
-	if (CHILD_EXIT_REQ == req) {	/* idled out */
-		send_blocking_resp_internal(c, CHILD_GONE_RESP);
-		req = NULL;
-	}
-
-	return req;
-}
-
-
-int
-send_blocking_resp_internal(
-	blocking_child *	c,
-	blocking_pipe_header *	resp
-	)
-{
-	ensure_workresp_empty_slot(c);
-
-	c->responses[c->next_response] = resp;
-	c->next_response = (1 + c->next_response) % c->responses_alloc;
-
-#ifdef USE_WORK_PIPE
-	IGNORE(write(c->resp_write_pipe, "", 1));
-#else
-	sem_post(c->blocking_response_ready);
-#endif
-
-	return 0;
-}
-
-
-#ifndef USE_WORK_PIPE
-void
-handle_blocking_resp_sem(
-	void *	context
-	)
-{
-	HANDLE			ready;
-	blocking_child *	c;
-	u_int			idx;
-
-	ready = (HANDLE)context;
-	c = NULL;
-	for (idx = 0; idx < blocking_children_alloc; idx++) {
-		c = blocking_children[idx];
-		if (c != NULL && c->thread_ref != NULL &&
-		    ready == c->blocking_response_ready)
-			break;
-	}
-	if (idx < blocking_children_alloc)
-		process_blocking_resp(c);
-}
-#endif	/* !USE_WORK_PIPE */
-
-
-blocking_pipe_header *
-receive_blocking_resp_internal(
-	blocking_child *	c
-	)
-{
-	blocking_pipe_header *	removed;
-#ifdef USE_WORK_PIPE
-	int			rc;
-	char			scratch[32];
-
-	do {
-		rc = read(c->resp_read_pipe, scratch, sizeof(scratch));
-	} while (-1 == rc && EINTR == errno);
-#endif
-	removed = c->responses[c->next_workresp];
-	if (NULL != removed) {
-		c->responses[c->next_workresp] = NULL;
-		c->next_workresp = (1 + c->next_workresp) %
-				   c->responses_alloc;
-		DEBUG_ENSURE(CHILD_GONE_RESP == removed ||
-			     BLOCKING_RESP_MAGIC == removed->magic_sig);
-	}
-	if (CHILD_GONE_RESP == removed) {
-		cleanup_after_child(c);
-		removed = NULL;
-	}
-
-	return removed;
-}
-
-
-static void
-start_blocking_thread(
-	blocking_child *	c
-	)
-{
-
-	DEBUG_INSIST(!c->reusable);
-
-	prepare_child_sems(c);
-	start_blocking_thread_internal(c);
-}
-
-
-static void
-start_blocking_thread_internal(
-	blocking_child *	c
-	)
-{
-	pthread_attr_t	thr_attr;
-	int		rc;
-	int		pipe_ends[2];	/* read then write */
-	bool		is_pipe;
-	int		flags;
-	size_t		stacksize;
-	sigset_t	saved_sig_mask;
-
-	rc = pipe_socketpair(&pipe_ends[0], &is_pipe);
-	if (0 != rc) {
-		msyslog(LOG_ERR, "start_blocking_thread: pipe_socketpair() %m");
-		exit(1);
-	}
-	c->resp_read_pipe = move_fd(pipe_ends[0]);
-	c->resp_write_pipe = move_fd(pipe_ends[1]);
-	c->ispipe = is_pipe;
-	flags = fcntl(c->resp_read_pipe, F_GETFL, 0);
-	if (-1 == flags) {
-		msyslog(LOG_ERR, "start_blocking_thread: fcntl(F_GETFL) %m");
-		exit(1);
-	}
-	rc = fcntl(c->resp_read_pipe, F_SETFL, O_NONBLOCK | flags);
-	if (-1 == rc) {
-		msyslog(LOG_ERR,
-			"start_blocking_thread: fcntl(F_SETFL, O_NONBLOCK) %m");
-		exit(1);
-	}
-	(*addremove_io_fd)(c->resp_read_pipe, c->ispipe, false);
-	pthread_attr_init(&thr_attr);
-	pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
-	rc = pthread_attr_getstacksize(&thr_attr, &stacksize);
-	if (0 != rc) {
-		errno = rc;
-		msyslog(LOG_ERR,
-			"start_blocking_thread: pthread_attr_getstacksize %m");
-	} else if (stacksize < THREAD_MINSTACKSIZE) {
-		rc = pthread_attr_setstacksize(&thr_attr,
-					       THREAD_MINSTACKSIZE);
-		if (0 != rc) {
-			errno = rc;
-			msyslog(LOG_ERR,
-				"start_blocking_thread: pthread_attr_setstacksize(0x%lx -> 0x%lx) %m",
-				(u_long)stacksize,
-				(u_long)THREAD_MINSTACKSIZE);
-		}
-	}
-	pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM);
-	c->thread_ref = emalloc_zero(sizeof(*c->thread_ref));
-	block_thread_signals(&saved_sig_mask);
-	rc = pthread_create(c->thread_ref, &thr_attr,
-			    &blocking_thread, c);
-	if (0 != rc) {
-	    if (EAGAIN == errno) {
-	        msyslog(LOG_ERR, "EAGAIN from pthread_create(), probably out of (locked) memory");
-	    } else {
-	        msyslog(LOG_ERR, "pthread_create() blocking child: %m");
-	    }
-	    exit(1);
-	}
-	pthread_sigmask(SIG_SETMASK, &saved_sig_mask, NULL);
-	pthread_attr_destroy(&thr_attr);
-}
-
-
-/*
- * block_thread_signals()
- *
- * Temporarily block signals used by ntpd main thread, so that signal
- * mask inherited by child threads leaves them blocked.  Returns prior
- * active signal mask via pmask, to be restored by the main thread
- * after pthread_create().
- */
-void
-block_thread_signals(
-	sigset_t *	pmask
-	)
-{
-	sigset_t	block;
-
-	sigemptyset(&block);
-	sigaddset(&block, SIGALRM);
-	sigaddset(&block, MOREDEBUGSIG);
-	sigaddset(&block, LESSDEBUGSIG);
-	sigaddset(&block, SIGINT);
-	sigaddset(&block, SIGQUIT);
-	sigaddset(&block, SIGTERM);
-	sigaddset(&block, SIGBUS);
-	sigemptyset(pmask);
-	pthread_sigmask(SIG_BLOCK, &block, pmask);
-}
-
-
-/*
- * prepare_child_sems()
- *
- * create sync events (semaphores)
- * child_is_blocking initially unset
- * blocking_req_ready initially unset
- *
- * Child waits for blocking_req_ready to be set after
- * setting child_is_blocking.  blocking_req_ready and
- * blocking_response_ready are auto-reset, so wake one
- * waiter and become unset (unsignalled) in one operation.
- */
-static void
-prepare_child_sems(
-	blocking_child *c
-	)
-{
-	size_t	octets;
-
-	if (NULL == c->blocking_req_ready) {
-		octets = sizeof(*c->blocking_req_ready);
-		octets += sizeof(*c->wake_scheduled_sleep);
-		/* !!!! octets += sizeof(*c->child_is_blocking); */
-		c->blocking_req_ready = emalloc_zero(octets);;
-		c->wake_scheduled_sleep = 1 + c->blocking_req_ready;
-		/* !!!! c->child_is_blocking = 1 + c->wake_scheduled_sleep; */
-	} else {
-		sem_destroy(c->blocking_req_ready);
-		sem_destroy(c->wake_scheduled_sleep);
-		/* !!!! sem_destroy(c->child_is_blocking); */
-	}
-	sem_init(c->blocking_req_ready, false, 0);
-	sem_init(c->wake_scheduled_sleep, false, 0);
-	/* !!!! sem_init(c->child_is_blocking, false, 0); */
-}
-
-
-static int
-wait_for_sem(
-	sem_ref			sem,
-	struct timespec *	timeout		/* wall-clock */
-	)
-	/* pthreads wait_for_sem() follows */
-{
-	int rc;
-
-	if (NULL == timeout)
-		rc = sem_wait(sem);
-	else
-#ifdef sem_timedwait
-		rc = sem_timedwait(sem, timeout);
-#else
-		/* No sem_timedwait on NetBSD - thread stays around forever. */
-		rc = sem_wait(sem);
-#endif
-
-	return rc;
-}
-
-
-/*
- * blocking_thread - thread functions have WINAPI calling convention
- */
-void *
-blocking_thread(
-	void *	ThreadArg
-	)
-{
-	blocking_child *c;
-
-	c = ThreadArg;
-	exit_worker(blocking_child_common(c));
-
-	/* NOTREACHED */
-	return 0;
-}
-
-
-/*
- * req_child_exit() runs in the parent.
- */
-int
-req_child_exit(
-	blocking_child *c
-	)
-{
-	return queue_req_pointer(c, CHILD_EXIT_REQ);
-}
-
-
-/*
- * cleanup_after_child() runs in parent.
- */
-static void
-cleanup_after_child(
-	blocking_child *	c
-	)
-{
-	u_int	idx;
-
-	DEBUG_INSIST(!c->reusable);
-	free(c->thread_ref);
-	c->thread_ref = NULL;
-	c->thread_id = 0;
-#ifdef USE_WORK_PIPE
-	DEBUG_INSIST(-1 != c->resp_read_pipe);
-	DEBUG_INSIST(-1 != c->resp_write_pipe);
-	(*addremove_io_fd)(c->resp_read_pipe, c->ispipe, true);
-	close(c->resp_write_pipe);
-	close(c->resp_read_pipe);
-	c->resp_write_pipe = -1;
-	c->resp_read_pipe = -1;
-#else
-	DEBUG_INSIST(NULL != c->blocking_response_ready);
-	(*addremove_io_semaphore)(c->blocking_response_ready, true);
-#endif
-	for (idx = 0; idx < c->workitems_alloc; idx++)
-		c->workitems[idx] = NULL;
-	c->next_workitem = 0;
-	c->next_workeritem = 0;
-	for (idx = 0; idx < c->responses_alloc; idx++)
-		c->responses[idx] = NULL;
-	c->next_response = 0;
-	c->next_workresp = 0;
-	c->reusable = true;
-}
-
-
-#else	/* !USE_WORK_THREAD follows */
-char work_thread_nonempty_compilation_unit;
-#endif


=====================================
libntp/wscript
=====================================
--- a/libntp/wscript
+++ b/libntp/wscript
@@ -14,9 +14,8 @@ def build(ctx):
         "mstolfp.c",
         "netof.c",
         "ntp_endian.c",
-        "ntp_intres.c",
         "ntp_random.c",
-        "ntp_worker.c",
+        "ntp_dns.c",
         "numtoa.c",
         "recvbuff.c",
         "refidsmear.c",
@@ -24,7 +23,6 @@ def build(ctx):
         "socktoa.c",
         "ssl_init.c",
         "syssignal.c",
-        "work_thread.c",
         "ymd2yd.c",
     ]
 


=====================================
ntpd/ntp_config.c
=====================================
--- a/ntpd/ntp_config.c
+++ b/ntpd/ntp_config.c
@@ -32,6 +32,7 @@
 #include "ntp_stdlib.h"
 #include "lib_strbuf.h"
 #include "ntp_assert.h"
+#include "ntp_dns.h"
 
 /*
  * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
@@ -130,13 +131,6 @@ static struct masks logcfg_class_items[] = {
 	{ NULL,			0 }
 };
 
-typedef struct peer_resolved_ctx_tag {
-	int		host_mode;	/* T_* token identifier */
-	u_short		family;
-	uint8_t		hmode;		/* MODE_* */
-	struct peer_ctl	ctl;
-} peer_resolved_ctx;
-
 /* Limits */
 #define MAXPHONE	10	/* maximum number of phone strings */
 /* #define MAXPPS	20	* maximum length of PPS device string UNUSED */
@@ -200,7 +194,7 @@ static void free_auth_node(config_tree *);
 static void free_all_config_trees(void);
 
 static struct peer *peer_config(sockaddr_u *, const char *,
-				 endpt *, uint8_t, struct peer_ctl *);
+				 endpt *, int, struct peer_ctl *);
 
 static void free_config_access(config_tree *);
 static void free_config_auth(config_tree *);
@@ -287,16 +281,6 @@ static void config_peers(config_tree *);
 static void config_unpeers(config_tree *);
 static void config_nic_rules(config_tree *, bool input_from_file);
 static void config_reset_counters(config_tree *);
-static uint8_t get_correct_host_mode(int token);
-
-#ifdef USE_WORKER
-static void peer_name_resolved(int, int, void *, const char *, const char *,
-			const struct addrinfo *,
-			const struct addrinfo *);
-static void unpeer_name_resolved(int, int, void *, const char *, const char *,
-			  const struct addrinfo *,
-			  const struct addrinfo *);
-#endif
 
 enum gnn_type {
 	t_UNK,		/* Unknown */
@@ -307,8 +291,7 @@ enum gnn_type {
 static uint32_t get_pfxmatch(const char **, struct masks *);
 static uint32_t get_match(const char *, struct masks *);
 static uint32_t get_logmask(const char *);
-static int getnetnum(const char *num, sockaddr_u *addr, int complain,
-		     enum gnn_type a_type);
+static int getnetnum(const char *num, sockaddr_u *addr);
 
 
 /* FUNCTIONS FOR INITIALIZATION
@@ -1733,7 +1716,7 @@ config_access(
 			AF(&addr) = (u_short)my_node->addr->type;
 
 			if (getnetnum(my_node->addr->address,
-				      &addr, 1, t_UNK) != 1) {
+				      &addr) != 1) {
 				/*
 				 * Attempt a blocking lookup.  This
 				 * is in violation of the nonblocking
@@ -1780,7 +1763,7 @@ config_access(
 				ZERO_SOCK(&mask);
 				AF(&mask) = my_node->mask->type;
 				if (getnetnum(my_node->mask->address,
-					      &mask, 1, t_MSK) != 1) {
+					      &mask) != 1) {
 					msyslog(LOG_ERR,
 						"restrict: ignoring line %d, mask '%s' unusable.",
 						my_node->line_no,
@@ -2313,7 +2296,7 @@ config_fudge(
 		 */
 		addr_node = curr_fudge->addr;
 		ZERO_SOCK(&addr_sock);
-		if (getnetnum(addr_node->address, &addr_sock, 1, t_REF)
+		if (getnetnum(addr_node->address, &addr_sock)
 		    != 1) {
 			err_flag = true;
 			msyslog(LOG_ERR,
@@ -2564,30 +2547,40 @@ peer_config(
 	sockaddr_u *	srcadr,
 	const char *	hostname,
 	endpt *		dstadr,
-	uint8_t		hmode,
+	int		htype,
 	struct peer_ctl  *ctl)
 {
 	uint8_t cast_flags;
+	uint8_t hmode;
 
 	/*
 	 * We do a dirty little jig to figure the cast flags. This is
 	 * probably not the best place to do this, at least until the
 	 * configure code is rebuilt. Note only one flag can be set.
 	 */
-	switch (hmode) {
-	case MODE_BROADCAST:
+	switch (htype) {
+	case T_Broadcast:
 		cast_flags = MDF_BCAST;
+		hmode = MODE_BROADCAST;
 		break;
 
-	case MODE_CLIENT:
-		if (hostname != NULL && SOCK_UNSPEC(srcadr))
-			cast_flags = MDF_POOL;
-		else
-			cast_flags = MDF_UCAST;
+	case T_Pool:
+		cast_flags = MDF_POOL;
+		hmode = MODE_CLIENT;
+		ctl->flags &= ~FLAG_PREEMPT;
+		break;
+
+	case T_Server:
+		cast_flags = MDF_UCAST;
+		hmode = MODE_CLIENT;
+		if (NULL != hostname)
+			ctl->flags |= FLAG_DNS;
 		break;
 
 	default:
+msyslog(LOG_ERR, "peer_config, strange htype: %d", htype);
 		cast_flags = MDF_UCAST;
+		hmode = MODE_CLIENT;
 	}
 
 	/*
@@ -2600,32 +2593,11 @@ peer_config(
 	ctl->flags |= FLAG_CONFIG;
 	if (mode_ntpdate)
 		ctl->flags |= FLAG_IBURST;
-	if (MDF_POOL & cast_flags)
-		ctl->flags &= ~FLAG_PREEMPT;
 	return newpeer(srcadr, hostname, dstadr, hmode, ctl->version,
 		       ctl->minpoll, ctl->maxpoll, (u_int)ctl->flags,
 		       cast_flags, ctl->ttl, ctl->peerkey, true);
 }
 
-static uint8_t
-get_correct_host_mode(
-	int token
-	)
-{
-	switch (token) {
-
-	case T_Server:
-	case T_Pool:
-	case T_Peer:
-		return MODE_CLIENT;
-
-	case T_Broadcast:
-		return MODE_BROADCAST;
-
-	default:
-		return 0;
-	}
-}
 
 static void
 config_peers(
@@ -2633,10 +2605,7 @@ config_peers(
 	)
 {
     sockaddr_u		peeraddr;
-    struct addrinfo		hints;
     peer_node *		curr_peer;
-    peer_resolved_ctx *	ctx;
-    uint8_t			hmode;
 
     /* add servers named on the command line with iburst implied */
     for ( ; cmdline_server_count > 0;
@@ -2664,37 +2633,16 @@ config_peers(
 				&peeraddr,
 				NULL,
 				NULL,
-				MODE_CLIENT,
+				T_Server,
 				&client_ctl);
 	    } else {
 		/* we have a hostname to resolve */
-# ifdef USE_WORKER
-		ctx = emalloc_zero(sizeof(*ctx));
-		ctx->family = AF_UNSPEC;
-		ctx->host_mode = T_Server;
-		ctx->hmode = MODE_CLIENT;
-		ctx->ctl.flags   = FLAG_IBURST;
-		ctx->ctl.maxpoll = NTP_MAXPOLL_UNK;
-		ctx->ctl.minpoll = NTP_MINDPOLL;
-		ctx->ctl.peerkey = 0;
-		ctx->ctl.ttl     = 0;
-		ctx->ctl.version = NTP_VERSION;
-
-		ZERO(hints);
-		hints.ai_family = (u_short)ctx->family;
-		hints.ai_socktype = SOCK_DGRAM;
-		hints.ai_protocol = IPPROTO_UDP;
-
-		getaddrinfo_sometime(*cmdline_servers,
-				     "ntp", &hints,
-				     INITIAL_DNS_RETRY,
-				     &peer_name_resolved,
-				     (void *)ctx);
-# else	/* !USE_WORKER follows */
-		msyslog(LOG_ERR,
-		    "hostname %s can not be used (%s), use IP address instead.",
-		    curr_peer->addr->address, gai_strerror(a_info));
-# endif
+		peer_config(
+			&peeraddr,
+			*cmdline_servers,
+			NULL,
+			T_Server,
+			&client_ctl);
 	    }
     }
 
@@ -2702,9 +2650,6 @@ config_peers(
     curr_peer = HEAD_PFIFO(ptree->peers);
     for (; curr_peer != NULL; curr_peer = curr_peer->link) {
 	ZERO_SOCK(&peeraddr);
-	/* Find the correct host-mode */
-	hmode = get_correct_host_mode(curr_peer->host_mode);
-	INSIST(hmode != 0);
 
 	if (T_Pool == curr_peer->host_mode) {
 	    AF(&peeraddr) = curr_peer->addr->type;
@@ -2712,7 +2657,7 @@ config_peers(
 		    &peeraddr,
 		    curr_peer->addr->address,
 		    NULL,
-		    hmode,
+		    curr_peer->host_mode,
 		    &curr_peer->ctl);
 	/*
 	 * If we have a numeric address, we can safely
@@ -2733,7 +2678,7 @@ config_peers(
 			&peeraddr,
 			NULL,
 			NULL,
-			hmode,
+			curr_peer->host_mode,
 			&curr_peer->ctl);
 		if ( NULL == peer )
 		{
@@ -2785,109 +2730,19 @@ config_peers(
 		}
 
 	    }
-	/*
-	 * synchronous lookup may be forced.
-	 */
+	/* DNS lookup */
 	} else {
-	    /* hand the hostname off to the blocking child */
-# ifdef USE_WORKER
-	    ctx = emalloc_zero(sizeof(*ctx));
-	    ctx->family = curr_peer->addr->type;
-	    ctx->host_mode = curr_peer->host_mode;
-	    ctx->hmode = hmode;
-	    ctx->ctl = curr_peer->ctl;
-
-	    ZERO(hints);
-	    hints.ai_family = ctx->family;
-	    hints.ai_socktype = SOCK_DGRAM;
-	    hints.ai_protocol = IPPROTO_UDP;
-
-	    getaddrinfo_sometime(curr_peer->addr->address,
-				 "ntp", &hints,
-				 INITIAL_DNS_RETRY,
-				 &peer_name_resolved, ctx);
-# else	/* !USE_WORKER follows */
-	    msyslog(LOG_ERR,
-		"hostname %s can not be used, please use IP address instead.",
-		curr_peer->addr->address);
-# endif
+	    AF(&peeraddr) = curr_peer->addr->type;
+	    peer_config(
+		&peeraddr,
+		curr_peer->addr->address,
+		NULL,
+		curr_peer->host_mode,
+		&curr_peer->ctl);
 	}
     }
 }
 
-/*
- * peer_name_resolved()
- *
- * Callback invoked when config_peers()'s DNS lookup completes.
- */
-#ifdef USE_WORKER
-static void
-peer_name_resolved(
-	int			rescode,
-	int			gai_errno,
-	void *			context,
-	const char *		name,
-	const char *		service,
-	const struct addrinfo *	hints,
-	const struct addrinfo *	res
-	)
-{
-	sockaddr_u		peeraddr;
-	peer_resolved_ctx *	ctx;
-	u_short			af;
-	const char *		fam_spec;
-
-	(void)gai_errno;
-	(void)service;
-	(void)hints;
-	ctx = context;
-
-	DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode));
-
-	if (rescode) {
-#ifndef ENABLE_DNS_RETRY
-		free(ctx);
-		msyslog(LOG_ERR,
-			"giving up resolving host %s: %s (%d)",
-			name, gai_strerror(rescode), rescode);
-#else	/* ENABLE_DNS_RETRY follows */
-		getaddrinfo_sometime(name, service, hints,
-				     INITIAL_DNS_RETRY,
-				     &peer_name_resolved, context);
-#endif
-		return;
-	}
-
-	/* Loop to configure a single association */
-	for (; res != NULL; res = res->ai_next) {
-		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
-		if (is_sane_resolved_address(&peeraddr,
-					     ctx->host_mode)) {
-			NLOG(NLOG_SYSINFO) {
-				af = ctx->family;
-				fam_spec = (AF_INET6 == af)
-					       ? "(AAAA) "
-					       : (AF_INET == af)
-						     ? "(A) "
-						     : "";
-				msyslog(LOG_INFO, "DNS %s %s-> %s",
-					name, fam_spec,
-					socktoa(&peeraddr));
-			}
-			peer_config(
-				&peeraddr,
-				NULL,
-				NULL,
-				ctx->hmode,
-				&ctx->ctl);
-			break;
-		}
-	}
-	free(ctx);
-}
-#endif	/* USE_WORKER */
-
-
 static void
 free_config_peers(
 	config_tree *ptree
@@ -2915,7 +2770,6 @@ config_unpeers(
 	)
 {
 	sockaddr_u		peeraddr;
-	struct addrinfo		hints;
 	unpeer_node *		curr_unpeer;
 	struct peer *		p;
 	const char *		name;
@@ -2947,7 +2801,7 @@ config_unpeers(
 		ZERO(peeraddr);
 		AF(&peeraddr) = curr_unpeer->addr->type;
 		name = curr_unpeer->addr->address;
-		rc = getnetnum(name, &peeraddr, 0, t_UNK);
+		rc = getnetnum(name, &peeraddr);
 		/* Do we have a numeric address? */
 		if (rc > 0) {
 			DPRINTF(1, ("unpeer: searching for %s\n",
@@ -2962,94 +2816,15 @@ config_unpeers(
 
 			continue;
 		}
-		/*
-		 * It's not a numeric IP address, it's a hostname.
-		 * Check for associations with a matching hostname.
-		 */
-		for (p = peer_list; p != NULL; p = p->p_link)
-			if (p->hostname != NULL)
-				if (!strcasecmp(p->hostname, name))
-					break;
+		/* It's not a numeric IP address, it's a hostname. */
+		p = findexistingpeer(NULL, name, NULL, -1);
 		if (p != NULL) {
 			msyslog(LOG_NOTICE, "unpeered %s", name);
 			peer_clear(p, "GONE", true);
 			unpeer(p);
 		}
-		/* Resolve the hostname to address(es). */
-# ifdef USE_WORKER
-		ZERO(hints);
-		hints.ai_family = curr_unpeer->addr->type;
-		hints.ai_socktype = SOCK_DGRAM;
-		hints.ai_protocol = IPPROTO_UDP;
-		getaddrinfo_sometime(name, "ntp", &hints,
-				     INITIAL_DNS_RETRY,
-				     &unpeer_name_resolved, NULL);
-# else	/* !USE_WORKER follows */
-		msyslog(LOG_ERR,
-			"hostname %s can not be used, please use IP address instead.",
-			name);
-# endif
-	}
-}
-
-
-/*
- * unpeer_name_resolved()
- *
- * Callback invoked when config_unpeers()'s DNS lookup completes.
- */
-#ifdef USE_WORKER
-static void
-unpeer_name_resolved(
-	int			rescode,
-	int			gai_errno,
-	void *			context,
-	const char *		name,
-	const char *		service,
-	const struct addrinfo *	hints,
-	const struct addrinfo *	res
-	)
-{
-	sockaddr_u	peeraddr;
-	struct peer *	peer;
-	u_short		af;
-	const char *	fam_spec;
-
-	(void)gai_errno;
-	(void)context;
-	(void)service;
-	(void)hints;
-	DPRINTF(1, ("unpeer_name_resolved(%s) rescode %d\n", name, rescode));
-
-	if (rescode) {
-		msyslog(LOG_ERR, "giving up resolving unpeer %s: %s (%d)",
-			name, gai_strerror(rescode), rescode);
-		return;
-	}
-	/*
-	 * Loop through the addresses found
-	 */
-	for (; res != NULL; res = res->ai_next) {
-		INSIST(res->ai_addrlen <= sizeof(peeraddr));
-		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
-		DPRINTF(1, ("unpeer: searching for peer %s\n",
-			    socktoa(&peeraddr)));
-		peer = findexistingpeer(&peeraddr, NULL, NULL, -1);
-		if (peer != NULL) {
-			af = AF(&peeraddr);
-			fam_spec = (AF_INET6 == af)
-				       ? "(AAAA) "
-				       : (AF_INET == af)
-					     ? "(A) "
-					     : "";
-			msyslog(LOG_NOTICE, "unpeered %s %s-> %s", name,
-				fam_spec, socktoa(&peeraddr));
-			peer_clear(peer, "GONE", true);
-			unpeer(peer);
-		}
 	}
 }
-#endif	/* USE_WORKER */
 
 
 static void
@@ -3560,13 +3335,9 @@ gettokens_netinfo (
 static int
 getnetnum(
 	const char *num,
-	sockaddr_u *addr,
-	int complain,
-	enum gnn_type a_type	/* ignored */
+	sockaddr_u *addr
 	)
 {
-	UNUSED_ARG(complain);
-	UNUSED_ARG(a_type);
 
 	NTP_REQUIRE(AF_UNSPEC == AF(addr) ||
 		    AF_INET == AF(addr) ||


=====================================
ntpd/ntp_io.c
=====================================
--- a/ntpd/ntp_io.c
+++ b/ntpd/ntp_io.c
@@ -18,8 +18,8 @@
 #include "ntp_lists.h"
 #include "ntp_refclock.h"
 #include "ntp_stdlib.h"
-#include "ntp_worker.h"
 #include "ntp_assert.h"
+#include "ntp_dns.h"
 #include "timespecops.h"
 
 #include <isc/mem.h>
@@ -246,12 +246,12 @@ static void		calc_addr_distance(sockaddr_u *,
 					   const sockaddr_u *);
 static int		cmp_addr_distance(const sockaddr_u *,
 					  const sockaddr_u *);
+static void		maintain_activefds(int fd, bool closing);
 
 /*
  * Routines to read the ntp packets
  */
 static inline int	read_network_packet	(SOCKET, endpt *, l_fp);
-static void ntpd_addremove_io_fd (int, int, int);
 static void input_handler (fd_set *, l_fp *);
 #ifdef REFCLOCK
 static int	read_refclock_packet	(SOCKET, struct refclockio *, l_fp);
@@ -262,13 +262,14 @@ static int	read_refclock_packet	(SOCKET, struct refclockio *, l_fp);
  */
 volatile bool sawALRM = false;
 volatile bool sawHUP = false;
+volatile bool sawDNS = false;
 volatile bool sawQuit = false;  /* SIGQUIT, SIGINT, SIGTERM */
 sigset_t blockMask;
 
 void
 maintain_activefds(
 	int fd,
-	int closing
+	bool closing
 	)
 {
 	int i;
@@ -374,23 +375,6 @@ init_io(void)
 	sigaddset(&blockMask, SIGTERM);
 	sigaddset(&blockMask, SIGHUP);
 
-
-#ifdef USE_WORK_PIPE
-	addremove_io_fd = &ntpd_addremove_io_fd;
-#endif
-}
-
-
-static void
-ntpd_addremove_io_fd(
-	int	fd,
-	int	is_pipe,
-	int	remove_it
-	)
-{
-	UNUSED_ARG(is_pipe);
-
-	maintain_activefds(fd, remove_it);
 }
 
 
@@ -1262,7 +1246,7 @@ interface_update(
 #ifdef DEBUG
 	msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver");
 #endif
-	interrupt_worker_sleep();
+	dns_new_interface();
 }
 
 
@@ -2396,7 +2380,7 @@ io_handler(void)
 	 * reception of input.
 	 */
 	pthread_sigmask(SIG_BLOCK, &blockMask, &runMask);
-	flag = sawALRM || sawQuit || sawHUP;
+	flag = sawALRM || sawQuit || sawHUP || sawDNS;
 	if (!flag) {
 	  rdfdes = activefds;
 	  nfound = pselect(maxactivefd+1, &rdfdes, NULL, NULL, NULL, &runMask);
@@ -2409,11 +2393,6 @@ io_handler(void)
 	if (nfound > 0) {
 		l_fp ts;
 
-		/*
-		 * Doesn't need to be intercepted, because the time
-		 * algorithms don't use it.  It's strictly internal
-		 * to the I/O handling.
-		 */
 		get_systime(&ts);
 
 		input_handler(&rdfdes, &ts);
@@ -2439,7 +2418,6 @@ input_handler(
 	)
 {
 	int		buflen;
-	u_int		idx;
 	int		doing;
 	SOCKET		fd;
 	l_fp		ts;	/* Timestamp at BOselect() gob */
@@ -2553,19 +2531,6 @@ input_handler(
 #endif /* USE_ROUTING_SOCKET */
 
 	/*
-	 * Check for a response from a blocking child
-	 */
-	for (idx = 0; idx < blocking_children_alloc; idx++) {
-		blocking_child *c = blocking_children[idx];
-		if (NULL == c || -1 == c->resp_read_pipe)
-			continue;
-		if (FD_ISSET(c->resp_read_pipe, fds)) {
-			select_count++;
-			process_blocking_resp(c);
-		}
-	}
-
-	/*
 	 * Done everything from that select.
 	 * If nothing to do, just return.
 	 * If an error occurred, complain and return.
@@ -3089,24 +3054,6 @@ io_closeclock(
 #endif	/* REFCLOCK */
 
 
-void
-kill_asyncio(
-	int	startfd
-	)
-{
-	UNUSED_ARG(startfd);
-
-	/*
-	 * In the child process we do not maintain activefds and
-	 * maxactivefd.  Zeroing maxactivefd disables code which
-	 * maintains it in close_and_delete_fd_from_list().
-	 */
-	maxactivefd = 0;
-
-	while (fd_list != NULL)
-		close_and_delete_fd_from_list(fd_list->fd);
-}
-
 /*
  * Add and delete functions for the list of open sockets
  */
@@ -3122,7 +3069,7 @@ add_fd_to_list(
 	lsock->type = type;
 
 	LINK_SLIST(fd_list, lsock, link);
-	maintain_activefds(fd, 0);
+	maintain_activefds(fd, false);
 }
 
 
@@ -3160,7 +3107,7 @@ close_and_delete_fd_from_list(
 	/*
 	 * remove from activefds
 	 */
-	maintain_activefds(fd, 1);
+	maintain_activefds(fd, true);
 }
 
 


=====================================
ntpd/ntp_peer.c
=====================================
--- a/ntpd/ntp_peer.c
+++ b/ntpd/ntp_peer.c
@@ -9,6 +9,7 @@
 #include "ntpd.h"
 #include "ntp_lists.h"
 #include "ntp_stdlib.h"
+#include "ntp_dns.h"
 
 /*
  *		    Table of valid association combinations
@@ -473,9 +474,6 @@ free_peer(
 	if (p->hostname != NULL)
 		free(p->hostname);
 
-	if (p->addrs != NULL)
-		free(p->addrs);		/* from copy_addrinfo_list() */
-
 	/* Add his corporeal form to peer free list */
 	ZERO(*p);
 	LINK_SLIST(peer_free, p, p_link);
@@ -491,6 +489,7 @@ unpeer(
 	struct peer *peer
 	)
 {
+	dns_cancel(peer);
 	mprintf_event(PEVNT_DEMOBIL, peer, "assoc %u", peer->associd);
 	restrict_source(&peer->srcadr, true, 0);
 	set_peerdstadr(peer, NULL);
@@ -623,7 +622,7 @@ newpeer(
 	uint8_t		maxpoll,
 	u_int		flags,
 	uint8_t		cast_flags,
-	uint32_t		ttl,
+	uint32_t	ttl,
 	keyid_t		key,
 	bool		initializing1
 	)
@@ -631,10 +630,8 @@ newpeer(
 	struct peer *	peer;
 	u_int		hash;
 
-	/*
-	 * For now only pool associations have a hostname.
-	 */
-	NTP_INSIST(NULL == hostname || (MDF_POOL & cast_flags));
+msyslog(LOG_INFO, "newpeer: addr:%s, name:%s, flags:%x",
+  socktoa(srcadr), hostname, cast_flags);
 
 	/*
 	 * First search from the beginning for an association with given
@@ -756,9 +753,11 @@ newpeer(
 	/*
 	 * Put the new peer in the hash tables.
 	 */
-	hash = NTP_HASH_ADDR(&peer->srcadr);
-	LINK_SLIST(peer_hash[hash], peer, adr_link);
-	peer_hash_count[hash]++;
+	if (FLAG_DNS && flags) {
+		hash = NTP_HASH_ADDR(&peer->srcadr);
+		LINK_SLIST(peer_hash[hash], peer, adr_link);
+		peer_hash_count[hash]++;
+	}
 	hash = peer->associd & NTP_HASH_MASK;
 	LINK_SLIST(assoc_hash[hash], peer, aid_link);
 	assoc_hash_count[hash]++;
@@ -773,6 +772,14 @@ newpeer(
 	return peer;
 }
 
+void peer_update_hash (struct peer *peer)
+{
+	u_int	hash;
+
+	hash = NTP_HASH_ADDR(&peer->srcadr);
+	LINK_SLIST(peer_hash[hash], peer, adr_link);
+	peer_hash_count[hash]++;
+}
 
 /*
  * peer_clr_stats - clear peer module statistics counters


=====================================
ntpd/ntp_proto.c
=====================================
--- a/ntpd/ntp_proto.c
+++ b/ntpd/ntp_proto.c
@@ -8,6 +8,7 @@
 #include "ntp_endian.h"
 #include "ntp_stdlib.h"
 #include "ntp_leapsec.h"
+#include "ntp_dns.h"
 #include "refidsmear.h"
 #include "timespecops.h"
 
@@ -156,17 +157,11 @@ static	double	root_distance	(struct peer *);
 static	void	clock_combine	(peer_select *, int, int);
 static	void	peer_xmit	(struct peer *);
 static	void	fast_xmit	(struct recvbuf *, int, keyid_t, int);
-static	void	pool_xmit	(struct peer *);
 static	void	clock_update	(struct peer *);
 static	void	measure_precision(const bool);
 static	double	measure_tick_fuzz(void);
 static	int	local_refid	(struct peer *);
 static	int	peer_unfit	(struct peer *);
-#ifdef USE_WORKER
-void	pool_name_resolved	(int, int, void *, const char *,
-				 const char *, const struct addrinfo *,
-				 const struct addrinfo *);
-#endif /* USE_WORKER */
 
 
 void
@@ -900,15 +895,27 @@ transmit(
 	 * resulted in 60 associations without the hard limit.
 	 */
 	if (peer->cast_flags & MDF_POOL) {
+		/* FIXME-DNS turn on FLAG_DNS for pool */
 		peer->outdate = current_time;
 		if ((peer_associations <= 2 * sys_maxclock) &&
 		    (peer_associations < sys_maxclock ||
 		     sys_survivors < sys_minclock))
-			pool_xmit(peer);
+			dns_probe(peer);
+		/* FIXME-DNS - need proper backoff */
 		poll_update(peer, hpoll);
 		return;
 	}
 
+	/* Does server need DNS lookup? */
+	if (peer->flags & FLAG_DNS) {
+		peer->outdate = current_time;
+		dns_probe(peer);
+		/* FIXME-DNS - need proper backoff */
+		poll_update(peer, hpoll);
+		return;
+        }
+
+
 	/*
 	 * In unicast modes the dance is much more intricate. It is
 	 * designed to back off whenever possible to minimize network
@@ -1260,10 +1267,6 @@ poll_update(
 			next = 1U << hpoll;
 		else
 #endif /* REFCLOCK */
-			/*
-			 * Doesn't need to be captured, because the poll interval
-			 * has no effect on replay.
-			 */
 			next = ((0x1000UL | (ntp_random() & 0x0ff)) <<
 			    hpoll) >> 12;
 		next += peer->outdate;
@@ -2409,131 +2412,98 @@ fast_xmit(
 
 
 /*
- * pool_xmit - resolve hostname or send unicast solicitation for pool.
+ * server_take_dns - process DNS query for server.
  */
-static void
-pool_xmit(
-	struct peer *pool	/* pool solicitor association */
+void
+server_take_dns(
+	struct peer *server,
+	struct addrinfo *ai
 	)
 {
-#ifdef USE_WORKER
-	struct pkt		xpkt;	/* transmit packet structure */
-	struct addrinfo		hints;
-	int			rc;
-	endpt *			lcladr;
 	sockaddr_u *		rmtadr;
 	int			restrict_mask;
 	struct peer *		p;
-	l_fp			xmt_tx;
-
-	if (NULL == pool->ai) {
-		if (pool->addrs != NULL) {
-			/* free() is used with copy_addrinfo_list() */
-			free(pool->addrs);
-			pool->addrs = NULL;
-		}
-		ZERO(hints);
-		hints.ai_family = AF(&pool->srcadr);
-		hints.ai_socktype = SOCK_DGRAM;
-		hints.ai_protocol = IPPROTO_UDP;
-		/* ignore getaddrinfo_sometime() errors, we will retry */
-		rc = getaddrinfo_sometime(
-			pool->hostname,
-			"ntp",
-			&hints,
-			0,			/* no retry */
-			&pool_name_resolved,
-			(void *)(intptr_t)pool->associd);
-		if (!rc)
-			DPRINTF(1, ("pool DNS lookup %s started\n",
-				pool->hostname));
-		else
-			msyslog(LOG_ERR,
-				"unable to start pool DNS %s %m",
-				pool->hostname);
-		return;
-	}
 
-	do {
-		/* copy_addrinfo_list ai_addr points to a sockaddr_u */
-		rmtadr = (sockaddr_u *)(void *)pool->ai->ai_addr;
-		pool->ai = pool->ai->ai_next;
+	for ( ; NULL != ai; ai = ai->ai_next)  {
+		rmtadr = (sockaddr_u *)(void *)ai->ai_addr;
+msyslog(LOG_INFO, "Server checking: %s", socktoa(rmtadr));
 		p = findexistingpeer(rmtadr, NULL, NULL, MODE_CLIENT);
-	} while (p != NULL && pool->ai != NULL);
-	if (p != NULL)
-		return;	/* out of addresses, re-query DNS next poll */
-	restrict_mask = restrictions(rmtadr);
-	if (RES_FLAGS & restrict_mask)
-		restrict_source(rmtadr, false,
-				current_time + POOL_SOLICIT_WINDOW + 1);
-	lcladr = findinterface(rmtadr);
-	memset(&xpkt, 0, sizeof(xpkt));
-	xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, pool->version,
-					 MODE_CLIENT);
-	xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
-	xpkt.ppoll = pool->hpoll;
-	xpkt.precision = sys_precision;
-	xpkt.refid = sys_refid;
-	xpkt.rootdelay = HTONS_FP(DTOUFP(sys_rootdelay));
-	xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
-	xpkt.reftime = htonl_fp(sys_reftime);
-	get_systime(&xmt_tx);
-	pool->org = xmt_tx;
-	xpkt.xmt = htonl_fp(xmt_tx);
-	sendpkt(rmtadr, lcladr, &xpkt, LEN_PKT_NOMAC);
-	pool->sent++;
-	pool->throttle += (1 << pool->minpoll) - 2;
-#ifdef DEBUG
-	if (debug)
-		printf("transmit: at %lu %s->%s pool\n",
-		    current_time, latoa(lcladr), socktoa(rmtadr));
-#endif
-	msyslog(LOG_INFO, "Soliciting pool server %s", socktoa(rmtadr));
-#endif	/* USE_WORKER */
+		if (NULL != p) continue;  /* already in use */
+
+msyslog(LOG_INFO, "Server trying: %s", socktoa(rmtadr));
+		
+		restrict_mask = restrictions(rmtadr);
+		if (RES_FLAGS & restrict_mask)
+			restrict_source(rmtadr, false, 0);
+
+		server->srcadr = *rmtadr;
+		server->dstadr = findinterface(rmtadr);
+if (NULL == server->dstadr)
+  msyslog(LOG_ERR, "server_take_dns: can't find interface for %s", server->hostname);
+		server->flags &= ~FLAG_DNS;
+		server->hpoll = server->minpoll;
+		server->nextdate = current_time;
+		peer_update_hash(server);
+		peer_xmit(server);
+
+		DPRINTF(1, ("transmit: at %ld %s->%s pool\n",
+		    current_time, latoa(lcladr), socktoa(rmtadr)));
+		msyslog(LOG_INFO, "Setup server %s", socktoa(rmtadr));
+		return;
+	};
 }
 
-
-#ifdef USE_WORKER
+/*
+ pool_take_dns - process DNS query for pool.
+ */
 void
-pool_name_resolved(
-	int			rescode,
-	int			gai_errno,
-	void *			context,
-	const char *		name,
-	const char *		service,
-	const struct addrinfo *	hints,
-	const struct addrinfo *	res
+pool_take_dns(
+	struct peer *pool,	/* pool solicitor association */
+	struct addrinfo *ai	/* answer from getaddrinfo */
 	)
 {
-	struct peer *	pool;	/* pool solicitor association */
-	associd_t	assoc;
-
-	UNUSED_ARG(gai_errno);
-	UNUSED_ARG(service);
-	UNUSED_ARG(hints);
+	struct pkt		xpkt;	/* transmit packet structure */
+	endpt *			lcladr;
+	sockaddr_u *		rmtadr;
+	int			restrict_mask;
+	struct peer *		p;
+	l_fp			xmt_tx;
 
-	if (rescode) {
-		msyslog(LOG_ERR,
-			"error resolving pool %s: %s (%d)",
-			name, gai_strerror(rescode), rescode);
-		return;
-	}
+	for ( ; NULL != ai; ai = ai->ai_next)  {
+		rmtadr = (sockaddr_u *)(void *)ai->ai_addr;
+msyslog(LOG_INFO, "Pool checking: %s", socktoa(rmtadr));
+		p = findexistingpeer(rmtadr, NULL, NULL, MODE_CLIENT);
+		if (NULL != p) continue;  /* already in use */
 
-	assoc = (associd_t)(intptr_t)context;
-	pool = findpeerbyassoc(assoc);
-	if (NULL == pool) {
-		msyslog(LOG_ERR,
-			"Could not find assoc %u for pool DNS %s",
-			assoc, name);
-		return;
-	}
-	DPRINTF(1, ("pool DNS %s completed\n", name));
-	pool->addrs = copy_addrinfo_list(res);
-	pool->ai = pool->addrs;
-	pool_xmit(pool);
+msyslog(LOG_INFO, "Pool trying: %s", socktoa(rmtadr));
+		restrict_mask = restrictions(rmtadr);
+		/* FIXME-DNS: RES_FLAGS includes RES_DONTSERVE?? */
+		if (RES_FLAGS & restrict_mask)
+			restrict_source(rmtadr, false,
+				current_time + POOL_SOLICIT_WINDOW + 1);
+		lcladr = findinterface(rmtadr);
+		memset(&xpkt, 0, sizeof(xpkt));
+		xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, pool->version,
+					 MODE_CLIENT);
+		xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
+		xpkt.ppoll = pool->hpoll;
+		xpkt.precision = sys_precision;
+		xpkt.refid = sys_refid;
+		xpkt.rootdelay = HTONS_FP(DTOUFP(sys_rootdelay));
+		xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
+		xpkt.reftime = htonl_fp(sys_reftime);
+		get_systime(&xmt_tx);
+		pool->org = xmt_tx;
+		xpkt.xmt = htonl_fp(xmt_tx);
+		sendpkt(rmtadr, lcladr, &xpkt, LEN_PKT_NOMAC);
+		pool->sent++;
+		pool->throttle += (1 << pool->minpoll) - 2;
 
+		DPRINTF(1, ("transmit: at %ld %s->%s pool\n",
+		    current_time, latoa(lcladr), socktoa(rmtadr)));
+		msyslog(LOG_INFO, "Soliciting pool server %s", socktoa(rmtadr));
+	};
 }
-#endif	/* USE_WORKER */
 
 
 /*


=====================================
ntpd/ntp_sandbox.c
=====================================
--- a/ntpd/ntp_sandbox.c
+++ b/ntpd/ntp_sandbox.c
@@ -356,6 +356,7 @@ int scmp_sc[] = {
 	SCMP_SYS(clone),	/* threads */
 	SCMP_SYS(exit),
 	SCMP_SYS(futex),	/* sem_xxx */
+	SCMP_SYS(kill),		/* generate signal */
 	SCMP_SYS(madvise),
 	SCMP_SYS(mprotect),
 	SCMP_SYS(set_robust_list),


=====================================
ntpd/ntp_timer.c
=====================================
--- a/ntpd/ntp_timer.c
+++ b/ntpd/ntp_timer.c
@@ -45,7 +45,6 @@ static	u_long adjust_timer;	/* second timer */
 static	u_long stats_timer;	/* stats timer */
 static	u_long leapf_timer;	/* Report leapfile problems once/day */
 static	u_long huffpuff_timer;	/* huff-n'-puff timer */
-static	u_long worker_idle_timer;/* next check for idle intres */
 u_long	leapsec;	        /* seconds to next leap (proximity class) */
 u_int	leap_smear_intv;	/* Duration of smear.  Enables smear mode. */
 int	leapdif;		/* TAI difference step at next leap second*/
@@ -169,27 +168,6 @@ init_timer(void)
 }
 
 
-/*
- * intres_timeout_req(s) is invoked in the parent to schedule an idle
- * timeout to fire in s seconds, if not reset earlier by a call to
- * intres_timeout_req(0), which clears any pending timeout.  When the
- * timeout expires, worker_idle_timer_fired() is invoked (again, in the
- * parent).
- *
- * ntpdig and ntpd each provide implementations adapted to their timers.
- */
-void
-intres_timeout_req(
-	u_int	seconds		/* 0 cancels */
-	)
-{
-	if (0 == seconds) {
-		worker_idle_timer = 0;
-		return;
-	}
-	worker_idle_timer = current_time + seconds;
-}
-
 
 /*
  * timer - event timer
@@ -304,9 +282,6 @@ timer(void)
 		interface_update(NULL, NULL);
 	}
 
-	if (worker_idle_timer && worker_idle_timer <= current_time)
-		worker_idle_timer_fired();
-
 	/*
 	 * Finally, write hourly stats and do the hourly
 	 * and daily leapfile checks.


=====================================
ntpd/ntpd.c
=====================================
--- a/ntpd/ntpd.c
+++ b/ntpd/ntpd.c
@@ -12,6 +12,7 @@
 #include "ntp_config.h"
 #include "ntp_syslog.h"
 #include "ntp_assert.h"
+#include "ntp_dns.h"
 #include "isc/error.h"
 #include "isc/formatcheck.h"
 
@@ -95,6 +96,7 @@ static int	wait_child_sync_if	(int, long);
 #endif
 
 static	void	catchHUP	(int);
+static	void	catchDNS	(int);
 
 # ifdef	DEBUG
 static	void	moredebug	(int);
@@ -653,6 +655,7 @@ ntpdmain(
 	signal_no_reset(SIGTERM, catchQuit);
 	signal_no_reset(SIGHUP, catchHUP);
 	signal_no_reset(SIGBUS, catchQuit);  /* FIXME: It's broken, can't continue. */
+	signal_no_reset(SIGDNS, catchDNS);
 
 # ifdef DEBUG
 	(void) signal_no_reset(MOREDEBUGSIG, moredebug);
@@ -889,8 +892,13 @@ static void mainloop(void)
 			 * Out here, signals are unblocked.  Call timer routine
 			 * to process expiry.
 			 */
-			timer();
 			sawALRM = false;
+			timer();
+		}
+
+		if (sawDNS) {
+			sawDNS = false;
+			dns_check();
 		}
 
 # ifdef ENABLE_DEBUG_TIMING
@@ -1026,6 +1034,14 @@ static void catchHUP(int sig)
 	UNUSED_ARG(sig);
 	sawHUP = true;
 }
+/*
+ * catchDNS - set flag to process answer DNS lookup
+ */
+static void catchDNS(int sig)
+{
+	UNUSED_ARG(sig);
+	sawDNS = true;
+}
 
 
 /*



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/1d40226e0f88fe91dd97f9568e07d4a0ed004dd7

---
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/1d40226e0f88fe91dd97f9568e07d4a0ed004dd7
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20170414/3033ceb5/attachment.html>


More information about the vc mailing list