[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