+* [Bug 47] Debugging and logging do not work after a fork.
+* [Bug 1010] getaddrinfo() could block and thus should not be called by
+ the main thread/process.
(4.2.7p10) 2010/01/24 Released by Harlan Stenn <stenn@ntp.org>
* [Bug 1140] Clean up debug.html, decode.html, and ntpq.html.
* Include (4.2.6p1-RC3) - Use TZ=UTC instead of TZ= when calling date in
LIBOPTS_CHECK(libopts)
AC_FUNC_FORK
+AC_FUNC_ALLOCA
AC_CACHE_CHECK(
[if $CC can handle @%:@warning],
AC_CHECK_FUNCS([clock_gettime clock_settime])
;;
esac
-AC_CHECK_FUNCS(daemon)
+AC_CHECK_FUNCS(closefrom daemon)
AC_CHECK_FUNCS(finite, ,
[AC_CHECK_FUNCS(isfinite, ,
[AC_MSG_CHECKING([for isfinite with <math.h>])
*-*-openbsd*)
# Just stubs. Idiots.
;;
- *) AC_CHECK_FUNCS(timer_create timer_settime)
+ *) AC_CHECK_FUNCS(timer_create)
;;
esac
+
+# some OSes prefer _exit() in forked children to exit()
+AC_CHECK_FUNCS(_exit)
+ntp_worker_child_exit=exit
+case "$ac_cv_func__exit::$host_os" in
+ yes::netbsd*)
+ ntp_worker_child_exit=_exit
+ ;;
+ yes::openbsd*)
+ ntp_worker_child_exit=_exit
+ ;;
+esac
+AC_DEFINE_UNQUOTED([WORKER_CHILD_EXIT], [$ntp_worker_child_exit],
+ [routine worker child proc uses to exit.])
+
case "$host" in
*-pc-cygwin*)
# I have no idea...
esac
AC_MSG_RESULT([$ans])
-AC_MSG_CHECKING([if ntpd will use the deferred DNS lookup path])
-AC_ARG_ENABLE(
- [force-defer-DNS],
- AS_HELP_STRING(
- [--enable-force-defer-DNS],
- [- force all DNS lookups to take the deferred path]
- ),
- [ans=$enableval],
- [ans=no]
-)
-case "$ans" in
- yes)
- AC_DEFINE(FORCE_DEFER_DNS, 1, [Force deferred DNS lookups?])
-esac
-AC_MSG_RESULT([$ans])
-
AC_CACHE_CHECK([if we have the tty_clk line discipline/streams module],
ac_cv_var_tty_clk,
[case "$ac_cv_header_sys_clkdefs_h$ac_cv_hdr_def_tiocdcdtimestamp" in
ntp_tty.h \
ntp_types.h \
ntp_unixtime.h \
+ ntp_worker.h \
+ ntp_workimpl.h \
ntpd.h \
ntpsim.h \
parse.h \
-#if !defined _ntp_iosignaled_h
-#define _ntp_iosignaled_h
+#ifndef IOSIGNAL_H
+#define IOSIGNAL_H
#include "ntp_refclock.h"
+ /*
+ * Some systems (MOST) define SIGPOLL == SIGIO, others SIGIO == SIGPOLL, and
+ * a few have separate SIGIO and SIGPOLL signals. This code checks for the
+ * SIGIO == SIGPOLL case at compile time.
+ * Do not define USE_SIGPOLL or USE_SIGIO.
+ * these are interal only to iosignal.c and ntpd/work_fork.c!
+ */
+#if defined(USE_SIGPOLL)
+# undef USE_SIGPOLL
+#endif
+#if defined(USE_SIGIO)
+# undef USE_SIGIO
+#endif
+
#if defined(HAVE_SIGNALED_IO)
+# if defined(USE_TTY_SIGPOLL) || defined(USE_UDP_SIGPOLL)
+# define USE_SIGPOLL
+# endif
+
+# if !defined(USE_TTY_SIGPOLL) || !defined(USE_UDP_SIGPOLL)
+# define USE_SIGIO
+# endif
+
+# if defined(USE_SIGIO) && defined(USE_SIGPOLL)
+# if SIGIO == SIGPOLL
+# define USE_SIGIO
+# undef USE_SIGPOLL
+# endif /* SIGIO == SIGPOLL */
+# endif /* USE_SIGIO && USE_SIGPOLL */
+
extern void block_sigio (void);
extern void unblock_sigio (void);
extern int init_clock_sig (struct refclockio *);
# define BLOCKIO() block_sigio()
# define UNBLOCKIO() unblock_sigio()
-#else
-
-# define BLOCKIO()
-# define UNBLOCKIO()
-#endif /* HAVE_SIGNALED_IO */
-
+#else /* !HAVE_SIGNALED_IO follows */
+# define BLOCKIO() do {} while (0)
+# define UNBLOCKIO() do {} while (0)
#endif
+
+#endif /* IOSIGNAL_H */
* This is optional
*/
-#ifndef _l_stdlib_h
-#define _l_stdlib_h
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#ifndef L_STDLIB_H
+#define L_STDLIB_H
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef DECL_SELECT_0
-#ifdef _ntp_select_h
+#ifdef NTP_SELECT_H
extern int select (int, fd_set *, fd_set *, fd_set *, struct timeval *);
#endif
#endif
extern int h_errno;
#endif
-#endif /* l_stdlib_h */
+#endif /* L_STDLIB_H */
* structures used by the ntp configuration code and the discrete event
* simulator.
*
- * Written By: Sachin Kamboj
- * University of Delaware
- * Newark, DE 19711
+ * Written By: Sachin Kamboj
+ * University of Delaware
+ * Newark, DE 19711
* Copyright (c) 2006
*/
-#ifndef __NTP_DATA_STRUCTURES_H__
-#define __NTP_DATA_STRUCTURES_H__
+#ifndef NTP_DATA_STRUCTURES_H
+#define NTP_DATA_STRUCTURES_H
/* Structures for storing a priority queue
} nodeu;
} node;
#define node_next nodeu.next
-
+
typedef struct Queue {
- int (*get_order)(void *, void *);
- node *front;
- int no_of_elements;
+ int (*get_order)(void *, void *);
+ node *front;
+ int no_of_elements;
} queue;
/* FUNCTION PROTOTYPES
* -------------------
*/
-queue *create_priority_queue(int (*get_order)(void *, void *));
+/* Define a function to create a FIFO queue */
+#define create_queue() create_priority_queue(&get_fifo_order)
+
void destroy_queue(queue *my_queue);
-void *get_node(size_t size);
void free_node(void *my_node);
void *next_node(void *my_node);
int empty(queue *my_queue);
void *queue_head(queue *my_queue);
queue *enqueue(queue *my_queue, void *my_node);
+void append_queue(queue *q1, queue *q2);
void *dequeue(queue *my_queue);
int get_no_of_elements(queue *my_queue);
-void append_queue(queue *q1, queue *q2);
int get_fifo_order(void *el1, void *el2);
-queue *create_queue(void);
+/*
+ * Preserve original callsite __FILE__ and __LINE__ for these
+ * malloc-like funcs when using MS C runtime debug heap.
+ */
+#ifdef _CRTDBG_MAP_ALLOC
+# define create_priority_queue(order) debug_create_priority_queue(order, __FILE__, __LINE__)
+# define get_node(size) debug_get_node(size, __FILE__, __LINE__)
+#else
+# define create_priority_queue(order) debug_create_priority_queue(order)
+# define get_node(size) debug_get_node(size)
+#endif
+
+queue *debug_create_priority_queue(
+ int (*get_order)(void *, void *)
+#ifdef _CRTDBG_MAP_ALLOC
+ , const char *, int /* __FILE__, __LINE__ */
#endif
+ );
+
+void *debug_get_node(
+ size_t
+#ifdef _CRTDBG_MAP_ALLOC
+ , const char *, int /* __FILE__, __LINE__ */
+#endif
+ );
+
+#endif /* NTP_DATA_STRUCTURES_H */
extern char * fptoa (s_fp, short);
extern char * fptoms (s_fp, short);
extern int hextolfp (const char *, l_fp *);
-extern void gpstolfp (int, int, unsigned long, l_fp *);
+extern void gpstolfp (int, int, unsigned long, l_fp *);
extern int mstolfp (const char *, l_fp *);
extern char * prettydate (l_fp *);
extern char * gmprettydate (l_fp *);
extern char * uglydate (l_fp *);
-extern void mfp_mul (int32 *, u_int32 *, int32, u_int32, int32, u_int32);
+extern void mfp_mul (int32 *, u_int32 *, int32, u_int32, int32, u_int32);
extern void get_systime (l_fp *);
extern int step_systime (double);
#ifndef NTP_INTRES_H
#define NTP_INTRES_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.
- */
-#if defined(VMS) || defined (SYS_VXWORKS) || \
- (!defined(HAVE_WORKING_FORK) && !defined(SYS_WINNT))
-#define NO_INTRES
-#endif
-
-#endif /* !defined(NTP_INTRES_H) */
+#include "ntp_worker.h"
+
+#ifdef WORKER
+
+extern int blocking_getaddrinfo(blocking_pipe_header *);
+extern int blocking_getnameinfo(blocking_pipe_header *);
+
+#ifdef TEST_BLOCKING_WORKER
+extern void gai_test_callback(int rescode, int gai_errno,
+ void *context, const char *name,
+ const char *service,
+ const struct addrinfo *hints,
+ const struct addrinfo *ai_res);
+extern void gni_test_callback(int rescode, int gni_errno,
+ sockaddr_u *psau, int flags,
+ const char *host,
+ const char *service, void *context);
+#endif /* TEST_BLOCKING_WORKER */
+#endif /* WORKER */
+#endif /* !NTP_INTRES_H */
#ifndef NTP_IO_H
#define NTP_IO_H
+
+#include "ntp_workimpl.h"
+
/*
* POSIX says use <fnct.h> to get O_* symbols and
* SEEK_SET symbol form <unistd.h>.
*/
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
MATCH_IFADDR
} nic_rule_match;
-
/*
* NIC rule actions
*/
} nic_rule_action;
+SOCKET move_fd(SOCKET fd);
isc_boolean_t get_broadcastclient_flag(void);
isc_boolean_t is_ip_address(const char *, isc_netaddr_t *);
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 add_nic_rule(nic_rule_match match_type,
+ const char *if_name, int prefixlen,
+ nic_rule_action action);
+#ifndef HAVE_IO_COMPLETION_PORT
+extern void close_all_beyond(int);
+#endif
+#ifdef WORK_FORK
+extern void update_resp_pipe_fd(int, int);
+#endif
#endif /* NTP_IO_H */
#ifndef NTP_LISTS_H
#define NTP_LISTS_H
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include <isc/list.h>
/*
+ * ntp_machine.h
+ *
* Collect all machine dependent idiosyncrasies in one place.
+ *
+ * The functionality formerly in this file is mostly handled by
+ * Autoconf these days.
*/
#ifndef NTP_MACHINE_H
#define NTP_MACHINE_H
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
HEY! CHECK THIS OUT!
- The first half of this file is obsolete, and is only there to help
- reconcile "what went before" with "current behavior".
-
The per-system SYS_* #defins ARE NO LONGER USED, with the temporary
exception of SYS_WINNT.
# define ntp_adjtime __adjtimex
#endif
-#if 0
-
-/*
- * IRIX 4.X and IRIX 5.x
- */
-#if defined(SYS_IRIX4)||defined(SYS_IRIX5)
-# define ADJTIME_IS_ACCURATE
-# define LOCK_PROCESS
-#endif
-
-/*
- * Ultrix
- * Note: posix version has NTP_POSIX_SOURCE and HAVE_SIGNALED_IO
- */
-#if defined(SYS_ULTRIX)
-# define S_CHAR_DEFINED
-# define NTP_SYSCALLS_STD
-# define HAVE_MODEM_CONTROL
-#endif
-
-/*
- * AUX
- */
-#if defined(SYS_AUX2) || defined(SYS_AUX3)
-# define NO_SIGNED_CHAR_DECL
-# define LOCK_PROCESS
-# define NTP_POSIX_SOURCE
-/*
- * This requires that _POSIX_SOURCE be forced on the
- * compiler command flag. We can't do it here since this
- * file is included _after_ the system header files and we
- * need to let _them_ know we're POSIX. We do this in
- * compilers/aux3.gcc...
- */
-# define LOG_NTP LOG_LOCAL1
-#endif
-
-/*
- * HPUX
- */
-#if defined(SYS_HPUX)
-# define getdtablesize() sysconf(_SC_OPEN_MAX)
-# define setlinebuf(f) setvbuf(f, NULL, _IOLBF, 0)
-# define NO_SIGNED_CHAR_DECL
-# define LOCK_PROCESS
-#endif
-
-/*
- * BSD/OS 2.0 and above
- */
-#if defined(SYS_BSDI)
-# define USE_FSETOWNCTTY /* this funny system demands a CTTY for FSETOWN */
-#endif
-
-/*
- * FreeBSD 2.0 and above
- */
-#ifdef SYS_FREEBSD
-# define KERNEL_PLL
-#endif
-
-/*
- * Linux
- */
-#if defined(SYS_LINUX)
-# define ntp_adjtime __adjtimex
-#endif
-
-/*
- * PTX
- */
-#if defined(SYS_PTX)
-# define LOCK_PROCESS
-struct timezone { int __0; }; /* unused placebo */
-/*
- * no comment !@!
- */
-typedef unsigned int u_int;
-# ifndef _NETINET_IN_SYSTM_INCLUDED /* i am about to comment... */
-typedef unsigned char u_char;
-typedef unsigned short u_short;
-typedef unsigned long u_long;
-# endif
-#endif
-
-/*
- * UNIX V.4 on and NCR 3000
- */
-#if defined(SYS_SVR4)
-# define STREAM
-# define LOCK_PROCESS
-# define SIZE_RETURNED_IN_BUFFER
-#endif
-
-/*
- * (Univel/Novell) Unixware1 SVR4 on intel x86 processor
- */
-#if defined(SYS_UNIXWARE1)
-/* #define _POSIX_SOURCE */
-# define STREAM
-# define STREAMS
-# undef STEP_SLEW /* TWO step */
-# define LOCK_PROCESS
-# define SIZE_RETURNED_IN_BUFFER
-# include <sys/sockio.h>
-# include <sys/types.h>
-# include <netinet/in_systm.h>
-#endif
-
-/*
- * DomainOS
- */
-#if defined(SYS_DOMAINOS)
-# define NTP_SYSCALLS_STD
-/* older versions of domain/os don't have class D */
-# ifndef IN_CLASSD
-# define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000)
-# define IN_CLASSD_NET 0xf0000000
-# define IN_CLASSD_NSHIFT 28
-# define IN_CLASSD_HOST 0xfffffff
-# define IN_MULTICAST(i) IN_CLASSD(i)
-# endif
-#endif
-
-/*
- * Fujitsu UXP/V
- */
-#if defined(SYS_UXPV)
-# define LOCK_PROCESS
-# define SIZE_RETURNED_IN_BUFFER
-#endif
-
-
-#endif /* 0 */
-
/*
* Define these here for non-Windows NT systems
* SOCKET and INVALID_SOCKET are native macros
&& !defined(HAVE_TERMIOS)
#include "ERROR: no tty type defined!"
# endif
-#endif /* SYS_WINNT || VMS || SYS_VXWORKS*/
+#endif /* !SYS_WINNT && !VMS && !SYS_VXWORKS*/
-#ifdef WORDS_BIGENDIAN
-# define XNTP_BIG_ENDIAN 1
-#else
-# define XNTP_LITTLE_ENDIAN 1
-#endif
-
-/*
- * Byte order woes.
- * This used to be resolved by calling ntohl() and htonl() to swap things
- * around, but this turned out to be quite costly on Vaxes where those
- * things are actual functions. The code now straightens out byte
- * order troubles on its own, with no performance penalty for little
- * end first machines, but at great expense to cleanliness.
- */
-#if !defined(XNTP_BIG_ENDIAN) && !defined(XNTP_LITTLE_ENDIAN)
- /*
- * Pick one or the other.
- */
- BYTE_ORDER_NOT_DEFINED_FOR_AUTHENTICATION
-#endif
-
-#if defined(XNTP_BIG_ENDIAN) && defined(XNTP_LITTLE_ENDIAN)
- /*
- * Pick one or the other.
- */
- BYTE_ORDER_NOT_DEFINED_FOR_AUTHENTICATION
-#endif
#endif /* NTP_MACHINE_H */
#ifndef NTP_MALLOC_H
#define NTP_MALLOC_H
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#else
# endif
#endif
+/*
+ * Deal with platform differences declaring alloca()
+ * This comes nearly verbatim from:
+ *
+ * http://www.gnu.org/software/autoconf/manual/autoconf.html#Particular-Functions
+ *
+ * The only modifications were to remove C++ support and guard against
+ * redefining alloca.
+ */
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# ifndef alloca
+# define alloca __builtin_alloca
+# endif
+#elif defined _AIX
+# ifndef alloca
+# define alloca __alloca
+# endif
+#elif defined _MSC_VER
+# include <malloc.h>
+# ifndef alloca
+# define alloca _alloca
+# endif
+#else
+# include <stddef.h>
+void * alloca(size_t);
+#endif
+
#endif /* NTP_MALLOC_H */
-#ifndef __ntp_proto_h
-#define __ntp_proto_h
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#ifndef NTP_PROTO_H
+#define NTP_PROTO_H
#define NTP_MAXFREQ 500e-6
-#endif /* __ntp_proto_h */
+#endif /* NTP_PROTO_H */
#ifndef NTP_RFC2553_H
#define NTP_RFC2553_H
-/*
- * Ensure that we include the configuration file before we check
- * for IPV6
- */
-#include <config.h>
#include <netdb.h>
#include <isc/net.h>
* Not all machines define FD_SET in sys/types.h
*/
#ifndef NTP_SELECT_H
-#define NTP_SELECT_H
+#define NTP_SELECT_H /* note: tested by include/l_stdlib.h */
/* Was: (defined(RS6000)||defined(SYS_PTX))&&!defined(_BSD) */
/* Could say: !defined(FD_SET) && defined(HAVE_SYS_SELECT_H) */
+/* except FD_SET can legitimately be a typedef... */
#if defined(HAVE_SYS_SELECT_H) && !defined(_BSD)
-#ifndef SYS_VXWORKS
-#include <sys/select.h>
-#else
-#include <sockLib.h>
-extern int select (int width, fd_set *pReadFds, fd_set *pWriteFds,
- fd_set *pExceptFds, struct timeval *pTimeOut);
-
-#endif
+# ifndef SYS_VXWORKS
+# include <sys/select.h>
+# else
+# include <sockLib.h>
+extern int select(int width, fd_set *pReadFds, fd_set *pWriteFds,
+ fd_set *pExceptFds, struct timeval *pTimeOut);
+# endif
#endif
#if !defined(FD_SET)
-#define NFDBITS 32
-#define FD_SETSIZE 32
-#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
-#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
-#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
-#define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p)))
+# define NFDBITS 32
+# define FD_SETSIZE 32
+# define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+# define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+# define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+# define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
#endif
#if defined(VMS)
typedef struct {
- unsigned int fds_bits[1];
+ unsigned int fds_bits[1];
} fd_set;
#endif
-#ifdef SYS_WINNT
-/* ports/winnt/libntp/setpriority.c */
-extern void InitSockets(void);
-#endif
-
#endif /* NTP_SELECT_H */
#endif
#include "l_stdlib.h"
-#include "ntp_rfc2553.h"
#include "ntp_types.h"
#include "ntp_string.h"
#include "ntp_net.h"
extern int atouint (const char *, u_long *);
extern int hextoint (const char *, u_long *);
extern char * humanlogtime (void);
+extern char * humantime (time_t);
extern char * inttoa (long);
extern char * mfptoa (u_long, u_long, short);
extern char * mfptoms (u_long, u_long, short);
* Define string ops: strchr strrchr memcmp memmove memset
*/
-#ifndef _ntp_string_h
-#define _ntp_string_h
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#ifndef NTP_STRING_H
+#define NTP_STRING_H
#ifdef HAVE_MEMORY_H
# include <memory.h>
ntp_memset((char *)(a), x, c)
#endif /* NTP_NEED_BOPS */
-#endif /* _ntp_string_h */
+#endif /* NTP_STRING_H */
#ifndef NTP_SYSCALL_H
#define NTP_SYSCALL_H
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
#ifdef HAVE_SYS_TIMEX_H
# include <sys/timex.h>
#endif
#ifndef NTP_SYSLOG_H
#define NTP_SYSLOG_H
-# ifdef VMS
+#ifdef VMS
extern void msyslog();
-# else
-# ifndef SYS_VXWORKS
-# include <syslog.h>
-# endif
-# endif /* VMS */
-# include <stdio.h>
+#else
+# ifndef SYS_VXWORKS
+# include <syslog.h>
+# endif
+#endif /* VMS */
+#include <stdio.h>
-extern int syslogit;
-extern FILE *syslog_file;
+extern int syslogit;
+extern FILE * syslog_file;
+extern char * syslog_fname;
+extern char * syslog_abs_fname;
#if defined(VMS) || defined (SYS_VXWORKS)
#define LOG_EMERG 0 /* system is unusable */
#if (SIZEOF_INT == 4)
# ifndef int32
-# define int32 int
+ typedef int int32;
# endif
# ifndef u_int32
-# define u_int32 unsigned int
+ typedef unsigned u_int32;
# endif
-#else /* not sizeof(int) == 4 */
+#else /* SIZEOF_INT != 4 */
# if (SIZEOF_LONG == 4)
# ifndef int32
-# define int32 long
+ typedef long int32;
# endif
# ifndef u_int32
-# define u_int32 unsigned long
+ typedef unsigned long u_int32;
# endif
-# else /* not sizeof(long) == 4 */
+# else /* SIZEOF_LONG != 4 */
# include "Bletch: what's 32 bits on this machine?"
-# endif /* not sizeof(long) == 4 */
-#endif /* not sizeof(int) == 4 */
+# endif
+#endif /* SIZEOF_INT != 4 */
typedef u_char ntp_u_int8_t;
typedef u_short ntp_u_int16_t;
--- /dev/null
+/*
+ * ntp_worker.h
+ */
+
+#ifndef NTP_WORKER_H
+#define NTP_WORKER_H
+
+#include "ntp_workimpl.h"
+
+#ifdef WORKER
+
+/* #define TEST_BLOCKING_WORKER */ /* ntp_config.c ntp_intres.c */
+
+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 = 0xb10c7ecf,
+ BLOCKING_RESP_MAGIC = 0xb10c7e54,
+} 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;
+ blocking_work_callback done_func;
+ void * context;
+} blocking_pipe_header;
+
+extern int intres_req_pending;
+
+extern int queue_blocking_request(blocking_work_req, void *, size_t, blocking_work_callback, void *);
+extern int queue_blocking_response(blocking_pipe_header *, size_t, const blocking_pipe_header *);
+extern int send_blocking_req_internal(blocking_pipe_header *, void *);
+extern int send_blocking_resp_internal(blocking_pipe_header *);
+extern blocking_pipe_header *receive_blocking_req_internal(void);
+extern blocking_pipe_header *receive_blocking_resp_internal(void);
+extern int blocking_child_common (void);
+extern void exit_worker(int);
+extern int worker_sleep(time_t);
+
+#endif /* WORKER */
+
+#endif /* !NTP_WORKER_H */
--- /dev/null
+/*
+ * ntp_workimpl.h - selects worker child implementation
+ */
+#ifndef NTP_WORKIMPL_H
+#define 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.
+ */
+#if defined(SYS_WINNT)
+# define WORK_THREAD
+#elif defined(VMS) || defined(SYS_VXWORKS)
+ /* empty */
+#elif defined(HAVE_WORKING_FORK)
+# define WORK_FORK
+#endif
+
+#if defined(WORK_FORK) || defined(WORK_THREAD)
+# define WORKER
+#endif
+
+
+#endif /* !NTP_WORKIMPL_H */
#include "ntp_select.h"
#include "ntp_malloc.h"
#include "ntp_refclock.h"
+#include "ntp_workimpl.h"
#include "recvbuff.h"
/* ntp_config.c */
extern int ctlsettrap (sockaddr_u *, struct interface *, int, int);
extern u_short ctlsysstatus (void);
extern void init_control (void);
-extern void init_logging (char const *, int);
-extern void setup_logfile (void);
+extern void init_logging (const char *, int);
+extern int change_logfile (const char *, int);
+extern void setup_logfile (int);
extern void process_control (struct recvbuf *, int);
extern void report_event (int, struct peer *, const char *);
#define WO (CAN_WRITE)
#define RW (CAN_READ|CAN_WRITE)
-extern char * add_var (struct ctl_var **, u_long, u_short);
-extern void free_varlist (struct ctl_var *);
-extern void set_var (struct ctl_var **, const char *, u_long, u_short);
-extern void set_sys_var (const char *, u_long, u_short);
+extern char * add_var (struct ctl_var **, u_long, u_short);
+extern void free_varlist (struct ctl_var *);
+extern void set_var (struct ctl_var **, const char *, u_long, u_short);
+extern void set_sys_var (const char *, u_long, u_short);
/* ntp_intres.c */
-extern void ntp_res_name (sockaddr_u, u_short);
-extern void ntp_res_recv (void);
-extern void ntp_intres (void);
-#ifdef SYS_WINNT
-extern unsigned WINAPI ntp_intres_thread (void *);
-#endif
+#ifdef WORKER
+typedef void (*gai_sometime_callback)
+ (int, int, void *, const char *, const char *,
+ const struct addrinfo *, const struct addrinfo *);
+/*
+ * you call getaddrinfo_sometime(name, service, &hints, callback_func, context);
+ * later (*callback_func)(rescode, gai_errno, context, name, service, hints, ai_result) is called.
+ */
+extern int getaddrinfo_sometime(const char *, const char *,
+ const struct addrinfo *,
+ gai_sometime_callback, void *);
+typedef void (*gni_sometime_callback)
+ (int, int, sockaddr_u *, int, const char *,
+ const char *, void *);
+/*
+ * you call getnameinfo_sometime(sockaddr, namelen, servlen, flags, callback_func, context);
+ * later (*callback_func)(rescode, gni_errno, sockaddr, flags, name, service, context) is called.
+ */
+extern int getnameinfo_sometime(sockaddr_u *, size_t, size_t, int,
+ gni_sometime_callback, void *);
+#endif /* WORKER */
/* ntp_io.c */
typedef struct interface_info {
extern void reinit_timer (void);
extern void timer (void);
extern void timer_clr_stats (void);
-extern void timer_interfacetimeout (u_long);
-extern volatile int interface_interval;
+extern void timer_interfacetimeout (u_long);
+extern volatile int interface_interval;
+extern u_long worker_idle_timer; /* next check current_time */
#ifdef OPENSSL
extern char *sys_hostname; /* host name */
extern char *sys_groupname; /* group name */
extern char *group_name; /* group name */
-extern u_long sys_revoke; /* keys revoke timeout */
-extern u_long sys_automax; /* session key timeout */
+extern u_long sys_revoke; /* keys revoke timeout */
+extern u_long sys_automax; /* session key timeout */
#endif /* OPENSSL */
/* ntp_util.c */
#endif
extern u_short sock_hash (sockaddr_u *);
extern char * fstostr(time_t); /* NTP timescale seconds */
-extern double old_drift;
-extern int drift_file_sw;
-extern double wander_threshold;
-extern double wander_resid;
+
+/* ntp_worker.c */
+#ifdef WORKER
+extern void process_blocking_response(void);
+extern void worker_idle_timer_fired(void);
+extern void interrupt_worker_sleep(void);
+#endif /* WORKER */
+#if defined(HAVE_DROPROOT) && defined(WORK_FORK)
+extern void fork_deferred_worker(void);
+#else
+# define fork_deferred_worker() do {} while (0)
+#endif
+
+/* ntpd.c */
+extern void parse_cmdline_opts(int *, char ***);
+
/*
* Variable declarations for ntpd.
extern u_long numctlbadop; /* bad op code found in packet */
extern u_long numasyncmsgs; /* number of async messages we've sent */
-/* ntp_intres.c */
-extern keyid_t req_keyid; /* request keyid */
-extern int req_keytype; /* OpenSSL NID such as NID_md5 */
-extern size_t req_hashlen; /* digest size for req_keytype */
-extern char * req_file; /* name of the file with configuration info */
-#ifdef SYS_WINNT
-extern HANDLE ResolverEventHandle;
-#else
-extern int resolver_pipe_fd[2]; /* used to let the resolver process alert the parent process */
-#endif /* SYS_WINNT */
-
/*
* Other statistics of possible interest
*/
extern u_long timer_xmtcalls;
/* ntp_util.c */
-extern int stats_control; /* write stats to fileset? */
-extern int stats_write_period; /* # of seconds between writes. */
-extern double stats_write_tolerance;
+extern int stats_control; /* write stats to fileset? */
+extern int stats_write_period; /* # of seconds between writes. */
+extern double stats_write_tolerance;
+extern double old_drift;
+extern int drift_file_sw;
+extern double wander_threshold;
+extern double wander_resid;
+
+/* ntp_worker.c */
+#if defined(WORK_FORK)
+extern int parent_resp_read_pipe;
+#elif defined (WORK_THREAD)
+extern HANDLE blocking_response_ready;
+#endif
/* ntpd.c */
-extern void parse_cmdline_opts(int *, char ***);
-extern volatile int debug; /* debugging flag */
-extern int nofork; /* no-fork flag */
-extern int initializing; /* initializing flag */
+extern volatile int debug; /* debugging flag */
+extern int nofork; /* no-fork flag */
+extern int initializing; /* initializing flag */
#ifdef HAVE_DROPROOT
-extern int droproot; /* flag: try to drop root privileges after startup */
-extern char *user; /* user to switch to */
-extern char *group; /* group to switch to */
-extern const char *chrootdir; /* directory to chroot to */
+extern int droproot; /* flag: try to drop root privileges after startup */
+extern int root_dropped; /* root has been dropped */
+extern char *user; /* user to switch to */
+extern char *group; /* group to switch to */
+extern const char *chrootdir; /* directory to chroot() to */
#endif
/* refclock_conf.c */
#ifndef RECVBUFF_H
#define RECVBUFF_H
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include "ntp.h"
#include "ntp_fp.h"
#include "ntp_lists.h"
#if defined HAVE_IO_COMPLETION_PORT
# include "ntp_iocompletionport.h"
-#include "ntp_timer.h"
+# include "ntp_timer.h"
# define RECV_BLOCK_IO() EnterCriticalSection(&RecvCritSection)
# define RECV_UNBLOCK_IO() LeaveCriticalSection(&RecvCritSection)
/*
* atoint - convert an ascii string to a signed long, with error checking
*/
+#include <config.h>
#include <sys/types.h>
#include <ctype.h>
/*
* atolfp - convert an ascii string to an l_fp number
*/
+#include <config.h>
#include <stdio.h>
#include <ctype.h>
/*
* atouint - convert an ascii string to an unsigned long, with error checking
*/
+#include <config.h>
#include <sys/types.h>
#include <ctype.h>
/*
* authusekey - decode a key from ascii and use it
*/
+#include <config.h>
#include <stdio.h>
#include <ctype.h>
/*
* caljulian - determine the Julian date from an NTP time.
*/
+#include <config.h>
#include <sys/types.h>
#include "ntp_types.h"
/*
* caltontp - convert a date to an NTP time
*/
+#include <config.h>
#include <sys/types.h>
#include "ntp_types.h"
* calyearstart - determine the NTP time at midnight of January 1 in
* the year of the given date.
*/
+#include <config.h>
#include <sys/types.h>
#include "ntp_types.h"
* clocktime - compute the NTP date from a day of year, hour, minute
* and second.
*/
+#include <config.h>
#include "ntp_fp.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
/*
* Data for pretty printing clock types
*/
+#include <config.h>
#include <stdio.h>
#include "ntp_fp.h"
/*
* dofptoa - do the grunge work to convert an fp number to ascii
*/
+#include <config.h>
#include <stdio.h>
#include "ntp_fp.h"
/*
* dolfptoa - do the grunge work of converting an l_fp number to decimal
*/
+#include <config.h>
#include <stdio.h>
#include "ntp_fp.h"
/*
* emalloc - return new memory obtained from the system. Belch if none.
*/
+#include <config.h>
#include "ntp_types.h"
#include "ntp_malloc.h"
#include "ntp_syslog.h"
/*
* fptoa - return an asciized representation of an s_fp number
*/
+#include <config.h>
#include "ntp_fp.h"
#include "ntp_stdlib.h"
/*
* fptoms - return an asciized s_fp number in milliseconds
*/
+#include <config.h>
#include "ntp_fp.h"
char *
/*LINTLIBRARY*/
+#include <config.h>
#include <stdio.h>
#include "ntp_stdlib.h"
* hextoint - convert an ascii string in hex to an unsigned
* long, with error checking
*/
+#include <config.h>
#include <ctype.h>
#include "ntp_stdlib.h"
/*
* hextolfp - convert an ascii hex string to an l_fp number
*/
+#include <config.h>
#include <stdio.h>
#include <ctype.h>
/*
* humandate - convert an NTP (or the current) time to something readable
*/
+#include <config.h>
#include <stdio.h>
#include "ntp_fp.h"
#include "ntp_unixtime.h" /* includes <sys/time.h> and <time.h> */
char *
humanlogtime(void)
{
- char *bp;
- time_t cursec = time((time_t *) 0);
- struct tm *tm;
+ char * bp;
+ time_t cursec;
+ struct tm * tm;
+ cursec = time(NULL);
tm = localtime(&cursec);
if (!tm)
return "-- --- --:--:--";
LIB_GETBUF(bp);
- (void) sprintf(bp, "%2d %s %02d:%02d:%02d",
- tm->tm_mday, months[tm->tm_mon],
- tm->tm_hour, tm->tm_min, tm->tm_sec);
+ snprintf(bp, LIB_BUFLENGTH, "%2d %s %02d:%02d:%02d",
+ tm->tm_mday, months[tm->tm_mon],
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return bp;
+}
+
+
+/*
+ * humantime() -- like humanlogtime() but without date, and with the
+ * time to display given as an argument.
+ */
+char *
+humantime(
+ time_t cursec
+ )
+{
+ char * bp;
+ struct tm * tm;
+
+ tm = localtime(&cursec);
+ if (!tm)
+ return "--:--:--";
+
+ LIB_GETBUF(bp);
+
+ snprintf(bp, LIB_BUFLENGTH, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
return bp;
}
* distribution. The only function provided is to load the radio
* frequency. All other parameters must be manually set before use.
*/
+#include <config.h>
#include "icom.h"
#include <unistd.h>
#include <stdio.h>
* SIGPOLL and SIGIO ROUTINES.
*/
- /*
- * Some systems (MOST) define SIGPOLL == SIGIO, others SIGIO == SIGPOLL, and
- * a few have separate SIGIO and SIGPOLL signals. This code checks for the
- * SIGIO == SIGPOLL case at compile time.
- * Do not define USE_SIGPOLL or USE_SIGIO.
- * these are interal only to iosignal.c!
- */
-# if defined(USE_SIGPOLL)
-# undef USE_SIGPOLL
-# endif
-# if defined(USE_SIGIO)
-# undef USE_SIGIO
-# endif
-
-# if defined(USE_TTY_SIGPOLL) || defined(USE_UDP_SIGPOLL)
-# define USE_SIGPOLL
-# endif
-
-# if !defined(USE_TTY_SIGPOLL) || !defined(USE_UDP_SIGPOLL)
-# define USE_SIGIO
-# endif
-
-# if defined(USE_SIGIO) && defined(USE_SIGPOLL)
-# if SIGIO == SIGPOLL
-# define USE_SIGIO
-# undef USE_SIGPOLL
-# endif /* SIGIO == SIGPOLL */
-# endif /* USE_SIGIO && USE_SIGIO */
/*
/*
* mfptoa - Return an asciized representation of a signed long fp number
*/
+#include <config.h>
#include "ntp_fp.h"
#include "ntp_stdlib.h"
/*
* mfptoms - Return an asciized signed long fp number in milliseconds
*/
+#include <config.h>
#include "ntp_fp.h"
#include "ntp_stdlib.h"
* by hand. Sorry about that.
*/
+#include <config.h>
#include "ntp_machine.h"
#if !defined(HAVE_MKTIME) || !defined(HAVE_TIMEGM)
/*
* modetoa - return an asciized mode
*/
+#include <config.h>
#include <stdio.h>
#include "lib_strbuf.h"
/*
* mstolfp - convert an ascii string in milliseconds to an l_fp number
*/
+#include <config.h>
#include <stdio.h>
#include <ctype.h>
* msutotsf - tables for converting from a subsecond millisecond value
* to a time stamp fraction.
*/
+#include <config.h>
#include <sys/types.h>
#include "ntp_types.h"
int syslogit = 1;
-FILE *syslog_file = NULL;
+FILE * syslog_file;
+char * syslog_fname;
+char * syslog_abs_fname;
-u_long ntp_syslogmask = ~ (u_long) 0;
+u_long ntp_syslogmask = ~(u_long)0; /* libntp default is all lit */
-#ifdef SYS_WINNT
-static char separator = '\\';
-#else
-static char separator = '/';
-#endif /* SYS_WINNT */
extern char *progname;
/* Declare the local functions */
void
addto_syslog(int level, char * buf)
{
- char *prog;
- FILE *out_file = syslog_file;
+ static const char * last_progname;
+ static const char * prog;
+ FILE * out_file;
#if !defined(VMS) && !defined (SYS_VXWORKS)
- if (syslogit)
- syslog(level, "%s", buf);
- else
+ if (syslogit) {
+ syslog(level, "%s", buf);
+ out_file = NULL;
+ } else
#endif /* VMS && SYS_VXWORKS*/
{
- out_file = syslog_file ? syslog_file: level <= LOG_ERR ? stderr : stdout;
- /* syslog() provides the timestamp, so if we're not using
- syslog, we must provide it. */
- prog = strrchr(progname, separator);
- if (prog == NULL)
- prog = progname;
- else
- prog++;
- (void) fprintf(out_file, "%s ", humanlogtime ());
- (void) fprintf(out_file, "%s[%d]: %s", prog, (int)getpid(), buf);
+ out_file = (syslog_file)
+ ? syslog_file
+ : (level <= LOG_ERR)
+ ? stderr
+ : stdout;
+ if (last_progname != progname) {
+ last_progname = progname;
+ prog = strrchr(progname, DIR_SEP);
+ if (NULL == prog)
+ prog = progname;
+ else
+ prog++;
+ }
+ /*
+ * syslog() provides the timestamp, so if we're not
+ * using syslog, we must provide it.
+ */
+ fprintf(out_file, "%s %s[%d]: %s", humanlogtime(),
+ prog, (int)getpid(), buf);
fflush (out_file);
}
#if DEBUG
if (debug && out_file != stdout && out_file != stderr)
- printf("addto_syslog: %s\n", buf);
+ printf("addto_syslog: %s", buf);
#endif
}
+
+
void
format_errmsg(char *nfmt, int lennfmt, const char *fmt, int errval)
{
n += len;
}
}
-#if !defined(VMS)
- if (!syslogit)
-#endif /* VMS */
- *n++ = '\n';
+ /*
+ * syslog adds a trailing \n if not present, do the same so we
+ * have the same behavior with syslog and a log file.
+ */
+ if (n > nfmt && '\n' != n[-1])
+ *n++ = '\n';
*n = '\0';
}
-#if defined(__STDC__) || defined(HAVE_STDARG_H)
+
void msyslog(int level, const char *fmt, ...)
-#else /* defined(__STDC__) || defined(HAVE_STDARG_H) */
- /*VARARGS*/
- void msyslog(va_alist)
- va_dcl
-#endif /* defined(__STDC__) || defined(HAVE_STDARG_H) */
{
-#if defined(__STDC__) || defined(HAVE_STDARG_H)
-#else
- int level;
- const char *fmt;
-#endif
va_list ap;
char buf[1025], nfmt[256];
int errval;
* netof - return the net address part of an ip address in a sockaddr_storage structure
* (zero out host part)
*/
+#include <config.h>
#include <stdio.h>
#include <syslog.h>
* octtoint - convert an ascii string in octal to an unsigned
* long, with error checking
*/
+#include <config.h>
#include <stdio.h>
#include <ctype.h>
/*
* prettydate - convert a time stamp to something readable
*/
+#include <config.h>
#include <stdio.h>
#include "ntp_fp.h"
/*
* refnumtoa - return asciized refclock addresses stored in local array space
*/
+#include <config.h>
#include <stdio.h>
#include "ntp_net.h"
/*
* socktoa - return a numeric host name from a sockaddr_storage structure
*/
+#include <config.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
+#include <config.h>
#include "ntp_malloc.h"
#if !HAVE_STRDUP
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
+
#ifdef HAVE_SIGACTION
+#ifdef SA_RESTART
+# define Z_SA_RESTART SA_RESTART
+#else
+# define Z_SA_RESTART 0
+#endif
+
+# ifdef SA_SIGINFO
+# define Z_SA_SIGINFO SA_SIGINFO
+# else
+# define Z_SA_SIGINFO 0
+# endif
+
+# define IGNORED_SA_FLAGS (Z_SA_RESTART | Z_SA_SIGINFO)
+
+
void
signal_no_reset(
-#if defined(__STDC__) || defined(HAVE_STDARG_H)
int sig,
- void (*func) (int)
-#else
- sig, func
-#endif
+ void (*func)(int)
)
-#if defined(__STDC__) || defined(HAVE_STDARG_H)
-#else
- int sig;
- void (*func) (int);
-#endif
{
int n;
struct sigaction vec;
+ struct sigaction ovec;
vec.sa_handler = func;
sigemptyset(&vec.sa_mask);
-#if 0
-#ifdef SA_RESTART
- vec.sa_flags = SA_RESTART;
-#else
- vec.sa_flags = 0;
-#endif
-#else
- vec.sa_flags = 0;
-#endif
-#ifdef SA_RESTART
-/* Added for PPS clocks on Solaris 7 which get EINTR errors */
+ vec.sa_flags = 0;
+ /* Added for PPS clocks on Solaris 7 which get EINTR errors */
# ifdef SIGPOLL
- if (sig == SIGPOLL) vec.sa_flags = SA_RESTART;
+ if (SIGPOLL == sig)
+ vec.sa_flags = Z_SA_RESTART;
# endif
# ifdef SIGIO
- if (sig == SIGIO) vec.sa_flags = SA_RESTART;
+ if (SIGIO == sig)
+ vec.sa_flags = Z_SA_RESTART;
# endif
-#endif
-
- while (1)
- {
- struct sigaction ovec;
+ do
n = sigaction(sig, &vec, &ovec);
- if (n == -1 && errno == EINTR) continue;
- if (ovec.sa_flags
-#ifdef SA_RESTART
- && ovec.sa_flags != SA_RESTART
-#endif
- )
- msyslog(LOG_DEBUG, "signal_no_reset: signal %d had flags %x",
- sig, ovec.sa_flags);
- break;
- }
- if (n == -1) {
+ while (-1 == n && EINTR == errno);
+ if (-1 == n) {
perror("sigaction");
exit(1);
}
+ if (ovec.sa_flags & ~IGNORED_SA_FLAGS)
+ msyslog(LOG_DEBUG,
+ "signal_no_reset: signal %d had flags %x",
+ sig, ovec.sa_flags);
}
#elif HAVE_SIGVEC
void
signal_no_reset(
int sig,
- RETSIGTYPE (*func) (int)
+ RETSIGTYPE (*func)(int)
)
{
struct sigvec sv;
int n;
- bzero((char *) &sv, sizeof(sv));
+ memset(&sv, 0, sizeof(sv));
sv.sv_handler = func;
n = sigvec(sig, &sv, (struct sigvec *)NULL);
- if (n == -1) {
+ if (-1 == n) {
perror("sigvec");
exit(1);
}
void
signal_no_reset(
int sig,
- RETSIGTYPE (*func) (int)
+ RETSIGTYPE (*func)(int)
)
{
int n;
n = sigset(sig, func);
- if (n == -1) {
+ if (-1 == n) {
perror("sigset");
exit(1);
}
void
signal_no_reset(
int sig,
- RETSIGTYPE (*func) (int)
+ RETSIGTYPE (*func)(int)
)
{
-#ifdef SIG_ERR
- if (SIG_ERR == signal(sig, func)) {
-#else
- int n;
- n = signal(sig, func);
- if (n == -1) {
+#ifndef SIG_ERR
+# define SIG_ERR (-1)
#endif
+ if (SIG_ERR == signal(sig, func)) {
perror("signal");
exit(1);
}
* ATTENTION: Get approval from Dave Mills on all changes to this file!
*
*/
+#include <config.h>
#include "ntp_machine.h"
#include "ntp_fp.h"
#include "ntp_syslog.h"
/*
* tsftomsu - convert from a time stamp fraction to milliseconds
*/
+#include <config.h>
#include "ntp_fp.h"
#include "ntp_stdlib.h"
* tstotv - tables for converting from NTP time stamps to struct timeval
*/
+#include <config.h>
#include "ntp_types.h"
/*
* tvtots - tables for converting from Unix struct timeval's to
* NTP time stamp format.
*/
+#include <config.h>
#include <sys/types.h>
#include "ntp_types.h"
* uglydate - convert a time stamp to something barely readable
* The string returned is 37 characters long.
*/
+#include <config.h>
#include <stdio.h>
#include "ntp_fp.h"
/*
* uinttoa - return an asciized unsigned integer
*/
+#include <config.h>
#include <stdio.h>
#include "lib_strbuf.h"
register char *buf;
LIB_GETBUF(buf);
+ snprintf(buf, LIB_BUFLENGTH, "%lu", uval);
- (void) sprintf(buf, "%lu", (u_long)uval);
return buf;
}
* ymd2yd - compute the date in the year from y/m/d
*/
+#include <config.h>
#include "ntp_fp.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
NULL=
-#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies
-AUTOMAKE_OPTIONS =
-BUILT_SOURCES =
+AUTOMAKE_OPTIONS =
+BUILT_SOURCES = info_trimble.c
noinst_LIBRARIES = @MAKE_LIBPARSE@ @MAKE_LIBPARSE_KERNEL@
EXTRA_LIBRARIES = libparse.a libparse_kernel.a
EXTRA_PROGRAMS = parsestreams parsesolaris
noinst_PROGRAMS = @MAKE_PARSEKMODULE@
-CLEANFILES = libparse.a libparse_kernel.a info_trimble.c
+CLEANFILES =
K_CFLAGS = -DPARSESTREAM -DNTP_NEED_BOPS
+# info_trimble.c was mistakenly created in the build directory
+# previously. Without special steps, building an updated tree from
+# outside the source directory (a VPATH build) would break trying to
+# update info_trimble.c in the build dir using the default SCCS get
+# action.
+# As a transitional measure, info_trimble.c is listed in
+# libparse_a_SOURCES prefixed by "$(srcdir)/".
+# This prevents attempting to update or use an old leftover
+# info_trimble.c in the build directory, when building outside
+# the source directory. At the same time, the rule to generate
+# info_trimble.c (now in the source directory) has been updated
+# to delete any leftover info_trimble.c in the build directory. To
+# ensure that fires in all build trees sharing a common source tree,
+# $(srcdir)/info_trimble.c now depends on Makefile, and has been added
+# temporarily to BUILT_SOURCES. This causes builds of updated trees to
+# get rid of the troublesome leftover info_trimble.c files in the build
+# directories.
+# After a month or so, this comment block should be removed, the
+# reference to info_trimble.c in libparse_a_SOURCES simplified to
+# filename only again, info_trimble.c be removed from BUILT_SOURCES,
+# and the commented-out $(srcdir)/info_trimble.c rule should replace
+# the info_trimble.c rule.
+
libparse_a_SOURCES = parse.c \
parse_conf.c \
clk_meinberg.c \
clk_wharton.c \
clk_varitext.c \
data_mbg.c \
- info_trimble.c \
+ $(srcdir)/info_trimble.c \
trim_info.c \
binio.c \
ieee754io.c \
EXTRA_DIST = parsesolaris.c parsestreams.c mkinfo_scmd.sed mkinfo_rcmd.sed info_trimble.c
-#
-# create info_trimble.c
-#
-info_trimble.c: $(top_srcdir)/include/trimble.h mkinfo_rcmd.sed mkinfo_scmd.sed
- @rm -f $@
- sed -n -f $(srcdir)/mkinfo_scmd.sed $(top_srcdir)/include/trimble.h > $@ || rm -f $@
- sed -n -f $(srcdir)/mkinfo_rcmd.sed $(top_srcdir)/include/trimble.h >> $@ || rm -f $@
-
-kieee754io.o: ieee754io.c
+info_trimble.c: Makefile $(top_srcdir)/include/trimble.h $(srcdir)/Makefile.am $(srcdir)/mkinfo_scmd.sed $(srcdir)/mkinfo_rcmd.sed
+ [ "$(srcdir)" != "." ] && rm -f info_trimble.c # rid ourselves of leftover from old way
+ sed -n -f $(srcdir)/mkinfo_scmd.sed $(top_srcdir)/include/trimble.h > info_trimble.new
+ sed -n -f $(srcdir)/mkinfo_rcmd.sed $(top_srcdir)/include/trimble.h >> info_trimble.new
+ cmp info_trimble.new $(srcdir)/info_trimble.c || mv -f info_trimble.new $(srcdir)/info_trimble.c
+ rm -f info_trimble.new
+
+# the workaround form above fires too much, such as during
+# "make install", due to the incorrect info_trimble.c target
+# rather than $(srcdir)/info_trimble.c. That's why it verifies
+# the file contents have changed before modifying it.
+# post-workaround version:
+# $(srcdir)/info_trimble.c: $(top_srcdir)/include/trimble.h $(srcdir)/Makefile.am $(srcdir)/mkinfo_scmd.sed $(srcdir)/mkinfo_rcmd.sed
+# sed -n -f $(srcdir)/mkinfo_scmd.sed $(top_srcdir)/include/trimble.h > info_trimble.new
+# sed -n -f $(srcdir)/mkinfo_rcmd.sed $(top_srcdir)/include/trimble.h >> info_trimble.new
+# mv -f info_trimble.new $@
+
+kieee754io.o: $(srcdir)/ieee754io.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/ieee754io.c -o $@
-kmfp_mul.o: mfp_mul.c
+kmfp_mul.o: $(srcdir)/mfp_mul.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/mfp_mul.c -o $@
-kgpstolfp.o: gpstolfp.c
+kgpstolfp.o: $(srcdir)/gpstolfp.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/gpstolfp.c -o $@
-kbinio.o: binio.c
+kbinio.o: $(srcdir)/binio.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/binio.c -o $@
-kclk_computime.o: clk_computime.c
+kclk_computime.o: $(srcdir)/clk_computime.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_computime.c -o $@
-kclk_computime_.o: clk_computime_.c
- $(COMPILE) $(K_CFLAGS) -c clk_computime_.c -o $@
-
-kclk_dcf7000.o: clk_dcf7000.c
+kclk_dcf7000.o: $(srcdir)/clk_dcf7000.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_dcf7000.c -o $@
-kclk_dcf7000_.o: clk_dcf7000_.c
- $(COMPILE) $(K_CFLAGS) -c clk_dcf7000_.c -o $@
-
-kclk_hopf6021.o: clk_hopf6021.c
+kclk_hopf6021.o: $(srcdir)/clk_hopf6021.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_hopf6021.c -o $@
-kclk_hopf6021_.o: clk_hopf6021_.c
- $(COMPILE) $(K_CFLAGS) -c clk_hopf6021_.c -o $@
-
-kclk_meinberg.o: clk_meinberg.c
+kclk_meinberg.o: $(srcdir)/clk_meinberg.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_meinberg.c -o $@
-kclk_meinberg_.o: clk_meinberg_.c
- $(COMPILE) $(K_CFLAGS) -c clk_meinberg_.c -o $@
-
-kclk_rawdcf.o: clk_rawdcf.c
+kclk_rawdcf.o: $(srcdir)/clk_rawdcf.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_rawdcf.c -o $@
-kclk_rawdcf_.o: clk_rawdcf_.c
- $(COMPILE) $(K_CFLAGS) -c clk_rawdcf_.c -o $@
-
-kclk_rcc8000.o: clk_rcc8000.c
+kclk_rcc8000.o: $(srcdir)/clk_rcc8000.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_rcc8000.c -o $@
-kclk_rcc8000_.o: clk_rcc8000_.c
- $(COMPILE) $(K_CFLAGS) -c clk_rcc8000_.c -o $@
-
-kclk_schmid.o: clk_schmid.c
+kclk_schmid.o: $(srcdir)/clk_schmid.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_schmid.c -o $@
-kclk_schmid_.o: clk_schmid_.c
- $(COMPILE) $(K_CFLAGS) -c clk_schmid_.c -o $@
-
-kclk_trimtaip.o: clk_trimtaip.c
+kclk_trimtaip.o: $(srcdir)/clk_trimtaip.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_trimtaip.c -o $@
-kclk_trimtaip_.o: clk_trimtaip_.c
- $(COMPILE) $(K_CFLAGS) -c clk_trimtaip_.c -o $@
-
-kclk_trimtsip.o: clk_trimtsip.c
+kclk_trimtsip.o: $(srcdir)/clk_trimtsip.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_trimtsip.c -o $@
-kclk_trimtsip_.o: clk_trimtsip_.c
- $(COMPILE) $(K_CFLAGS) -c clk_trimtsip_.c -o $@
-
-kclk_varitext.o: clk_varitext.c
+kclk_varitext.o: $(srcdir)/clk_varitext.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_varitext.c -o $@
-kclk_varitext_.o: clk_varitext_.c
- $(COMPILE) $(K_CFLAGS) -c clk_varitext_.c -o $@
-
-kclk_wharton.o: clk_wharton.c
+kclk_wharton.o: $(srcdir)/clk_wharton.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/clk_wharton.c -o $@
-kclk_wharton_.o: clk_wharton_.c
- $(COMPILE) $(K_CFLAGS) -c clk_wharton_.c -o $@
-
-kparse.o: parse.c
+kparse.o: $(srcdir)/parse.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/parse.c -o $@
-kparse_.o: parse_.c
- $(COMPILE) $(K_CFLAGS) -c parse_.c -o $@
-
-kparse_conf.o: parse_conf.c
+kparse_conf.o: $(srcdir)/parse_conf.c
$(COMPILE) $(K_CFLAGS) -c $(srcdir)/parse_conf.c -o $@
-kparse_conf_.o: parse_conf_.c
- $(COMPILE) $(K_CFLAGS) -c parse_conf_.c -o $@
-
parsestreams.loadable_module.o: $(parsestreams_OBJECTS) libparse_kernel.a ../libntp/libntp.a
$(LD) -r -o $@ $(parsestreams_OBJECTS) libparse_kernel.a ../libntp/libntp.a
parsesolaris.o: sys/systm.h
sys/systm.h:
- mkdir sys && \
+ -mkdir sys
sed -e '/ffs(.*)/d' < /usr/include/sys/systm.h > sys/systm.h
include $(top_srcdir)/depsver.mf
*
*/
+#include <config.h>
#include "binio.h"
long
*
*/
+#include <config.h>
#ifdef PARSESTREAM
#define NEED_BOPS
#include "ntp_string.h"
* SUCH DAMAGE.
*
*/
+#include <config.h>
#include "ntp_fp.h"
#define GPSORIGIN 2524953600UL /* NTP origin - GPS origin in seconds */
* Automatically generated - do not modify
*/
+#include <config.h>
#include "ntp_types.h"
#include "ntpd.h"
#include "trimble.h"
{ CMD_RSUPER, "CMD_RSUPER", "super paket (0x8F)", "", 0 },
{ 0xFF, "", "" }
};
-
* SUCH DAMAGE.
*
*/
+#include <config.h>
#include <stdio.h>
#include "ntp_stdlib.h"
#include "ntp_types.h"
1i\
\
+\
cmd_info_t trimble_rcmds[] = {
-s!^#define[ ][ ]*\(CMD_R[^ ]*\)[ ][ ]*\([^ ]*\)[ ][ ]*/\*[ ][ ]*\(.*\)[ ]*:\([^:]*\):\([^:]*\)[ ][ ]*\*/! { \1, "\1", "\3 (\2)", "\4", \5 },!p
+s!^#define[ \ ][ \ ]*\(CMD_R[^ \ ]*\)[ \ ][ \ ]*\([^ \ ]*\)[ \ ][ \ ]*/\*[ \ ][ \ ]*\(.*\)[ \ ]*:\([^:]*\):\([^:]*\)[ \ ][ \ ]*\*/!\ { \1, "\1", "\3 (\2)", "\4", \5 },!p
$a\
- { 0xFF, "", "" }\
-};\
-
+\ { 0xFF, "", "" }\
+};
1i\
/*\
- * Automatically generated - do not modify\
- */\
+\ * Automatically generated - do not modify\
+\ */\
\
+#include <config.h>\
#include "ntp_types.h"\
#include "ntpd.h"\
#include "trimble.h"\
cmd_info_t trimble_scmds[] = {
s!^#define[ ][ ]*\(CMD_C[^ ]*\)[ ][ ]*\([^ ]*\)[ ][ ]*/\*[ ][ ]*\(.*\)[ ][ ]*\*/! { \1, "\1", "\3 (\2)", "", 0 },!p
$a\
- { 0xFF, "", "" }\
-};\
-
-
+\ { 0xFF, "", "" }\
+};
static char rcsid[] = "parsesolaris.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A";
#endif
+#include <config.h>
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/errno.h>
* SUCH DAMAGE.
*
*/
+#include <config.h>
#include "ntp_types.h"
#include "trimble.h"
#
# VPHACK and VPHACK_AFTER are enabled on non-GNU makes (such as
# BSD make) to work around issues specific to compiling
-# ntp_parser.y into ntp_parser.h and ntp_parser.c in a vPATH
+# ntp_parser.y into ntp_parser.h and ntp_parser.c in a VPATH
# configuration where we would like (for a change) the output
# files ntp_parser.[ch] to be placed in the source directory,
# as opposed to the build directory. This allows a single
ntp_signd.c \
ntp_timer.c \
ntp_util.c \
+ ntp_worker.c \
ppsapi_timepps.h \
refclock_acts.c \
refclock_arbiter.c \
refclock_wwv.c \
refclock_wwvb.c \
refclock_zyfer.c \
+ work_fork.c \
+ work_thread.c \
$(NULL)
ntp_keyword.out: keyword-gen
* Definitions of things either imported from or exported to outside
*/
extern char const *progname;
-extern const char *specific_interface;
#ifdef HAVE_NETINFO
extern int check_netinfo;
if (HAVE_OPT( USER )) {
droproot = 1;
user = estrdup(OPT_ARG( USER ));
- group = rindex(user, ':');
- if (group)
+ group = strrchr(user, ':');
+ if (group != NULL)
*group++ = '\0'; /* get rid of the ':' */
}
#endif
# include <netinfo/ni.h>
#endif
+#include <stdio.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#include <signal.h>
+#ifndef SIGCHLD
+# define SIGCHLD SIGCLD
+#endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
#include "ntp.h"
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_stdlib.h"
#include "ntp_assert.h"
#include "ntpd-opts.h"
-/*
- * Sim header. Currently unconditionally included
- * PDMXXX This needs to be a conditional include
- */
-#include "ntpsim.h"
-
-#include <ntp_random.h>
-#include "ntp_intres.h"
+#include "ntp_random.h"
+#include "ntp_workimpl.h"
#include <isc/net.h>
#include <isc/result.h>
-#include <stdio.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#endif
-#include <signal.h>
-#ifndef SIGCHLD
-# define SIGCHLD SIGCLD
-#endif
-#if !defined(VMS)
-# ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-# endif
-#endif /* VMS */
-
-#ifdef SYS_WINNT
-# include <io.h>
-HANDLE ResolverEventHandle;
-#else
-int resolver_pipe_fd[2]; /* used to let the resolver process alert the parent process */
-#endif /* SYS_WINNT */
/*
* [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
* "logconfig" building blocks
*/
struct masks {
- const char *name;
- unsigned long mask;
+ const char * name;
+ unsigned long mask;
};
static struct masks logcfg_class[] = {
- { "clock", NLOG_OCLOCK },
- { "peer", NLOG_OPEER },
- { "sync", NLOG_OSYNC },
- { "sys", NLOG_OSYS },
- { (char *)0, 0 }
+ { "clock", NLOG_OCLOCK },
+ { "peer", NLOG_OPEER },
+ { "sync", NLOG_OSYNC },
+ { "sys", NLOG_OSYS },
+ { NULL, 0 }
};
static struct masks logcfg_item[] = {
{ "allsys", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS },
{ "allsync", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC },
{ "all", NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK },
- { (char *)0, 0 }
+ { NULL, 0 }
};
/* Limits */
#define ISSPACE(c) ((c) == ' ' || (c) == '\t')
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
-/*
- * File descriptor used by the resolver save routines, and temporary file
- * name.
- */
-int call_resolver = 1; /* ntp-genkeys sets this to 0, for example */
-#ifndef SYS_WINNT
-static char res_file[20]; /* enough for /tmp/ntpXXXXXX\0 */
-#define RES_TEMPFILE "/tmp/ntpXXXXXX"
-#else
-static char res_file[MAX_PATH];
-#endif /* SYS_WINNT */
-
/*
* Definitions of things either imported from or exported to outside
*/
extern int yydebug; /* ntp_parser.c (.y) */
int curr_include_level; /* The current include level */
struct FILE_INFO *fp[MAXINCLUDELEVEL+1];
-FILE *res_fp;
struct config_tree cfgt; /* Parser output stored here */
-struct config_tree *cfg_tree_history = NULL; /* History of configs */
+struct config_tree *cfg_tree_history; /* History of configs */
char *sys_phone[MAXPHONE] = {NULL}; /* ACTS phone numbers */
char default_keysdir[] = NTP_KEYSDIR;
char *keysdir = default_keysdir; /* crypto keys directory */
void destroy_restrict_node(struct restrict_node *my_node);
static int is_sane_resolved_address(sockaddr_u *peeraddr, int hmode);
static int get_correct_host_mode(int hmode);
+static int peerflag_bits(struct peer_node *);
static void save_and_apply_config_tree(void);
void getconfig(int, char **);
#if !defined(SIM)
static void config_ntpd(struct config_tree *);
#endif
+#ifdef WORKER
+void peer_name_resolved(int, int, void *, const char *, const char *,
+ const struct addrinfo *,
+ const struct addrinfo *);
+void unpeer_name_resolved(int, int, void *, const char *, const char *,
+ const struct addrinfo *,
+ const struct addrinfo *);
+#endif
+
enum gnn_type {
t_UNK, /* Unknown */
t_REF, /* Refclock */
static int get_multiple_netnums(const char *num, sockaddr_u *addr,
struct addrinfo **res, int complain,
enum gnn_type a_type);
-static void save_resolve(char *name, int no_needed, int type,
- int mode, int version, int minpoll, int maxpoll,
- u_int flags, int ttl, keyid_t keyid, u_char *keystr);
-static void abort_resolve(void);
-static void do_resolve_internal(void);
struct config_tree *ptree
)
{
- extern int cache_type; /* authkeys.c */
#ifdef OPENSSL
-#ifndef NO_INTRES
- u_char digest[EVP_MAX_MD_SIZE];
- u_int digest_len;
- EVP_MD_CTX ctx;
-#endif
struct attr_val *my_val;
int item;
#endif
if (ptree->auth.revoke)
sys_revoke = ptree->auth.revoke;
#endif /* OPENSSL */
-
-#ifndef NO_INTRES
- /* find a keyid */
- if (info_auth_keyid == 0)
- req_keyid = 65535;
- else
- req_keyid = info_auth_keyid;
-
- /* if doesn't exist, make up one at random */
- if (authhavekey(req_keyid)) {
- req_keytype = cache_type;
-#ifndef OPENSSL
- req_hashlen = 16;
-#else /* OPENSSL follows */
- EVP_DigestInit(&ctx, EVP_get_digestbynid(req_keytype));
- EVP_DigestFinal(&ctx, digest, &digest_len);
- req_hashlen = digest_len;
-#endif
- } else {
- int rankey;
-
- rankey = ntp_random();
- req_keytype = NID_md5;
- req_hashlen = 16;
- MD5auth_setkey(req_keyid, req_keytype,
- (u_char *)&rankey, sizeof(rankey));
- authtrust(req_keyid, 1);
- }
-
- /* save keyid so we will accept config requests with it */
- info_auth_keyid = req_keyid;
-#endif /* !NO_INTRES */
-
}
)
{
struct attr_val *curr_var;
- FILE *new_file;
int len;
curr_var = queue_head(ptree->vars);
stats_config(STATS_PID_FILE, curr_var->value.s);
break;
case T_Logfile:
- new_file = fopen(curr_var->value.s, "a");
- if (new_file != NULL) {
- NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
- msyslog(LOG_NOTICE, "logging to file %s", curr_var->value.s);
- if (syslog_file != NULL &&
- fileno(syslog_file) != fileno(new_file))
- (void)fclose(syslog_file);
-
- syslog_file = new_file;
- syslogit = 0;
- }
- else
+ if (-1 == change_logfile(curr_var->value.s, 0))
msyslog(LOG_ERR,
- "Cannot open log file %s",
+ "Cannot open logfile %s: %m",
curr_var->value.s);
break;
return 1;
}
+
static int
get_correct_host_mode(
- int hmode
+ int token
)
{
- switch (hmode) {
+ switch (token) {
case T_Server:
case T_Pool:
case T_Manycastclient:
}
}
-static void
-config_peers(
- struct config_tree *ptree
+
+/*
+ * peerflag_bits() get config_peers() peerflags value from a
+ * peer_node's queue of flag attr_val entries.
+ */
+static int
+peerflag_bits(
+ struct peer_node *pn
)
{
- struct addrinfo *res, *res_bak;
- sockaddr_u peeraddr;
- struct peer_node *curr_peer;
- struct attr_val *option;
- int hmode;
int peerflags;
- int status;
- int no_needed;
- int i;
+ struct attr_val *option;
- curr_peer = queue_head(ptree->peers);
- while (curr_peer != NULL) {
- /* Find the number of associations needed.
- * If a pool coomand is specified, then sys_maxclock needed
- * else, only one is needed
- */
- no_needed = (T_Pool == curr_peer->host_mode)
- ? sys_maxclock
- : 1;
+ /* translate peerflags options to bits */
+ peerflags = 0;
+ option = queue_head(pn->peerflags);
+ for (; option != NULL; option = next_node(option))
+ switch (option->value.i) {
- /* Find the correct host-mode */
- hmode = get_correct_host_mode(curr_peer->host_mode);
- NTP_INSIST(hmode != -1);
+ default:
+ NTP_INSIST(0);
+ break;
- /* translate peerflags options to bits */
- peerflags = 0;
- option = queue_head(curr_peer->peerflags);
- for (; option != NULL; option = next_node(option))
- switch (option->value.i) {
+ case T_Autokey:
+ peerflags |= FLAG_SKEY;
+ break;
- default:
- NTP_INSIST(0);
- break;
+ case T_Burst:
+ peerflags |= FLAG_BURST;
+ break;
- case T_Autokey:
- peerflags |= FLAG_SKEY;
- break;
+ case T_Iburst:
+ peerflags |= FLAG_IBURST;
+ break;
- case T_Burst:
- peerflags |= FLAG_BURST;
- break;
+ case T_Noselect:
+ peerflags |= FLAG_NOSELECT;
+ break;
- case T_Iburst:
- peerflags |= FLAG_IBURST;
- break;
+ case T_Preempt:
+ peerflags |= FLAG_PREEMPT;
+ break;
- case T_Noselect:
- peerflags |= FLAG_NOSELECT;
- break;
+ case T_Prefer:
+ peerflags |= FLAG_PREFER;
+ break;
- case T_Preempt:
- peerflags |= FLAG_PREEMPT;
- break;
+ case T_True:
+ peerflags |= FLAG_TRUE;
+ break;
- case T_Prefer:
- peerflags |= FLAG_PREFER;
- break;
+ case T_Xleave:
+ peerflags |= FLAG_XLEAVE;
+ break;
+ }
- case T_True:
- peerflags |= FLAG_TRUE;
- break;
+ return peerflags;
+}
- case T_Xleave:
- peerflags |= FLAG_XLEAVE;
- break;
- }
- /* Attempt to resolve the address */
- ZERO_SOCK(&peeraddr);
- AF(&peeraddr) = (u_short)curr_peer->addr->type;
+static void
+config_peers(
+ struct config_tree *ptree
+ )
+{
+ sockaddr_u peeraddr;
+ isc_netaddr_t i_netaddr;
+ struct addrinfo hints;
+ struct peer_node *curr_peer;
+ int hmode;
+ int num_needed;
- status = get_multiple_netnums(curr_peer->addr->address,
- &peeraddr, &res, 0, t_UNK);
+ for (curr_peer = queue_head(ptree->peers);
+ curr_peer != NULL;
+ curr_peer = next_node(curr_peer)) {
-#ifdef FORCE_DEFER_DNS
- /* Hack for debugging Deferred DNS
- * Pretend working names didn't work.
- */
- if (status == 1) {
- /* Deferring everything breaks refclocks. */
- memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
- if (!ISREFCLOCKADR(&peeraddr)) {
- status = 0; /* force deferred DNS path */
- msyslog(LOG_INFO, "Forcing Deferred DNS for %s, %s",
- curr_peer->addr->address, stoa(&peeraddr));
- } else {
- msyslog(LOG_INFO, "NOT Deferring DNS for %s, %s",
- curr_peer->addr->address, stoa(&peeraddr));
- }
- }
-#endif
+ /* Find the correct host-mode */
+ hmode = get_correct_host_mode(curr_peer->host_mode);
+ NTP_INSIST(hmode != -1);
- /* I don't know why getnetnum would return -1.
- * The old code had this test, so I guess it must be
- * useful
+ /* Find the number of associations needed.
+ * If a pool coomand is specified, then sys_maxclock needed
+ * else, only one is needed
*/
- if (status == -1) {
- /* Do nothing, apparently we found an IPv6
- * address and can't do anything about it */
- }
- /* Check if name resolution failed. If yes, store the
- * peer information in a file for asynchronous
- * resolution later
+ num_needed = (T_Pool == curr_peer->host_mode)
+ ? sys_maxclock
+ : 1;
+
+ /*
+ * If we have a numeric address, we can safely use
+ * getaddrinfo in the mainline with it. Otherwise
+ * hand it off to the blocking child.
*/
- else if (status != 1) {
- msyslog(LOG_INFO, "Deferring DNS for %s %d", curr_peer->addr->address, no_needed);
- save_resolve(curr_peer->addr->address,
- no_needed,
- curr_peer->addr->type,
- hmode,
- curr_peer->peerversion,
- curr_peer->minpoll,
- curr_peer->maxpoll,
- peerflags,
- curr_peer->ttl,
- curr_peer->peerkey,
- (u_char *)"*");
+ memset(&i_netaddr, 0, sizeof(i_netaddr));
+ i_netaddr.family = (u_short)curr_peer->addr->type;
+
+ if (1 == num_needed
+ && is_ip_address(curr_peer->addr->address,
+ &i_netaddr)) {
+
+ AF(&peeraddr) = (u_short)i_netaddr.family;
+ SET_PORT(&peeraddr, NTP_PORT);
+ if (AF_INET6 == i_netaddr.family)
+ SET_ADDR6N(&peeraddr,
+ i_netaddr.type.in6);
+ else
+ SET_ADDR4N(&peeraddr,
+ i_netaddr.type.in.s_addr);
+
+ if (is_sane_resolved_address(&peeraddr,
+ curr_peer->host_mode))
+ peer_config(&peeraddr,
+ NULL,
+ hmode,
+ curr_peer->peerversion,
+ curr_peer->minpoll,
+ curr_peer->maxpoll,
+ peerflag_bits(curr_peer),
+ curr_peer->ttl,
+ curr_peer->peerkey,
+ (u_char *)"*");
+ } else {
+ /* we have a hostname to resolve */
+#ifdef WORKER
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = (u_short)curr_peer->addr->type;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ getaddrinfo_sometime(curr_peer->addr->address, "ntp",
+ &hints, &peer_name_resolved,
+ (void *)curr_peer);
+#else /* !WORKER follows */
+ msyslog(LOG_ERR,
+ "hostname %s can not be used, please use address\n",
+ curr_peer->addr->address);
+#endif
}
- /* Yippie!! Name resolution has succeeded!!!
- * Now we can proceed to some more sanity checks on
- * the resolved address before we start to configure
- * the peer
- */
- else {
- res_bak = res;
+ }
+}
- /*
- * Loop to configure the desired number of
- * associations
- */
- for (i = 0; (i < no_needed) && res; res =
- res->ai_next) {
- ++i;
- memcpy(&peeraddr, res->ai_addr,
- res->ai_addrlen);
- if (is_sane_resolved_address(
- &peeraddr,
- curr_peer->host_mode))
-
- peer_config(&peeraddr,
- NULL,
- hmode,
- curr_peer->peerversion,
- curr_peer->minpoll,
- curr_peer->maxpoll,
- peerflags,
- curr_peer->ttl,
- curr_peer->peerkey,
- (u_char *)"*");
+
+/*
+ * peer_name_resolved()
+ *
+ * Callback invoked when config_peers()'s DNS lookup completes.
+ */
+#ifdef WORKER
+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;
+ struct peer_node * curr_peer;
+ int num_needed;
+ int hmode;
+ int i;
+ int af;
+ const char * fam_spec;
+
+ curr_peer = context;
+
+ DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode));
+
+ if (rescode) {
+#ifndef IGNORE_DNS_ERRORS
+ msyslog(LOG_ERR,
+ "giving up resolving host %s: %s (%d)",
+ name, gai_strerror(rescode), rescode);
+#else /* IGNORE_DNS_ERRORS follows */
+ getaddrinfo_sometime(name, service, hints,
+ &peer_name_resolved, context);
+#endif
+ return;
+ }
+
+ hmode = get_correct_host_mode(curr_peer->host_mode);
+ NTP_INSIST(hmode != -1);
+ num_needed = (T_Pool == curr_peer->host_mode)
+ ? sys_maxclock
+ : 1;
+
+ /* Loop to configure the desired number of associations */
+ for (i = 0;
+ res != NULL && i < num_needed;
+ res = res->ai_next) {
+
+ memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
+
+ if (is_sane_resolved_address(&peeraddr,
+ curr_peer->host_mode)) {
+ i++;
+ NLOG(NLOG_SYSINFO) {
+ af = curr_peer->addr->type;
+ fam_spec = (AF_INET6 == af)
+ ? "(AAAA) "
+ : (AF_INET == af)
+ ? "(A) "
+ : "";
+ msyslog(LOG_INFO, "DNS %s %s-> %s",
+ name, fam_spec,
+ stoa(&peeraddr));
}
- freeaddrinfo(res_bak);
+ peer_config(&peeraddr,
+ NULL,
+ hmode,
+ curr_peer->peerversion,
+ curr_peer->minpoll,
+ curr_peer->maxpoll,
+ peerflag_bits(curr_peer),
+ curr_peer->ttl,
+ curr_peer->peerkey,
+ (u_char *)"*");
}
- curr_peer = next_node(curr_peer);
}
}
+#endif /* WORKER */
#ifdef FREE_CFG_T
struct config_tree *ptree
)
{
- struct addrinfo *res, *res_bak;
sockaddr_u peeraddr;
+ struct addrinfo hints;
+ isc_netaddr_t i_netaddr;
struct unpeer_node *curr_unpeer;
struct peer *peer;
- int status;
int found;
for (curr_unpeer = queue_head(ptree->unpeers);
continue;
}
- /* Attempt to resolve the name or address */
- ZERO_SOCK(&peeraddr);
- AF(&peeraddr) = (u_short)curr_unpeer->addr->type;
+ /*
+ * If we have a numeric address, we can safely use
+ * getaddrinfo in the mainline with it. Otherwise
+ * hand it off to the blocking child.
+ */
+ memset(&i_netaddr, 0, sizeof(i_netaddr));
+ i_netaddr.family = (u_short)curr_unpeer->addr->type;
- status = get_multiple_netnums(
- curr_unpeer->addr->address, &peeraddr, &res, 0,
- t_UNK);
+ if (is_ip_address(curr_unpeer->addr->address, &i_netaddr)) {
- /* I don't know why getnetnum would return -1.
- * The old code had this test, so I guess it must be
- * useful
- */
- if (status == -1) {
- /* Do nothing, apparently we found an IPv6
- * address and can't do anything about it */
- }
- /* Check if name resolution failed. If yes, throw
- * up our hands.
- */
- else if (status != 1) {
- /* Do nothing */
+ AF(&peeraddr) = (u_short)i_netaddr.family;
+ if (AF_INET6 == i_netaddr.family)
+ SET_ADDR6N(&peeraddr,
+ i_netaddr.type.in6);
+ else
+ SET_ADDR4N(&peeraddr,
+ i_netaddr.type.in.s_addr);
+
+ found = 0;
+ peer = NULL;
+
+ DPRINTF(1, ("searching for %s\n", stoa(&peeraddr)));
+
+ do {
+ peer = findexistingpeer(&peeraddr, peer, -1);
+ if (NULL != peer && (FLAG_CONFIG & peer->flags))
+ found = 1;
+ } while (!found && NULL != peer);
+
+ if (found) {
+ msyslog(LOG_INFO, "unpeered %s",
+ stoa(&peeraddr));
+ peer_clear(peer, "GONE");
+ unpeer(peer);
+ }
+ } else {
+ /* we have a hostname to resolve */
+#ifdef WORKER
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = (u_short)curr_unpeer->addr->type;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ getaddrinfo_sometime(curr_unpeer->addr->address, "ntp",
+ &hints, &unpeer_name_resolved,
+ (void *)curr_unpeer);
+#else /* !WORKER follows */
+ msyslog(LOG_ERR,
+ "hostname %s can not be used, please use address\n",
+ curr_unpeer->addr->address);
+#endif
}
- /* Yippie!! Name resolution has succeeded!!!
- */
- else {
- res_bak = res;
+ }
+}
- /*
- * Loop through the addresses found
- */
- while (res) {
- memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
- found = 0;
- peer = NULL;
+/*
+ * unpeer_name_resolved()
+ *
+ * Callback invoked when config_unpeers()'s DNS lookup completes.
+ */
+#ifdef WORKER
+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 unpeer_node * curr_unpeer;
+ struct peer * peer;
+ int found;
+ int af;
+ const char * fam_spec;
- DPRINTF(1, ("searching for %s\n", stoa(&peeraddr)));
+ DPRINTF(1, ("unpeer_name_resolved(%s) rescode %d\n", name, rescode));
- while (!found) {
- peer = findexistingpeer(&peeraddr, peer, -1);
- if (!peer)
- break;
- if (peer->flags & FLAG_CONFIG)
- found = 1;
- }
+ curr_unpeer = context;
- if (found) {
- peer_clear(peer, "GONE");
- unpeer(peer);
- }
+ if (rescode)
+ msyslog(LOG_ERR, "giving up resolving unpeer %s: %s (%d)",
+ name, gai_strerror(rescode), rescode);
+ else {
+ /*
+ * Loop through the addresses found
+ */
+ while (res) {
+ found = 0;
+ peer = NULL;
- res = res->ai_next;
+ memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
+ DPRINTF(1, ("searching for peer %s\n", stoa(&peeraddr)));
+
+ do {
+ peer = findexistingpeer(&peeraddr, peer, -1);
+ if (NULL != peer && (FLAG_CONFIG & peer->flags))
+ found = 1;
+ } while (!found && NULL != peer);
+
+ if (found) {
+ af = curr_unpeer->addr->type;
+ fam_spec = (AF_INET6 == af)
+ ? "(AAAA) "
+ : (AF_INET == af)
+ ? "(A) "
+ : "";
+ msyslog(LOG_INFO, "unpeered %s %s-> %s",
+ name, fam_spec,
+ stoa(&peeraddr));
+ peer_clear(peer, "GONE");
+ unpeer(peer);
}
- freeaddrinfo(res_bak);
+
+ res = res->ai_next;
}
}
}
+#endif /* WORKER */
#ifdef FREE_CFG_T
config_unpeers(ptree);
config_fudge(ptree);
config_qos(ptree);
+
+#ifdef TEST_BLOCKING_WORKER
+ {
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ getaddrinfo_sometime("www.cnn.com", "ntp", &hints, gai_test_callback, (void *)1);
+ hints.ai_family = AF_INET6;
+ getaddrinfo_sometime("ipv6.google.com", "ntp", &hints, gai_test_callback, (void *)0x600);
+ }
+#endif
}
#endif /* !SIM */
exit(1);
}
alt_config_file = alt_config_file_storage;
-
#endif /* SYS_WINNT */
- res_fp = NULL;
- ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */
/*
* install a non default variable with this daemon version
if (config_netinfo)
free_netinfo_config(config_netinfo);
#endif /* HAVE_NETINFO */
-
- /*
- printf("getconfig: res_fp <%p> call_resolver: %d", res_fp, call_resolver);
- */
-
- if (res_fp != NULL) {
- if (call_resolver) {
- /*
- * Need name resolution
- */
- do_resolve_internal();
- }
- }
}
}
-#if !defined(VMS) && !defined(SYS_WINNT)
-/*
- * catchchild - receive the resolver's exit status
- */
-static RETSIGTYPE
-catchchild(
- int sig
- )
-{
- /*
- * We only start up one child, and if we're here
- * it should have already exited. Hence the following
- * shouldn't hang. If it does, please tell me.
- */
-#if !defined (SYS_WINNT) && !defined(SYS_VXWORKS)
- (void) wait(0);
-#endif /* SYS_WINNT && VXWORKS*/
-}
-#endif /* VMS */
-
-
-/*
- * save_resolve - save configuration info into a file for later name resolution
- */
-static void
-save_resolve(
- char *name,
- int no_needed,
- int type,
- int mode,
- int version,
- int minpoll,
- int maxpoll,
- u_int flags,
- int ttl,
- keyid_t keyid,
- u_char *keystr
- )
-{
-#ifndef SYS_VXWORKS
- if (res_fp == NULL) {
-#ifndef SYS_WINNT
- strcpy(res_file, RES_TEMPFILE);
-#else
- int len;
-
- /* no /tmp directory under NT */
- if (!GetTempPath(sizeof res_file, res_file)) {
- msyslog(LOG_ERR, "can not get temp dir: %m");
- exit(1);
- }
-
- len = strlen(res_file);
- if (sizeof res_file < len + sizeof "ntpdXXXXXX") {
- msyslog(LOG_ERR,
- "temporary directory path %s too long",
- res_file);
- exit(1);
- }
-
- memmove(res_file + len, "ntpdXXXXXX",
- sizeof "ntpdXXXXXX");
-#endif /* SYS_WINNT */
-#ifdef HAVE_MKSTEMP
- {
- int fd;
-
- res_fp = NULL;
- if ((fd = mkstemp(res_file)) != -1)
- res_fp = fdopen(fd, "r+");
- }
-#else
- mktemp(res_file);
- res_fp = fopen(res_file, "w");
-#endif
- if (res_fp == NULL) {
- msyslog(LOG_ERR, "open failed for %s: %m", res_file);
- return;
- }
- }
-#ifdef DEBUG
- if (debug) {
- printf("resolving %s\n", name);
- }
-#endif
-
- (void)fprintf(res_fp, "%s %d %d %d %d %d %d %d %d %u %s\n",
- name, no_needed, type,
- mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr);
-#ifdef DEBUG
- if (debug > 1)
- printf("config: %s %d %d %d %d %d %d %x %d %u %s\n",
- name, no_needed, type,
- mode, version, minpoll, maxpoll, flags,
- ttl, keyid, keystr);
-#endif
-
-#else /* SYS_VXWORKS */
- /* save resolve info to a struct */
-#endif /* SYS_VXWORKS */
-}
-
-
-/*
- * abort_resolve - terminate the resolver stuff and delete the file
- */
-static void
-abort_resolve(void)
-{
- /*
- * In an ideal world we would might reread the file and
- * log the hosts which aren't getting configured. Since
- * this is too much work, however, just close and delete
- * the temp file.
- */
- if (res_fp != NULL)
- (void) fclose(res_fp);
- res_fp = NULL;
-
-#ifndef SYS_VXWORKS /* we don't open the file to begin with */
-#if !defined(VMS)
- if (unlink(res_file))
- msyslog(LOG_WARNING,
- "Unable to remove temporary resolver file %s, %m",
- res_file);
-#else
- (void) delete(res_file);
-#endif /* VMS */
-#endif /* SYS_VXWORKS */
-}
-
-
-/*
- * do_resolve_internal - start up the resolver function (not program)
- *
- * On VMS, VxWorks, and Unix-like systems lacking fork(), this routine
- * will simply refuse to resolve anything.
- *
- * Possible implementation: keep `res_file' in memory, do async
- * name resolution via QIO, update from within completion AST.
- * I'm unlikely to find the time for doing this, though. -wjm
- */
-static void
-do_resolve_internal(void)
-{
-#ifndef SYS_WINNT
- int i;
-#endif
-
- if (res_fp == NULL) {
- /* belch */
- msyslog(LOG_ERR,
- "do_resolve_internal: Fatal: res_fp == NULL");
- exit(1);
- }
-
- /* we are done with this now */
- (void) fclose(res_fp);
- res_fp = NULL;
-
-#ifndef NO_INTRES
- req_file = res_file; /* set up pointer to res file */
-#ifndef SYS_WINNT
- (void) signal_no_reset(SIGCHLD, catchchild);
-
- /* the parent process will write to the pipe
- * in order to wake up to child process
- * which may be waiting in a select() call
- * on the read fd */
- if (pipe(resolver_pipe_fd) < 0) {
- msyslog(LOG_ERR,
- "unable to open resolver pipe");
- exit(1);
- }
-
- i = fork();
- /* Shouldn't the code below be re-ordered?
- * I.e. first check if the fork() returned an error, then
- * check whether we're parent or child.
- * Martin Burnicki
- */
- if (i == 0) {
- /*
- * this used to close everything
- * I don't think this is necessary
- */
- /*
- * To the unknown commenter above:
- * Well, I think it's better to clean up
- * after oneself. I have had problems with
- * refclock-io when intres was running - things
- * where fine again when ntpintres was gone.
- * So some systems react erratic at least.
- *
- * Frank Kardel
- *
- * 94-11-16:
- * Further debugging has proven that the above is
- * absolutely harmful. The internal resolver
- * is still in the SIGIO process group and the lingering
- * async io information causes it to process requests from
- * all file decriptor causing a race between the NTP daemon
- * and the resolver. which then eats data when it wins 8-(.
- * It is absolutly necessary to kill any IO associations
- * shared with the NTP daemon.
- *
- * We also block SIGIO (currently no ports means to
- * disable the signal handle for IO).
- *
- * Thanks to wgstuken@informatik.uni-erlangen.de to notice
- * that it is the ntp-resolver child running into trouble.
- *
- * THUS:
- */
-
- /*
- msyslog(LOG_INFO, "do_resolve_internal: pre-closelog");
- */
- closelog();
- kill_asyncio(0);
-
- (void) signal_no_reset(SIGCHLD, SIG_DFL);
-
- init_logging("ntpd_intres", 0);
- setup_logfile();
- /*
- msyslog(LOG_INFO, "do_resolve_internal: post-closelog");
- */
-
- ntp_intres();
-
- /*
- * If we got here, the intres code screwed up.
- * Print something so we don't die without complaint
- */
- msyslog(LOG_ERR, "call to ntp_intres lost");
- abort_resolve();
- exit(1);
- }
- if (i == -1) {
- msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m");
- (void) signal_no_reset(SIGCHLD, SIG_DFL);
- abort_resolve();
- } else
- /* This is the parent process who will write to the pipe,
- * so we close the read fd */
- close(resolver_pipe_fd[0]);
-#else /* SYS_WINNT */
- {
- /* NT's equivalent of fork() is _spawn(), but the start point
- * of the new process is an executable filename rather than
- * a function name as desired here.
- */
- unsigned thread_id;
- uintptr_t res_thd_handle;
-
- fflush(stdout);
- ResolverEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (ResolverEventHandle == NULL) {
- msyslog(LOG_ERR, "Unable to create resolver event object, can't start ntp_intres");
- abort_resolve();
- }
- res_thd_handle = _beginthreadex(
- NULL, /* no security attributes */
- 0, /* use default stack size */
- ntp_intres_thread, /* thread function */
- NULL, /* argument to thread function */
- 0, /* use default creation flags */
- &thread_id); /* receives thread identifier */
- if (!res_thd_handle) {
- msyslog(LOG_ERR, "_beginthreadex ntp_intres_thread failed %m");
- CloseHandle(ResolverEventHandle);
- ResolverEventHandle = NULL;
- abort_resolve();
- }
- }
-#endif /* SYS_WINNT */
-#else /* NO_INTRES follows */
- msyslog(LOG_ERR,
- "Deferred DNS not implemented - use numeric addresses");
- abort_resolve();
-#endif
-}
res_authenticate = 1;
res_keyid = ntohl(*(u_int32 *)((u_char *)pkt +
properlen));
-
DPRINTF(3, ("recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n",
rbufp->recv_length, properlen, res_keyid,
maclen));
else if (authdecrypt(res_keyid, (u_int32 *)pkt,
rbufp->recv_length - maclen,
maclen)) {
- DPRINTF(3, ("authenticated okay\n"));
res_authokay = 1;
+ DPRINTF(3, ("authenticated okay\n"));
} else {
- DPRINTF(3, ("authentication failed\n"));
res_keyid = 0;
+ DPRINTF(3, ("authentication failed\n"));
}
}
* This file contains the data structures used by the ntp configuration
* code and the discrete event simulator.
*
- * Written By: Sachin Kamboj
- * University of Delaware
- * Newark, DE 19711
+ * Written By: Sachin Kamboj
+ * University of Delaware
+ * Newark, DE 19711
* Copyright (c) 2006
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
-
-#include <stdlib.h> /* Needed for malloc */
#include "ntp_data_structures.h"
#include "ntp_stdlib.h"
*/
-queue *create_priority_queue(int (*get_order)(void *, void *))
+queue *debug_create_priority_queue(
+ int (*get_order)(void *, void *)
+#ifdef _CRTDBG_MAP_ALLOC
+ , const char *sourcefile
+ , int line_num
+#endif
+ )
{
- queue *my_queue = (queue *) emalloc(sizeof(queue));
- my_queue->get_order = get_order;
- my_queue->front = NULL;
- my_queue->no_of_elements = 0;
- return my_queue;
+ queue *my_queue;
+
+#ifndef _CRTDBG_MAP_ALLOC
+ my_queue = emalloc(sizeof(queue));
+#else
+ /* preserve original callsite __FILE__ and __LINE__ for leak report */
+ my_queue = debug_erealloc(NULL, sizeof(queue), sourcefile, line_num);
+#endif
+ my_queue->get_order = get_order;
+ my_queue->front = NULL;
+ my_queue->no_of_elements = 0;
+
+ return my_queue;
}
* all the allocated resources in the process
*/
-void destroy_queue(queue *my_queue)
+void destroy_queue(
+ queue *my_queue
+ )
{
node *temp = NULL;
* bytes plus the number of bytes needed for bookkeeping
*/
-void *get_node(size_t size)
+void *debug_get_node(
+ size_t size
+#ifdef _CRTDBG_MAP_ALLOC
+ , const char * sourcefile
+ , int line_num
+#endif
+ )
{
- node *new_node = emalloc(sizeof(*new_node) + size);
- new_node->node_next = NULL;
- return new_node + 1;
+ node *new_node;
+
+#ifndef _CRTDBG_MAP_ALLOC
+ new_node = emalloc(sizeof(*new_node) + size);
+#else
+ new_node = debug_erealloc(NULL, sizeof(*new_node) + size,
+ sourcefile, line_num);
+#endif
+ new_node->node_next = NULL;
+
+ return new_node + 1;
}
/* Define a function to free the allocated memory for a queue node */
-void free_node(void *my_node)
+void free_node(
+ void *my_node
+ )
{
- node *old_node = my_node;
- free(old_node - 1);
+ node *old_node = my_node;
+
+ free(old_node - 1);
}
/* Define a function to check if the queue is empty. */
-int empty(queue *my_queue)
+int empty(
+ queue *my_queue
+ )
{
- return (!my_queue || !my_queue->front);
+ return (!my_queue || !my_queue->front);
}
* The element is added according to its priority -
* relative priority is given by the get_order function
*/
-queue *enqueue(queue *my_queue, void *my_node)
+queue *enqueue(
+ queue * my_queue,
+ void * my_node
+ )
{
- node *new_node = ((node *) my_node) - 1;
- node *i = NULL;
- node *j = my_queue->front;
-
- while (j != NULL && ((*my_queue->get_order)(new_node + 1, j + 1) > 0)) {
- i = j;
- j = j->node_next;
- }
-
- if (i == NULL) { /* Insert at beginning of the queue */
- new_node->node_next = my_queue->front;
- my_queue->front = new_node;
- }
- else { /* Insert Elsewhere, including the end */
- new_node->node_next = i->node_next;
- i->node_next = new_node;
- }
-
- ++my_queue->no_of_elements;
- return my_queue;
+ node *new_node = (node *)my_node - 1;
+ node *i = NULL;
+ node *j = my_queue->front;
+
+ while (j != NULL &&
+ (*my_queue->get_order)(new_node + 1, j + 1) > 0) {
+ i = j;
+ j = j->node_next;
+ }
+
+ if (i == NULL) { /* Insert at beginning of the queue */
+ new_node->node_next = my_queue->front;
+ my_queue->front = new_node;
+ } else { /* Insert Elsewhere, including the end */
+ new_node->node_next = i->node_next;
+ i->node_next = new_node;
+ }
+
+ ++my_queue->no_of_elements;
+ return my_queue;
}
/* Define a function to dequeue the first element from the priority
* queue and return it
*/
-
-void *dequeue(queue *my_queue)
+void *dequeue(
+ queue *my_queue
+ )
{
- node *my_node = my_queue->front;
- if (my_node != NULL) {
- my_queue->front = my_node->node_next;
- --my_queue->no_of_elements;
- return (void *)(my_node + 1);
- }
- else
- return NULL;
+ node *my_node = my_queue->front;
+
+ if (my_node != NULL) {
+ my_queue->front = my_node->node_next;
+ --my_queue->no_of_elements;
+ return my_node + 1;
+ } else
+ return NULL;
}
+
/* Define a function that returns the number of elements in the
* priority queue
*/
-int get_no_of_elements(queue *my_queue)
+int get_no_of_elements(
+ queue *my_queue
+ )
{
- return my_queue->no_of_elements;
+ return my_queue->no_of_elements;
}
+
/* Define a function to append a queue onto another.
* Note: there is a faster way (O(1) as opposed to O(n))
* to do this for simple (FIFO) queues, but we can't rely on
* out to be a bottleneck, I will consider replacing the
* current implementation with a binomial or fibonacci heap.
*/
-
-void append_queue(queue *q1, queue *q2)
+void append_queue(
+ queue *q1,
+ queue *q2
+ )
{
- while (!empty(q2))
- enqueue(q1, dequeue(q2));
- destroy_queue(q2);
+ while (!empty(q2))
+ enqueue(q1, dequeue(q2));
+ destroy_queue(q2);
}
+
/* FIFO Queue
* ----------
* Use the priority queue to create a traditional FIFO queue.
/* C is not Lisp and does not allow anonymous lambda functions :-(.
* So define a get_fifo_order function here
*/
-
int get_fifo_order(void *el1, void *el2)
-{ return 1;
-}
-
-/* Define a function to create a FIFO queue */
-
-queue *create_queue()
-{ return create_priority_queue(get_fifo_order);
+{
+ return 1;
}
/*
- * ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92
- * routine callable from ntpd, rather than separate program
- * also, key info passed in via a global, so no key file needed.
- */
-
-/*
- * ntpres - process configuration entries which require use of the resolver
+ * ntp_intres.c - Implements a generic blocking worker child or 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 both Unix and Windows ntpd. ntp_worker.c, work_fork.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 initial implementation for Unix uses a pair of unidirectional
+ * pipes, one each for requests and responses, connecting the forked
+ * blocking child worker with the ntpd mainline. The threaded code
+ * uses arrays of pointers to queue requests and responses.
+ *
+ * Memory is managed differently for a child process, which mallocs
+ * request buffers to read from the pipe into, whereas the threaded
+ * 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.
+ *
+ * Response memory allocation is also platform-dependent. With a
+ * separate process and pipes, the response is free()d after being
+ * written to the pipe. With threads, the same memory is handed
+ * over and the requestor frees it after processing is completed.
*
- * This is meant to be run by ntpd on the fly. It is not guaranteed
- * to work properly if run by hand. This is actually a quick hack to
- * stave off violence from people who hate using numbers in the
- * configuration file (at least I hope the rest of the daemon is
- * better than this). Also might provide some ideas about how one
- * might go about autoconfiguring an NTP distribution network.
+ * The code should be generalized to support threads on Unix using
+ * much of the same code used for Windows initially.
*
*/
-
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
-#include "ntp_intres.h"
+#include "ntp_workimpl.h"
-#ifndef NO_INTRES
+#ifdef WORKER
#include <stdio.h>
#include <ctype.h>
# include <netdb.h>
# endif
# include <resolv.h>
+# ifdef RES_TIMEOUT
+# undef RES_TIMEOUT /* resolv.h has one, we want ours */
+# endif
#endif
-#ifdef RES_TIMEOUT
-#undef RES_TIMEOUT /* resolv.h has one, we want ours */
-#endif
-
-#include "ntp_machine.h"
-#include "ntpd.h"
-#include "ntp_io.h"
-#include "ntp_request.h"
#include "ntp_stdlib.h"
+#include "ntp_malloc.h"
#include "ntp_syslog.h"
-#include "ntp_config.h"
-
-#include <isc/net.h>
-#include <isc/result.h>
-
-#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
-
-/*
- * Each item we are to resolve and configure gets one of these
- * structures defined for it.
- */
-struct conf_entry {
- struct conf_entry *ce_next;
- char *ce_name; /* name to resolve */
- struct conf_peer ce_config; /* config info for peer */
- int no_needed; /* number of addresses needed (pool) */
- /* no_needed isn't used yet: It's needed to fix bug-975 */
- int type; /* -4 and -6 flags */
- sockaddr_u peer_store; /* address info for both fams */
-};
-#define ce_peeraddr ce_config.peeraddr
-#define ce_peeraddr6 ce_config.peeraddr6
-#define ce_hmode ce_config.hmode
-#define ce_version ce_config.version
-#define ce_minpoll ce_config.minpoll
-#define ce_maxpoll ce_config.maxpoll
-#define ce_flags ce_config.flags
-#define ce_ttl ce_config.ttl
-#define ce_keyid ce_config.keyid
-#define ce_keystr ce_config.keystr
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_assert.h"
+#include "ntp_unixtime.h"
+#include "ntp_intres.h"
-/*
- * confentries is a pointer to the list of configuration entries
- * we have left to do.
- */
-static struct conf_entry *confentries = NULL;
/*
- * We take an interrupt every thirty seconds, at which time we decrement
- * config_timer and resolve_timer. The former is set to 2, so we retry
- * unsucessful reconfigurations every minute. The latter is set to
- * an exponentially increasing value which starts at 2 and increases to
- * 32. When this expires we retry failed name resolutions.
+ * 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()
*
- * We sleep SLEEPTIME seconds before doing anything, to give the server
- * time to arrange itself.
+ * 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.
*/
-#define MINRESOLVE 2
-#define MAXRESOLVE 32
-#define CONFIG_TIME 2
-#define ALARM_TIME 30
-#define SLEEPTIME 2
-static volatile int config_timer = 0;
-static volatile int resolve_timer = 0;
+#define INITIAL_DNS_RETRY 2 /* seconds between queries */
+
+typedef struct blocking_gai_req_tag {
+ size_t octets;
+ 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 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;
+ 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 */
+ size_t hostoctets;
+ size_t servoctets;
+ /*
+ * Followed by hostoctets bytes of null-terminated host,
+ * then servoctets bytes of null-terminated service.
+ */
+} blocking_gni_resp;
-static int resolve_value; /* next value of resolve timer */
+static time_t next_dns_timeslot;
+static time_t ignore_scheduled_before;
+#ifdef HAVE_RES_INIT
+static time_t next_res_init;
+#endif
-/*
- * Big hack attack
- */
-#define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */
+static void scheduled_sleep(time_t, time_t);
+static void manage_dns_retry_interval(time_t *, time_t *, int *);
+static int should_retry_dns(int, int);
+static void getaddrinfo_sometime_complete(blocking_work_req, void *,
+ size_t, void *);
+static void getnameinfo_sometime_complete(blocking_work_req, void *,
+ size_t, void *);
-/*
- * Select time out. Set to 2 seconds. The server is on the local machine,
- * after all.
- */
-#define TIMEOUT_SEC 2
-#define TIMEOUT_USEC 0
/*
- * Input processing. The data on each line in the configuration file
- * is supposed to consist of entries in the following order
+ * getaddrinfo_sometime - uses blocking child to call getaddrinfo then
+ * invokes provided callback completion function.
*/
-#define TOK_HOSTNAME 0
-#define TOK_NEEDED 1
-#define TOK_TYPE 2
-#define TOK_HMODE 3
-#define TOK_VERSION 4
-#define TOK_MINPOLL 5
-#define TOK_MAXPOLL 6
-#define TOK_FLAGS 7
-#define TOK_TTL 8
-#define TOK_KEYID 9
-#define TOK_KEYSTR 10
-#define NUMTOK 11
-
-#define MAXLINESIZE 512
-
+int
+getaddrinfo_sometime(
+ const char * node,
+ const char * service,
+ const struct addrinfo * hints,
+ gai_sometime_callback callback,
+ void * context
+ )
+{
+ blocking_gai_req * gai_req;
+ 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);
+ }
-/*
- * File descriptor for ntp request code.
- */
-static SOCKET sockfd = INVALID_SOCKET; /* NT uses SOCKET */
-
-/* stuff to be filled in by caller */
-
-keyid_t req_keyid; /* request keyid */
-int req_keytype; /* OpenSSL NID such as NID_md5 */
-size_t req_hashlen; /* digest size for req_keytype */
-char *req_file; /* name of the file with configuration info */
-
-/* end stuff to be filled in */
-
-
-static void checkparent (void);
-static struct conf_entry *
- removeentry (struct conf_entry *);
-static void addentry (char *, int, int, int, int, int, int, u_int,
- int, keyid_t, char *);
-static int findhostaddr (struct conf_entry *);
-static void openntp (void);
-static int request (struct conf_peer *);
-static char * nexttoken (char **);
-static void readconf (FILE *, char *);
-static void doconfigure (int);
-
-struct ntp_res_t_pkt { /* Tagged packet: */
- void *tag; /* For the caller */
- u_int32 paddr; /* IP to look up, or 0 */
- char name[MAXHOSTNAMELEN]; /* Name to look up (if 1st byte is not 0) */
-};
-
-struct ntp_res_c_pkt { /* Control packet: */
- char name[MAXHOSTNAMELEN];
- u_int32 paddr;
- int mode;
- int version;
- int minpoll;
- int maxpoll;
- u_int flags;
- int ttl;
- keyid_t keyid;
- u_char keystr[MAXFILENAME];
-};
-
-
-static void resolver_exit (int);
+ nodesize = strlen(node) + 1;
+ servsize = strlen(service) + 1;
+ req_size = sizeof(*gai_req) + nodesize + servsize;
+
+ gai_req = emalloc(req_size);
+
+ gai_req->octets = req_size;
+ now = time(NULL);
+ next_dns_timeslot = max(now, next_dns_timeslot);
+ gai_req->scheduled = now;
+ gai_req->earliest = next_dns_timeslot;
+ gai_req->hints = *hints;
+ gai_req->retry = INITIAL_DNS_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;
+ }
-/*
- * Call here instead of just exiting
- */
+ return 0;
+}
-static void resolver_exit (int code)
+int
+blocking_getaddrinfo(
+ blocking_pipe_header * req
+ )
{
-#ifdef SYS_WINNT
- CloseHandle(ResolverEventHandle);
- ResolverEventHandle = NULL;
- _endthreadex(code); /* Just to kill the thread not the process */
-#else
- exit(code); /* kill the forked process */
+ blocking_gai_req * gai_req;
+ 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;
+
+ scheduled_sleep(gai_req->scheduled, gai_req->earliest);
+
+#ifdef HAVE_RES_INIT
+ /*
+ * This is ad-hoc. Reload /etc/resolv.conf once per minute
+ * to pick up on changes from the DHCP client. [Bug 1226]
+ */
+ time_now = time(NULL);
+ if (next_res_init <= time_now) {
+ if (next_res_init)
+ res_init();
+ next_res_init = time_now + 60;
+ }
#endif
-}
-/*
- * ntp_res_recv: Process an answer from the resolver
- */
-
-void
-ntp_res_recv(void)
-{
/*
- We have data ready on our descriptor.
- It may be an EOF, meaning the resolver process went away.
- Otherwise, it will be an "answer".
- */
-}
+ * Take a shot at the final size, better to overestimate
+ * at first and then realloc to a smaller size.
+ */
+ resp = emalloc(sizeof(*resp) + sizeof(*gai_resp)
+ + 16 * (sizeof(struct addrinfo)
+ + sizeof(sockaddr_u))
+ + 256);
+ gai_resp = (void *)(resp + 1);
-/*
- * ntp_intres needs;
- *
- * req_key(???), req_keyid, req_file valid
- * syslog still open
- */
+ DPRINTF(2, ("blocking_getaddrinfo given node %s serv %s fam %d flags %x\n",
+ node, service, gai_req->hints.ai_family,
+ gai_req->hints.ai_flags));
+
+ ai_res = NULL;
+ gai_resp->retcode = getaddrinfo(node, service, &gai_req->hints, &ai_res);
-void
-ntp_intres(void)
-{
- FILE *in;
-#ifdef SYS_WINNT
- DWORD rc;
-#else
- int rc;
- struct timeval tv;
- fd_set fdset;
- int time_left;
+ switch (gai_resp->retcode) {
+#ifdef EAI_SYSTEM
+ case EAI_SYSTEM:
+ gai_resp->gai_errno = errno;
+ break;
#endif
-
-#ifdef DEBUG
- if (debug > 1) {
- msyslog(LOG_INFO, "NTP_INTRES running");
+ default:
+ gai_resp->gai_errno = 0;
}
-#endif
- /* check out auth stuff */
- if (sys_authenticate) {
- if (!authistrusted(req_keyid)) {
- msyslog(LOG_ERR, "invalid request keyid %08x",
- req_keyid );
- resolver_exit(1);
+ gai_resp->ai_count = canons_octets = 0;
+
+ if (!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_req->retry > INITIAL_DNS_RETRY) {
+ time_now = time(NULL);
+ ignore_scheduled_before = time_now;
+ next_dns_timeslot = time_now;
+ DPRINTF(1, ("DNS success after retry, ignoring sleeps scheduled before now (%s)",
+ humantime(time_now)));
}
}
/*
- * Read the configuration info
- * {this is bogus, since we are forked, but it is easier
- * to keep this code - gdt}
+ * Our response consists of a header, followed by ai_count
+ * addrinfo structs followed by ai_count sockaddr_storage
+ * structs followed by the canonical names.
*/
- if ((in = fopen(req_file, "r")) == NULL) {
- msyslog(LOG_ERR, "can't open configuration file %s: %m",
- req_file);
- resolver_exit(1);
- }
- readconf(in, req_file);
- (void) fclose(in);
+ gai_resp->octets = sizeof(*gai_resp)
+ + gai_resp->ai_count
+ * (sizeof(gai_req->hints)
+ + sizeof(sockaddr_u))
+ + canons_octets;
-#ifdef DEBUG
- if (!debug)
-#endif
- if (unlink(req_file))
- msyslog(LOG_WARNING,
- "unable to remove intres request file %s, %m",
- req_file);
+ resp_octets = sizeof(*resp) + gai_resp->octets;
+ resp = erealloc(resp, resp_octets);
+ gai_resp = (void *)(resp + 1);
- /*
- * Set up the timers to do first shot immediately.
- */
- resolve_timer = 0;
- resolve_value = MINRESOLVE;
- config_timer = CONFIG_TIME;
-
- for (;;) {
- checkparent();
-
- if (resolve_timer == 0) {
- /*
- * Sleep a little to make sure the network is completely up
- */
- sleep(SLEEPTIME);
- doconfigure(1);
-
- /* prepare retry, in case there's more work to do */
- resolve_timer = resolve_value;
-#ifdef DEBUG
- if (debug > 2)
- msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer);
-#endif
- if (resolve_value < MAXRESOLVE)
- resolve_value <<= 1;
-
- config_timer = CONFIG_TIME;
- } else if (config_timer == 0) { /* MB: in which case would this be required ? */
- doconfigure(0);
- /* MB: should we check now if we could exit, similar to the code above? */
- config_timer = CONFIG_TIME;
-#ifdef DEBUG
- if (debug > 2)
- msyslog(LOG_INFO, "config_timer: 0->%d", config_timer);
-#endif
- }
+ /* cp serves as our current pointer while serializing */
+ cp = (void *)(gai_resp + 1);
+ canons_octets = 0;
+
+ if (!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 */
- if (confentries == NULL)
- resolver_exit(0); /* done */
+ ai = ai->ai_next;
+ }
-#ifdef SYS_WINNT
- rc = WaitForSingleObject(ResolverEventHandle, 1000 * ALARM_TIME); /* in milliseconds */
+ 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);
- if ( rc == WAIT_OBJECT_0 ) { /* signaled by the main thread */
- resolve_timer = 0; /* retry resolving immediately */
- continue;
+ ai = ai->ai_next;
}
- if ( rc != WAIT_TIMEOUT ) /* not timeout: error */
- resolver_exit(1);
-
-#else /* not SYS_WINNT */
- /* Bug 1386: fork() in NetBSD leaves timers running. */
- /* So we need to retry select on EINTR */
- time_left = ALARM_TIME;
- while (time_left > 0) {
- tv.tv_sec = time_left;
- tv.tv_usec = 0;
- FD_ZERO(&fdset);
- FD_SET(resolver_pipe_fd[0], &fdset);
- rc = select(resolver_pipe_fd[0] + 1, &fdset, (fd_set *)0, (fd_set *)0, &tv);
-
- if (rc == 0) /* normal timeout */
- break;
-
- if (rc > 0) { /* parent process has written to the pipe */
- read(resolver_pipe_fd[0], (char *)&rc, sizeof(rc)); /* make pipe empty */
- resolve_timer = 0; /* retry resolving immediately */
- break;
- }
-
- if ( rc < 0 ) { /* select() returned error */
- if (errno == EINTR) { /* Timer went off */
- time_left -= (1<<EVENT_TIMEOUT);
- continue; /* try again */
+ 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;
}
- msyslog(LOG_ERR, "ntp_intres: Error from select: %s",
- strerror(errno));
- resolver_exit(1);
- }
- }
-#endif
- /* normal timeout, keep on waiting */
- if (config_timer > 0)
- config_timer--;
- if (resolve_timer > 0)
- resolve_timer--;
+ ai = ai->ai_next;
+ }
}
-}
+ /*
+ * make sure our walk and earlier calc match
+ */
+ NTP_INSIST((size_t)(cp - (char *)resp) == resp_octets);
-#ifdef SYS_WINNT
-/*
- * ntp_intres_thread wraps the slightly different interface of Windows
- * thread functions and ntp_intres
- */
-unsigned WINAPI
-ntp_intres_thread(void *UnusedThreadArg)
-{
- UNUSED_ARG(UnusedThreadArg);
+ if (queue_blocking_response(resp, resp_octets, req)) {
+ DPRINTF(1, ("blocking_getaddrinfo unable to queue response"));
+ return -1;
+ }
- ntp_intres();
return 0;
}
-#endif /* SYS_WINNT */
-
-/*
- * checkparent - see if our parent process is still running
- *
- * No need to worry in the Windows NT environment whether the
- * main thread is still running, because if it goes
- * down it takes the whole process down with it (in
- * which case we won't be running this thread either)
- * Turn function into NOP;
- */
static void
-checkparent(void)
+getaddrinfo_sometime_complete(
+ blocking_work_req rtype,
+ void * context,
+ size_t respsize,
+ void * resp
+ )
{
-#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS)
+ blocking_gai_req * gai_req;
+ blocking_gai_resp * gai_resp;
+ struct addrinfo * ai;
+ struct addrinfo * next_ai;
+ sockaddr_u * psau;
+ char * node;
+ char * service;
+ char * canon_start;
+ int again;
+ int af;
+ const char * fam_spec;
+ int i;
+
+ gai_req = context;
+ gai_resp = resp;
+
+ NTP_REQUIRE(BLOCKING_GETADDRINFO == rtype);
+ NTP_REQUIRE(respsize == gai_resp->octets);
+
+ node = (char *)gai_req + sizeof(*gai_req);
+ service = node + gai_req->nodesize;
+
+ if (gai_resp->retcode) {
+ again = should_retry_dns(gai_resp->retcode, gai_resp->gai_errno);
+ /*
+ * exponential backoff of DNS retries to 64s
+ */
+ if (gai_req->retry && 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)
+ msyslog(LOG_INFO,
+ "retrying DNS %s%s: EAI_SYSTEM %s (%d)",
+ node, fam_spec,
+ strerror(gai_resp->gai_errno),
+ 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);
+ 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);
+ }
+ }
/*
- * If our parent (the server) has died we will have been
- * inherited by init. If so, exit.
+ * fixup pointers in returned addrinfo array
*/
- if (getppid() == 1) {
- msyslog(LOG_INFO, "parent died before we finished, exiting");
- resolver_exit(0);
+ 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];
}
-#endif /* SYS_WINNT && SYS_VXWORKS*/
-}
-
+ psau = (void *)((char *)ai + gai_resp->ai_count * sizeof(*ai));
+ canon_start = (char *)psau + gai_resp->ai_count * sizeof(*psau);
-/*
- * removeentry - we are done with an entry, remove it from the list
- */
-static struct conf_entry *
-removeentry(
- struct conf_entry *entry
- )
-{
- register struct conf_entry *ce;
- struct conf_entry *next_ce;
+ 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;
+ }
- ce = confentries;
- if (ce == entry)
- confentries = ce->ce_next;
- else
- while (ce != NULL) {
- if (ce->ce_next == entry) {
- ce->ce_next = entry->ce_next;
- break;
- }
- ce = ce->ce_next;
- }
+ NTP_ENSURE((char *)psau == canon_start);
- next_ce = entry->ce_next;
- if (entry->ce_name != NULL)
- free(entry->ce_name);
- free(entry);
+ 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);
- return next_ce;
+ free(gai_req);
+ /* gai_resp is part of block freed by process_blocking_response() */
}
-/*
- * addentry - add an entry to the configuration list
- */
-static void
-addentry(
- char *name,
- int no_needed,
- int type,
- int mode,
- int version,
- int minpoll,
- int maxpoll,
- u_int flags,
- int ttl,
- keyid_t keyid,
- char *keystr
- )
+#ifdef TEST_BLOCKING_WORKER
+void gai_test_callback(int rescode, int gai_errno, void *context, const char *name, const char *service, const struct addrinfo *hints, const struct addrinfo *ai_res)
{
- register struct conf_entry *ce;
-
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "intres: <%s> %d %d %d %d %d %d %x %d %x %s",
- name, no_needed, type, mode, version,
- minpoll, maxpoll, flags, ttl, keyid, keystr);
-#endif
- ce = emalloc(sizeof(*ce));
- ce->ce_name = estrdup(name);
- ce->ce_peeraddr = 0;
-#ifdef ISC_PLATFORM_HAVEIPV6
- ce->ce_peeraddr6 = in6addr_any;
-#endif
- ZERO_SOCK(&ce->peer_store);
- ce->ce_hmode = (u_char)mode;
- ce->ce_version = (u_char)version;
- ce->ce_minpoll = (u_char)minpoll;
- ce->ce_maxpoll = (u_char)maxpoll;
- ce->no_needed = no_needed; /* Not used after here. */
- /* Start of fixing bug-975 */
- ce->type = type;
- ce->ce_flags = (u_char)flags;
- ce->ce_ttl = (u_char)ttl;
- ce->ce_keyid = keyid;
- strncpy(ce->ce_keystr, keystr, sizeof(ce->ce_keystr) - 1);
- ce->ce_keystr[sizeof(ce->ce_keystr) - 1] = 0;
- ce->ce_next = NULL;
-
- if (confentries == NULL) {
- confentries = ce;
- } else {
- register struct conf_entry *cep;
+ sockaddr_u addr;
- for (cep = confentries; cep->ce_next != NULL;
- cep = cep->ce_next)
- /* nothing */;
- cep->ce_next = ce;
+ if (rescode) {
+ DPRINTF(1, ("gai_test_callback context %p error rescode %d %s serv %s\n",
+ context, rescode, name, service));
+ return;
+ }
+ while (!rescode && NULL != ai_res) {
+ ZERO_SOCK(&addr);
+ memcpy(&addr, ai_res->ai_addr, ai_res->ai_addrlen);
+ DPRINTF(1, ("ctx %p fam %d addr %s canon '%s' type %s at %p ai_addr %p ai_next %p\n",
+ context,
+ AF(&addr),
+ stoa(&addr),
+ (ai_res->ai_canonname)
+ ? ai_res->ai_canonname
+ : "",
+ (SOCK_DGRAM == ai_res->ai_socktype)
+ ? "DGRAM"
+ : (SOCK_STREAM == ai_res->ai_socktype)
+ ? "STREAM"
+ : "(other)",
+ ai_res,
+ ai_res->ai_addr,
+ ai_res->ai_next));
+
+ getnameinfo_sometime((sockaddr_u *)ai_res->ai_addr, 128, 32, 0, gni_test_callback, context);
+
+ ai_res = ai_res->ai_next;
}
}
+#endif /* TEST_BLOCKING_WORKER */
-/*
- * findhostaddr - resolve a host name into an address (Or vice-versa)
- *
- * Given one of {ce_peeraddr,ce_name}, find the other one.
- * It returns 1 for "success" and 0 for an uncorrectable failure.
- * Note that "success" includes try again errors. You can tell that you
- * got a "try again" since {ce_peeraddr,ce_name} will still be zero.
- */
-static int
-findhostaddr(
- struct conf_entry *entry
+int
+getnameinfo_sometime(
+ sockaddr_u * psau,
+ size_t hostoctets,
+ size_t servoctets,
+ int flags,
+ gni_sometime_callback callback,
+ void * context
)
{
- static int eai_again_seen = 0;
- struct addrinfo *addr;
- struct addrinfo hints;
- int again;
- int error;
-
- checkparent(); /* make sure our guy is still running */
-
- if (entry->ce_name != NULL && !SOCK_UNSPEC(&entry->peer_store)) {
- /* HMS: Squawk? */
- msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined...");
- return 1;
- }
-
- if (entry->ce_name == NULL && SOCK_UNSPEC(&entry->peer_store)) {
- msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!");
- return 0;
- }
-
- if (entry->ce_name) {
- DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
- entry->ce_name));
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = entry->type;
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_protocol = IPPROTO_UDP;
- /*
- * If IPv6 is not available look only for v4 addresses
- */
- if (!ipv6_works)
- hints.ai_family = AF_INET;
- error = getaddrinfo(entry->ce_name, NULL, &hints, &addr);
- if (error == 0) {
- entry->peer_store = *((sockaddr_u *)(addr->ai_addr));
- if (IS_IPV4(&entry->peer_store)) {
- entry->ce_peeraddr =
- NSRCADR(&entry->peer_store);
- entry->ce_config.v6_flag = 0;
- } else {
- entry->ce_peeraddr6 =
- SOCK_ADDR6(&entry->peer_store);
- entry->ce_config.v6_flag = 1;
- }
- freeaddrinfo(addr);
- }
- } else {
- DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
- stoa(&entry->peer_store)));
-
- entry->ce_name = emalloc(MAXHOSTNAMELEN);
- error = getnameinfo((const struct sockaddr *)&entry->peer_store,
- SOCKLEN(&entry->peer_store),
- (char *)&entry->ce_name, MAXHOSTNAMELEN,
- NULL, 0, 0);
- }
-
- if (0 == error) {
-
- /* again is our return value, for success it is 1 */
- again = 1;
-
- DPRINTF(2, ("findhostaddr: %s resolved.\n",
- (entry->ce_name) ? "name" : "address"));
- } else {
- /*
- * If the resolver failed, see if the failure is
- * temporary. If so, return success.
- */
- again = 0;
-
- switch (error) {
-
- case EAI_FAIL:
- again = 1;
- break;
-
- case EAI_AGAIN:
- again = 1;
- eai_again_seen = 1;
- break;
-
- case EAI_NONAME:
-#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
- case EAI_NODATA:
-#endif
- msyslog(LOG_ERR, "host name not found%s%s: %s",
- (EAI_NONAME == error) ? "" : " EAI_NODATA",
- (eai_again_seen) ? " (permanent)" : "",
- entry->ce_name);
- again = !eai_again_seen;
- 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 = 1;
- DPRINTF(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n",
- errno, strerror(errno)));
- break;
-#endif
- }
-
- /* do this here to avoid perturbing errno earlier */
- DPRINTF(2, ("intres: got error status of: %d\n", error));
+ blocking_gni_req * gni_req;
+ time_t time_now;
+
+ NTP_REQUIRE(hostoctets);
+ NTP_REQUIRE(hostoctets + servoctets < 1024);
+
+ gni_req = emalloc(sizeof(*gni_req));
+ memset(gni_req, 0, sizeof(*gni_req));
+
+ gni_req->octets = sizeof(*gni_req);
+ time_now = time(NULL);
+ next_dns_timeslot = max(time_now, next_dns_timeslot);
+ gni_req->scheduled = time_now;
+ gni_req->earliest = next_dns_timeslot;
+ 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 again;
+ return 0;
}
-/*
- * openntp - open a socket to the ntp server
- */
-static void
-openntp(void)
+int
+blocking_getnameinfo(
+ blocking_pipe_header * req
+ )
{
- const char *localhost = "127.0.0.1"; /* Use IPv4 loopback */
- struct addrinfo hints;
- struct addrinfo *addr;
- u_long on;
- int err;
+ blocking_gni_req * gni_req;
+ blocking_pipe_header * resp;
+ blocking_gni_resp * gni_resp;
+ size_t octets;
+ size_t resp_octets;
+ char * host;
+ char * service;
+ char * cp;
+ int rc;
+ time_t time_now;
- if (sockfd != INVALID_SOCKET)
- return;
+ gni_req = (void *)((char *)req + sizeof(*req));
- memset(&hints, 0, sizeof(hints));
+ octets = gni_req->hostoctets + gni_req->servoctets;
/*
- * For now only bother with IPv4
+ * Some alloca() implementations are fragile regarding
+ * large allocations. We only need room for the host
+ * and service names.
*/
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_DGRAM;
+ NTP_REQUIRE(octets < 1024);
- err = getaddrinfo(localhost, "ntp", &hints, &addr);
-
- if (err) {
-#ifdef EAI_SYSTEM
- if (EAI_SYSTEM == err)
- msyslog(LOG_ERR, "getaddrinfo(%s) failed: %m",
- localhost);
- else
-#endif
- msyslog(LOG_ERR, "getaddrinfo(%s) failed: %s",
- localhost, gai_strerror(err));
- resolver_exit(1);
+#ifndef HAVE_ALLOCA
+ host = emalloc(octets);
+#else
+ host = alloca(octets);
+ if (NULL == host) {
+ msyslog(LOG_ERR,
+ "blocking_getnameinfo unable to allocate %d octets on stack",
+ octets);
+ exit(1);
}
+#endif
+ service = host + gni_req->hostoctets;
- sockfd = socket(addr->ai_family, addr->ai_socktype, 0);
-
- if (INVALID_SOCKET == sockfd) {
- msyslog(LOG_ERR, "socket() failed: %m");
- resolver_exit(1);
- }
+ scheduled_sleep(gni_req->scheduled, gni_req->earliest);
-#ifndef SYS_WINNT
+#ifdef HAVE_RES_INIT
/*
- * On Windows only the count of sockets must be less than
- * FD_SETSIZE. On Unix each descriptor's value must be less
- * than FD_SETSIZE, as fd_set is a bit array.
+ * This is ad-hoc. Reload /etc/resolv.conf once per minute
+ * to pick up on changes from the DHCP client. [Bug 1226]
*/
- if (sockfd >= FD_SETSIZE) {
- msyslog(LOG_ERR, "socket fd %d too large, FD_SETSIZE %d",
- (int)sockfd, FD_SETSIZE);
- resolver_exit(1);
+ time_now = time(NULL);
+ if (next_res_init <= time_now) {
+ if (next_res_init)
+ res_init();
+ next_res_init = time_now + 60;
}
+#endif
/*
- * Make the socket non-blocking. We'll wait with select()
- * Unix: fcntl(O_NONBLOCK) or fcntl(FNDELAY)
- */
-# ifdef O_NONBLOCK
- if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {
- msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m");
- resolver_exit(1);
- }
-# else
-# ifdef FNDELAY
- if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) {
- msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m");
- resolver_exit(1);
- }
-# else
-# include "Bletch: NEED NON BLOCKING IO"
-# endif /* FNDDELAY */
-# endif /* O_NONBLOCK */
- (void)on; /* quiet unused warning */
-#else /* !SYS_WINNT above */
- /*
- * Make the socket non-blocking. We'll wait with select()
- * Windows: ioctlsocket(FIONBIO)
+ * Take a shot at the final size, better to overestimate
+ * then realloc to a smaller size.
*/
- on = 1;
- err = ioctlsocket(sockfd, FIONBIO, &on);
- if (SOCKET_ERROR == err) {
- msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
- resolver_exit(1);
- }
-#endif /* SYS_WINNT */
-
- err = connect(sockfd, addr->ai_addr, addr->ai_addrlen);
- if (SOCKET_ERROR == err) {
- msyslog(LOG_ERR, "openntp: connect() failed: %m");
- resolver_exit(1);
- }
-
- freeaddrinfo(addr);
-}
+ resp_octets = sizeof(*resp) + sizeof(*gni_resp) + octets;
+ resp = emalloc(resp_octets);
+ gni_resp = (void *)((char *)resp + sizeof(*resp));
-/*
- * request - send a configuration request to the server, wait for a response
- */
-static int
-request(
- struct conf_peer *conf
- )
-{
- struct sock_timeval tvout;
- struct req_pkt reqpkt;
- size_t req_len;
- size_t total_len; /* req_len plus keyid & digest */
- fd_set fdset;
- l_fp ts;
- char * pch;
- char * pchEnd;
- l_fp * pts;
- keyid_t *pkeyid;
- int n;
-#ifdef SYS_WINNT
- HANDLE hReadWriteEvent = NULL;
- BOOL ret;
- DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait;
- OVERLAPPED overlap;
-#endif /* SYS_WINNT */
-
- checkparent(); /* make sure our guy is still running */
-
- if (sockfd == INVALID_SOCKET)
- openntp();
+ DPRINTF(2, ("blocking_getnameinfo given addr %s flags 0x%x hostlen %d servlen %d\n",
+ stoa(&gni_req->socku), gni_req->flags,
+ gni_req->hostoctets, gni_req->servoctets));
-#ifdef SYS_WINNT
- hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-#endif /* SYS_WINNT */
-
- /*
- * Try to clear out any previously received traffic so it
- * doesn't fool us. Note the socket is nonblocking.
- */
- tvout.tv_sec = 0;
- tvout.tv_usec = 0;
- FD_ZERO(&fdset);
- FD_SET(sockfd, &fdset);
- while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) >
- 0) {
- recv(sockfd, (char *)&reqpkt, sizeof(reqpkt), 0);
- FD_ZERO(&fdset);
- FD_SET(sockfd, &fdset);
+ gni_resp->retcode = getnameinfo(&gni_req->socku.sa,
+ SOCKLEN(&gni_req->socku),
+ host,
+ gni_req->hostoctets,
+ service,
+ gni_req->servoctets,
+ gni_req->flags);
+
+ switch (gni_resp->retcode) {
+#ifdef EAI_SYSTEM
+ case EAI_SYSTEM:
+ gni_resp->gni_errno = errno;
+ break;
+#endif
+ default:
+ gni_resp->gni_errno = 0;
}
- /*
- * Make up a request packet with the configuration info
- */
- memset(&reqpkt, 0, sizeof(reqpkt));
-
- reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
- reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */
- reqpkt.implementation = IMPL_XNTPD; /* local implementation */
- reqpkt.request = REQ_CONFIG; /* configure a new peer */
- reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */
- reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(*conf));
- /* Make sure mbz_itemsize <= sizeof reqpkt.data */
- if (sizeof(*conf) > sizeof(reqpkt.data)) {
- msyslog(LOG_ERR,
- "Bletch: conf_peer is too big for reqpkt.data!");
- resolver_exit(1);
- }
- memcpy(reqpkt.data, conf, sizeof(*conf));
-
- if (sys_authenticate && req_hashlen > 16) {
- pch = reqpkt.data;
- /* 32-bit alignment */
- pch += (sizeof(*conf) + 3) & ~3;
- pts = (void *)pch;
- pkeyid = (void *)(pts + 1);
- pchEnd = (void *)pkeyid;
- req_len = pchEnd - (char *)&reqpkt;
- pchEnd = (void *)(pkeyid + 1);
- pchEnd += req_hashlen;
- total_len = pchEnd - (char *)&reqpkt;
- if (total_len > sizeof(reqpkt)) {
- msyslog(LOG_ERR,
- "intres total_len %u limit is %u (%u octet digest)\n",
- total_len, sizeof(reqpkt),
- req_hashlen);
- resolver_exit(1);
- }
+ if (gni_resp->retcode) {
+ gni_resp->hostoctets = 0;
+ gni_resp->servoctets = 0;
} else {
- pts = &reqpkt.tstamp;
- pkeyid = &reqpkt.keyid;
- req_len = REQ_LEN_NOMAC;
- }
-
- *pkeyid = htonl(req_keyid);
- get_systime(&ts);
- L_ADDUF(&ts, SKEWTIME);
- HTONL_FP(&ts, pts);
- if (sys_authenticate) {
- n = authencrypt(req_keyid, (void *)&reqpkt, req_len);
- if ((size_t)n != req_hashlen + sizeof(reqpkt.keyid)) {
- msyslog(LOG_ERR,
- "intres maclen %d expected %u\n",
- n, req_hashlen + sizeof(reqpkt.keyid));
- resolver_exit(1);
+ 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);
+ ignore_scheduled_before = time_now;
+ next_dns_timeslot = time_now;
+ DPRINTF(1, ("DNS success after retrying, ignoring sleeps scheduled before now (%s)",
+ humantime(time_now)));
}
- req_len += n;
}
-
+ octets = gni_resp->hostoctets + gni_resp->servoctets;
/*
- * Done. Send it.
+ * Our response consists of a header, followed by the host and
+ * service strings, each null-terminated.
*/
-#ifndef SYS_WINNT
- n = send(sockfd, (char *)&reqpkt, req_len, 0);
- if (n < 0) {
- msyslog(LOG_ERR, "send to NTP server failed: %m");
- return 0; /* maybe should exit */
- }
-#else
- /* In the NT world, documentation seems to indicate that there
- * exist _write and _read routines that can be used to do blocking
- * I/O on sockets. Problem is these routines require a socket
- * handle obtained through the _open_osf_handle C run-time API
- * of which there is no explanation in the documentation. We need
- * nonblocking write's and read's anyway for our purpose here.
- * We're therefore forced to deviate a little bit from the Unix
- * model here and use the ReadFile and WriteFile Win32 I/O API's
- * on the socket
- */
- overlap.Offset = overlap.OffsetHigh = (DWORD)0;
- overlap.hEvent = hReadWriteEvent;
- ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, req_len,
- NULL, (LPOVERLAPPED)&overlap);
- if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
- msyslog(LOG_ERR, "send to NTP server failed: %m");
- return 0;
- }
- dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
- if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
- if (dwWait == WAIT_FAILED)
- msyslog(LOG_ERR, "WaitForSingleObject failed: %m");
- return 0;
- }
- if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap,
- (LPDWORD)&NumberOfBytesWritten, FALSE)) {
- msyslog(LOG_ERR, "GetOverlappedResult for WriteFile fails: %m");
- return 0;
- }
-#endif /* SYS_WINNT */
+ resp_octets = sizeof(*resp) + sizeof(*gni_resp) + octets;
+ resp = erealloc(resp, resp_octets);
+ gni_resp = (void *)(resp + 1);
- /*
- * Wait for a response. A weakness of the mode 7 protocol used
- * is that there is no way to associate a response with a
- * particular request, i.e. the response to this configuration
- * request is indistinguishable from that to any other. I should
- * fix this some day. In any event, the time out is fairly
- * pessimistic to make sure that if an answer is coming back
- * at all, we get it.
- */
- for (;;) {
- FD_ZERO(&fdset);
- FD_SET(sockfd, &fdset);
- tvout.tv_sec = TIMEOUT_SEC;
- tvout.tv_usec = TIMEOUT_USEC;
-
- n = select(sockfd + 1, &fdset, (fd_set *)0,
- (fd_set *)0, &tvout);
-
- if (n < 0) {
- if (errno != EINTR)
- msyslog(LOG_ERR, "select() fails: %m");
- return 0;
- } else if (n == 0) {
-#ifdef DEBUG
- if (debug)
- msyslog(LOG_INFO, "ntp_intres select() returned 0.");
-#endif
- return 0;
- }
+ gni_resp->octets = sizeof(*gni_resp) + octets;
-#ifndef SYS_WINNT
- n = recv(sockfd, (char *)&reqpkt, sizeof(reqpkt), 0);
- if (n <= 0) {
- if (n < 0) {
- msyslog(LOG_ERR, "recv() fails: %m");
- return 0;
- }
- continue;
- }
-#else /* Overlapped I/O used on non-blocking sockets on Windows NT */
- ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, sizeof(reqpkt),
- NULL, (LPOVERLAPPED)&overlap);
- if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
- msyslog(LOG_ERR, "ReadFile() fails: %m");
- return 0;
- }
- dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
- if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
- if (dwWait == WAIT_FAILED) {
- msyslog(LOG_ERR, "WaitForSingleObject for ReadFile fails: %m");
- return 0;
- }
- continue;
- }
- if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap,
- (LPDWORD)&NumberOfBytesRead, FALSE)) {
- msyslog(LOG_ERR, "GetOverlappedResult fails: %m");
- return 0;
- }
- n = NumberOfBytesRead;
-#endif /* SYS_WINNT */
+ /* cp serves as our current pointer while serializing */
+ cp = (void *)(gni_resp + 1);
- /*
- * Got one. Check through to make sure it is what
- * we expect.
- */
- if (n < RESP_HEADER_SIZE) {
- msyslog(LOG_ERR, "received runt response (%d octets)",
- n);
- continue;
- }
+ if (!gni_resp->retcode) {
+ memcpy(cp, host, gni_resp->hostoctets);
+ cp += gni_resp->hostoctets;
+ memcpy(cp, service, gni_resp->servoctets);
+ cp += gni_resp->servoctets;
+ }
- if (!ISRESPONSE(reqpkt.rm_vn_mode)) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO, "received non-response packet");
-#endif
- continue;
- }
+ NTP_INSIST((size_t)(cp - (char *)resp) == resp_octets);
+ NTP_INSIST(resp_octets - sizeof(*resp) == gni_resp->octets);
- if (ISMORE(reqpkt.rm_vn_mode)) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO, "received fragmented packet");
+ rc = queue_blocking_response(resp, resp_octets, req);
+ if (rc)
+ msyslog(LOG_ERR, "blocking_getnameinfo unable to queue response");
+#ifndef HAVE_ALLOCA
+ free(host);
#endif
- continue;
- }
+ return rc;
+}
- if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2)
- || (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION))
- || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "version (%d/%d) or mode (%d/%d) incorrect",
- INFO_VERSION(reqpkt.rm_vn_mode),
- NTP_VERSION,
- INFO_MODE(reqpkt.rm_vn_mode),
- MODE_PRIVATE);
-#endif
- continue;
- }
- if (INFO_SEQ(reqpkt.auth_seq) != 0) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "nonzero sequence number (%d)",
- INFO_SEQ(reqpkt.auth_seq));
-#endif
- continue;
- }
+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;
+ char * host;
+ char * service;
+ int again;
- if (reqpkt.implementation != IMPL_XNTPD ||
- reqpkt.request != REQ_CONFIG) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "implementation (%d) or request (%d) incorrect",
- reqpkt.implementation, reqpkt.request);
-#endif
- continue;
- }
+ gni_req = context;
+ gni_resp = resp;
- if (INFO_NITEMS(reqpkt.err_nitems) != 0 ||
- INFO_MBZ(reqpkt.mbz_itemsize) != 0 ||
- INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "nitems (%d) mbz (%d) or itemsize (%d) nonzero",
- INFO_NITEMS(reqpkt.err_nitems),
- INFO_MBZ(reqpkt.mbz_itemsize),
- INFO_ITEMSIZE(reqpkt.mbz_itemsize));
-#endif
- continue;
- }
+ NTP_REQUIRE(BLOCKING_GETNAMEINFO == rtype);
+ NTP_REQUIRE(respsize == gni_resp->octets);
- n = INFO_ERR(reqpkt.err_nitems);
- switch (n) {
- case INFO_OKAY:
- /* success */
- return 1;
-
- case INFO_ERR_NODATA:
- /*
- * newpeer() refused duplicate association, no
- * point in retrying so call it success.
- */
- return 1;
-
- case INFO_ERR_IMPL:
- msyslog(LOG_ERR,
- "ntp_intres.request: implementation mismatch");
- return 0;
-
- case INFO_ERR_REQ:
- msyslog(LOG_ERR,
- "ntp_intres.request: request unknown");
- return 0;
-
- case INFO_ERR_FMT:
- msyslog(LOG_ERR,
- "ntp_intres.request: format error");
- return 0;
-
- case INFO_ERR_AUTH:
- msyslog(LOG_ERR,
- "ntp_intres.request: permission denied");
- return 0;
-
- default:
- msyslog(LOG_ERR,
- "ntp_intres.request: unknown error code %d", n);
- return 0;
+ if (gni_resp->retcode) {
+ again = should_retry_dns(gni_resp->retcode, gni_resp->gni_errno);
+ /*
+ * exponential backoff of DNS retries to 64s
+ */
+ if (gni_req->retry)
+ manage_dns_retry_interval(&gni_req->scheduled,
+ &gni_req->earliest, &gni_req->retry);
+
+ if (gni_req->retry && 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", stoa(&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;
+ }
-/*
- * nexttoken - return the next token from a line
- */
-static char *
-nexttoken(
- char **lptr
- )
-{
- register char *cp;
- register char *tstart;
+ (*gni_req->callback)(gni_resp->retcode, gni_resp->gni_errno,
+ &gni_req->socku, gni_req->flags, host,
+ service, gni_req->context);
- cp = *lptr;
+ free(gni_req);
+ /* gni_resp is part of block freed by process_blocking_response() */
+}
- /*
- * Skip leading white space
- */
- while (*cp == ' ' || *cp == '\t')
- cp++;
-
- /*
- * If this is the end of the line, return nothing.
- */
- if (*cp == '\n' || *cp == '\0') {
- *lptr = cp;
- return NULL;
- }
-
- /*
- * Must be the start of a token. Record the pointer and look
- * for the end.
- */
- tstart = cp++;
- while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0')
- cp++;
-
- /*
- * Terminate the token with a \0. If this isn't the end of the
- * line, space to the next character.
- */
- if (*cp == '\n' || *cp == '\0')
- *cp = '\0';
- else
- *cp++ = '\0';
- *lptr = cp;
- return tstart;
+#ifdef TEST_BLOCKING_WORKER
+void gni_test_callback(int rescode, int gni_errno, sockaddr_u *psau, int flags, const char *host, const char *service, void *context)
+{
+ if (!rescode)
+ DPRINTF(1, ("gni_test_callback got host '%s' serv '%s' for addr %s context %p\n",
+ host, service, stoa(psau), context));
+ else
+ DPRINTF(1, ("gni_test_callback context %p rescode %d gni_errno %d flags 0x%x addr %s\n",
+ context, rescode, gni_errno, flags, stoa(psau)));
}
+#endif /* TEST_BLOCKING_WORKER */
-/*
- * readconf - read the configuration information out of the file we
- * were passed. Note that since the file is supposed to be
- * machine generated, we bail out at the first sign of trouble.
- */
static void
-readconf(
- FILE *fp,
- char *name
+scheduled_sleep(
+ time_t scheduled,
+ time_t earliest
)
{
- register int i;
- char *token[NUMTOK];
- u_long intval[NUMTOK];
- u_int flags;
- char buf[MAXLINESIZE];
- char *bp;
-
- while (fgets(buf, MAXLINESIZE, fp) != NULL) {
-
- bp = buf;
- for (i = 0; i < NUMTOK; i++) {
- if ((token[i] = nexttoken(&bp)) == NULL) {
- msyslog(LOG_ERR,
- "tokenizing error in file `%s', quitting",
- name);
- resolver_exit(1);
- }
- }
-
- for (i = 1; i < NUMTOK - 1; i++) {
- if (!atouint(token[i], &intval[i])) {
- msyslog(LOG_ERR,
- "format error for integer token `%s', file `%s', quitting",
- token[i], name);
- resolver_exit(1);
- }
- }
-
-#if 0 /* paranoid checking - these are done in newpeer() */
- if (intval[TOK_HMODE] != MODE_ACTIVE &&
- intval[TOK_HMODE] != MODE_CLIENT &&
- intval[TOK_HMODE] != MODE_BROADCAST) {
- msyslog(LOG_ERR, "invalid mode (%ld) in file %s",
- intval[TOK_HMODE], name);
- resolver_exit(1);
- }
+ time_t now;
- if (intval[TOK_VERSION] > NTP_VERSION ||
- intval[TOK_VERSION] < NTP_OLDVERSION) {
- msyslog(LOG_ERR, "invalid version (%ld) in file %s",
- intval[TOK_VERSION], name);
- resolver_exit(1);
- }
- if (intval[TOK_MINPOLL] < ntp_minpoll ||
- intval[TOK_MINPOLL] > NTP_MAXPOLL) {
-
- msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s",
- intval[TOK_MINPOLL], name);
- resolver_exit(1);
- }
-
- if (intval[TOK_MAXPOLL] < ntp_minpoll ||
- intval[TOK_MAXPOLL] > NTP_MAXPOLL) {
- msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s",
- intval[TOK_MAXPOLL], name);
- resolver_exit(1);
- }
+ if (scheduled < ignore_scheduled_before) {
+ DPRINTF(1, ("ignoring sleep until %s scheduled at %s (before %s)",
+ humantime(earliest), humantime(scheduled),
+ humantime(ignore_scheduled_before)));
+ return;
+ }
- if ((intval[TOK_FLAGS] & ~(FLAG_PREFER | FLAG_NOSELECT |
- FLAG_BURST | FLAG_IBURST | FLAG_SKEY)) != 0) {
- msyslog(LOG_ERR, "invalid flags (%ld) in file %s",
- intval[TOK_FLAGS], name);
- resolver_exit(1);
+ now = time(NULL);
+
+ if (now < earliest) {
+ DPRINTF(1, ("sleep until %s scheduled at %s (>= %s)",
+ humantime(earliest), humantime(scheduled),
+ humantime(ignore_scheduled_before)));
+ if (-1 == worker_sleep(earliest - now)) {
+ /* our sleep was interrupted */
+ now = time(NULL);
+ ignore_scheduled_before = now;
+ next_dns_timeslot = now;
+#ifdef HAVE_RES_INIT
+ next_res_init = now + 60;
+ res_init();
+#endif
+ DPRINTF(1, ("sleep interrupted by daemon, ignoring sleeps scheduled before now (%s)",
+ humantime(ignore_scheduled_before)));
}
-#endif /* end paranoid checking */
-
- flags = 0;
- if (intval[TOK_FLAGS] & FLAG_PREFER)
- flags |= CONF_FLAG_PREFER;
- if (intval[TOK_FLAGS] & FLAG_NOSELECT)
- flags |= CONF_FLAG_NOSELECT;
- if (intval[TOK_FLAGS] & FLAG_BURST)
- flags |= CONF_FLAG_BURST;
- if (intval[TOK_FLAGS] & FLAG_IBURST)
- flags |= CONF_FLAG_IBURST;
-
-#ifdef OPENSSL
- if (intval[TOK_FLAGS] & FLAG_SKEY)
- flags |= CONF_FLAG_SKEY;
-#endif /* OPENSSL */
-
- /*
- * This is as good as we can check it. Add it in.
- */
- addentry(token[TOK_HOSTNAME],
- (int)intval[TOK_NEEDED], (int)intval[TOK_TYPE],
- (int)intval[TOK_HMODE], (int)intval[TOK_VERSION],
- (int)intval[TOK_MINPOLL], (int)intval[TOK_MAXPOLL],
- flags, (int)intval[TOK_TTL],
- intval[TOK_KEYID], token[TOK_KEYSTR]);
}
}
/*
- * doconfigure - attempt to resolve names and configure the server
+ * 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
-doconfigure(
- int dores
+manage_dns_retry_interval(
+ time_t * pscheduled,
+ time_t * pwhen,
+ int * pretry
)
{
- register struct conf_entry *ce;
+ time_t now;
+ time_t when;
+ int retry;
+
+ now = time(NULL);
+ retry = *pretry;
+ when = max(now + retry, next_dns_timeslot);
+ next_dns_timeslot = when;
+ retry = min(64, retry << 1);
+
+ *pscheduled = now;
+ *pwhen = when;
+ *pretry = retry;
+}
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO, "Running doconfigure %s DNS",
- dores ? "with" : "without" );
-#endif
+/*
+ * should_retry_dns is a helper used by getaddrinfo_sometime_complete
+ * and getnameinfo_sometime_complete which implements ntpd's DNS retry
+ * policy.
+ */
+static int
+should_retry_dns(
+ int rescode,
+ int res_errno
+ )
+{
+ static int eai_again_seen;
+ int again;
-#if defined(HAVE_RES_INIT)
- if (dores) /* Reload /etc/resolv.conf - bug 1226 */
- res_init();
-#endif
- ce = confentries;
- while (ce != NULL) {
-#ifdef DEBUG
- if (debug > 1)
- msyslog(LOG_INFO,
- "doconfigure: <%s> has peeraddr %s",
- ce->ce_name, stoa(&ce->peer_store));
-#endif
- if (dores && SOCK_UNSPEC(&ce->peer_store)) {
- if (!findhostaddr(ce)) {
-#ifndef IGNORE_DNS_ERRORS
- msyslog(LOG_ERR,
- "couldn't resolve `%s', giving up on it",
- ce->ce_name);
- ce = removeentry(ce);
- continue;
+ /*
+ * If the resolver failed, see if the failure is
+ * temporary. If so, return success.
+ */
+ again = 0;
+
+ switch (rescode) {
+
+ case EAI_FAIL:
+ again = 1;
+ break;
+
+ case EAI_AGAIN:
+ again = 1;
+ eai_again_seen = 1; /* [Bug 1178] */
+ break;
+
+ case EAI_NONAME:
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+ case EAI_NODATA:
#endif
- } else if (!SOCK_UNSPEC(&ce->peer_store))
- msyslog(LOG_INFO,
- "DNS %s -> %s", ce->ce_name,
- stoa(&ce->peer_store));
- }
+ again = !eai_again_seen; /* [Bug 1178] */
+ break;
- if (!SOCK_UNSPEC(&ce->peer_store)) {
- if (request(&ce->ce_config)) {
- ce = removeentry(ce);
- continue;
- }
- /*
- * Failed case. Should bump counter and give
- * up.
- */
-#ifdef DEBUG
- if (debug > 1) {
- msyslog(LOG_INFO,
- "doconfigure: request() FAILED, maybe next time.");
- }
+#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 = 1;
+ DPRINTF(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n",
+ res_errno, strerror(res_errno)));
+ break;
#endif
- }
- ce = ce->ce_next;
}
+
+ DPRINTF(2, ("intres: resolver returned: %s (%d), %sretrying\n",
+ gai_strerror(rescode), rescode, again ? "" : "not "));
+
+ return again;
}
-#else /* NO_INTRES follows */
+#else /* !WORKER follows */
int ntp_intres_nonempty_compilation_unit;
#endif
*/
fd_set activefds;
int maxactivefd;
+
+#ifndef HAVE_IO_COMPLETION_PORT
+static void maintain_activefds(int fd, int closing);
+#else
+#define maintain_activefds(fd, closing) do {} while (0)
+#endif
+
/*
* bit alternating value to detect verified interfaces during an update cycle
*/
static void remove_interface(struct interface *);
static struct interface *create_interface(u_short, struct interface *);
-static int move_fd (SOCKET);
static int is_wildcard_addr (sockaddr_u *);
static int is_wildcard_netaddr (const isc_netaddr_t *);
#endif
+
+#ifndef HAVE_IO_COMPLETION_PORT
+static void
+maintain_activefds(
+ int fd,
+ int closing
+ )
+{
+ int i;
+
+ if (fd < 0 || fd >= FD_SETSIZE) {
+ msyslog(LOG_ERR,
+ "Too many sockets in use, FD_SETSIZE %d exceeded by fd %d",
+ FD_SETSIZE, fd);
+ exit(1);
+ }
+
+ if (!closing) {
+ FD_SET(fd, &activefds);
+ maxactivefd = max(fd, maxactivefd);
+ } else {
+ FD_CLR(fd, &activefds);
+ if (maxactivefd && fd == maxactivefd) {
+ for (i = maxactivefd - 1; i >= 0; i--)
+ if (FD_ISSET(i, &activefds)) {
+ maxactivefd = i;
+ break;
+ }
+ NTP_INSIST(fd != maxactivefd);
+ }
+ }
+}
+#endif /* !HAVE_IO_COMPLETION_PORT */
+
+
+#ifdef WORK_FORK
+void
+update_resp_pipe_fd(
+ int resp_pipe_fd,
+ int closing
+ )
+{
+ maintain_activefds(resp_pipe_fd, closing);
+}
+#endif
+
+
/*
* on Unix systems the stdio library typically
* makes use of file descriptors in the lower
* and may exceed to current file decriptor limits.
* We are using following strategy:
* - keep a current socket fd boundary initialized with
- * max(0, min(getdtablesize() - FD_CHUNK, FOPEN_MAX))
+ * max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX))
* - attempt to move the descriptor to the boundary or
* above.
* - if that fails and boundary > 0 set boundary
* allocation is possible or 0 is reached - at this
* point the algrithm will be disabled
*/
-static int
+SOCKET
move_fd(
SOCKET fd
)
#ifndef FD_CHUNK
#define FD_CHUNK 10
#endif
+#ifndef FOPEN_MAX
+#define FOPEN_MAX 20
+#endif
/*
* number of fds we would like to have for
* stdio FILE* available.
#define FD_PREFERRED_SOCKBOUNDARY 48
#endif
-#ifndef HAVE_GETDTABLESIZE
+#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
+#define GETDTABLESIZE() ((int)sysconf(_SC_OPEN_MAX))
+#elif !defined(HAVE_GETDTABLESIZE)
/*
* if we have no idea about the max fd value set up things
* so we will start at FOPEN_MAX
*/
-#define getdtablesize() (FOPEN_MAX+FD_CHUNK)
+#define GETDTABLESIZE() (FOPEN_MAX + FD_CHUNK)
#endif
-#ifndef FOPEN_MAX
-#define FOPEN_MAX 20 /* assume that for the lack of anything better */
-#endif
static SOCKET socket_boundary = -1;
SOCKET newfd;
* already
*/
if (socket_boundary == -1) {
- socket_boundary = max(0, min(getdtablesize() - FD_CHUNK,
+ socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK,
min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY)));
#ifdef DEBUG
msyslog(LOG_DEBUG,
"ntp_io: estimated max descriptors: %d, initial socket boundary: %d",
- getdtablesize(), socket_boundary);
+ GETDTABLESIZE(), socket_boundary);
#endif
}
return fd;
}
+
+#ifndef HAVE_IO_COMPLETION_PORT
+/*
+ * close_all_beyond()
+ *
+ * Close all file descriptors after the given keep_fd, which is the
+ * highest fd to keep open.
+ */
+void
+close_all_beyond(
+ int keep_fd
+ )
+{
+# ifdef HAVE_CLOSEFROM
+ closefrom(keep_fd + 1);
+# elif defined(F_CLOSEM)
+ /*
+ * From 'Writing Reliable AIX Daemons,' SG24-4946-00,
+ * by Eric Agar (saves us from doing 32767 system
+ * calls)
+ */
+ if (fcntl(keep_fd + 1, F_CLOSEM, 0) == -1)
+ msyslog(LOG_ERR, "F_CLOSEM(%d): %m", keep_fd + 1);
+# else /* !HAVE_CLOSEFROM && !F_CLOSEM follows */
+ int fd;
+ int max_fd;
+
+ max_fd = GETDTABLESIZE();
+ for (fd = keep_fd + 1; fd < max_fd; fd++)
+ close(fd);
+# endif /* !HAVE_CLOSEFROM && !F_CLOSEM */
+}
+#endif /* HAVE_IO_COMPLETION_PORT */
+
+
#ifdef DEBUG_TIMING
/*
* collect timing information for various processing
- * paths. currently we only pass then on to the file
+ * paths. currently we only pass them on to the file
* for later processing. this could also do histogram
* based analysis in other to reduce the load (and skew)
* dur to the file output
#ifdef SYS_WINNT
init_io_completion_port();
-#endif /* SYS_WINNT */
+#endif
#if defined(HAVE_SIGNALED_IO)
(void) set_signal();
* addresses (up to 46 bytes), the delimiter character and the
* terminating NULL character.
*/
- if (inet_pton(AF_INET, host, &in4) == 1) {
- isc_netaddr_fromin(addr, &in4);
- return (ISC_TRUE);
- } else if (sizeof(tmpbuf) > strlen(host)) {
- if ('[' == host[0]) {
- strncpy(tmpbuf, &host[1], sizeof(tmpbuf));
- pch = strchr(tmpbuf, ']');
+ if (AF_UNSPEC == addr->family || AF_INET == addr->family)
+ if (inet_pton(AF_INET, host, &in4) == 1) {
+ isc_netaddr_fromin(addr, &in4);
+ return (ISC_TRUE);
+ }
+
+ if (AF_UNSPEC == addr->family || AF_INET6 == addr->family)
+ if (sizeof(tmpbuf) > strlen(host)) {
+ if ('[' == host[0]) {
+ strncpy(tmpbuf, &host[1], sizeof(tmpbuf));
+ pch = strchr(tmpbuf, ']');
+ if (pch != NULL)
+ *pch = '\0';
+ } else
+ strncpy(tmpbuf, host, sizeof(tmpbuf));
+ pch = strchr(tmpbuf, '%');
if (pch != NULL)
*pch = '\0';
- } else
- strncpy(tmpbuf, host, sizeof(tmpbuf));
- pch = strchr(tmpbuf, '%');
- if (pch != NULL)
- *pch = '\0';
-
- if (inet_pton(AF_INET6, tmpbuf, &in6) == 1) {
- isc_netaddr_fromin6(addr, &in6);
- return (ISC_TRUE);
+
+ if (inet_pton(AF_INET6, tmpbuf, &in6) == 1) {
+ isc_netaddr_fromin6(addr, &in6);
+ return (ISC_TRUE);
+ }
}
- }
/*
* If we got here it was not an IP address
*/
#ifdef DEBUG
msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver");
#endif
-#ifdef SYS_WINNT
- /* wake up the resolver thread */
- if (ResolverEventHandle != NULL)
- SetEvent(ResolverEventHandle);
-#else
- /* write any single byte to the pipe to wake up the resolver process */
- write( resolver_pipe_fd[1], &new_interface_found, 1 );
-#endif
+ interrupt_worker_sleep();
}
}
#endif /* HAS_ROUTING_SOCKET */
+ /*
+ * Check for a response from the blocking child
+ */
+ if (parent_resp_read_pipe &&
+ FD_ISSET(parent_resp_read_pipe, &fds)) {
+ select_count++;
+ process_blocking_response();
+ }
+
/*
* Done everything from that select.
*/
lsock->type = type;
LINK_SLIST(fd_list, lsock, link);
- /*
- * I/O Completion Ports don't care about the select and FD_SET
- */
-#ifndef HAVE_IO_COMPLETION_PORT
- if (fd < 0 || fd >= FD_SETSIZE) {
- msyslog(LOG_ERR,
- "Too many sockets in use, FD_SETSIZE %d exceeded",
- FD_SETSIZE);
- exit(1);
- }
- /*
- * keep activefds in sync
- */
- maxactivefd = max(fd, maxactivefd);
-
- FD_SET(fd, &activefds);
-#endif
+ maintain_activefds(fd, 0);
}
static void
}
free(lsock);
- /*
- * I/O Completion Ports don't care about select and fd_set
- */
-#ifndef HAVE_IO_COMPLETION_PORT
/*
* remove from activefds
*/
- FD_CLR(fd, &activefds);
-
- if (fd == maxactivefd && maxactivefd) {
- int i;
- NTP_INSIST(maxactivefd - 1 < FD_SETSIZE);
- for (i = maxactivefd - 1; i >= 0; i--)
- if (FD_ISSET(i, &activefds)) {
- maxactivefd = i;
- break;
- }
- NTP_INSIST(fd != maxactivefd);
- }
-#endif
+ maintain_activefds(fd, 1);
}
}
#include <openssl/rand.h>
#endif /* OPENSSL */
+
+/* TC_ERR represents the timer_create() error return value. */
+#ifdef SYS_VXWORKS
+#define TC_ERR ERROR
+#else
+#define TC_ERR (-1)
+#endif
+
/*
- * These routines provide support for the event timer. The timer is
+ * These routines provide support for the event timer. The timer is
* implemented by an interrupt routine which sets a flag once every
- * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
- * is called when the mainline code gets around to seeing the flag.
- * The timer routine dispatches the clock adjustment code if its time
- * has come, then searches the timer queue for expiries which are
- * dispatched to the transmit procedure. Finally, we call the hourly
- * procedure to do cleanup and print a message.
+ * second, and a timer routine which is called when the mainline code
+ * gets around to seeing the flag. The timer routine dispatches the
+ * clock adjustment code if its time has come, then searches the timer
+ * queue for expiries which are dispatched to the transmit procedure.
+ * Finally, we call the hourly procedure to do cleanup and print a
+ * message.
*/
volatile int interface_interval = 300; /* update interface every 5 minutes as default */
static u_long stats_timer; /* stats timer */
static u_long huffpuff_timer; /* huff-n'-puff timer */
u_long leapsec; /* leapseconds countdown */
-l_fp sys_time; /* current system time */
+u_long worker_idle_timer; /* next check for idle intres */
#ifdef OPENSSL
static u_long revoke_timer; /* keys revoke timer */
static u_long keys_timer; /* session key timer */
#if !defined(VMS)
# if !defined SYS_WINNT || defined(SYS_CYGWIN32)
-# ifndef HAVE_TIMER_SETTIME
- struct itimerval itimer;
-# else
- static timer_t ntpd_timerid;
+# ifdef HAVE_TIMER_CREATE
+ static timer_t timer_id;
struct itimerspec itimer;
-# endif /* HAVE_TIMER_SETTIME */
-# endif /* SYS_WINNT */
-#endif /* VMS */
+# else
+ struct itimerval itimer;
+# endif
+# endif
+#endif
/*
- * reinit_timer - reinitialize interval timer.
+ * reinit_timer - reinitialize interval timer after a clock step.
*/
void
reinit_timer(void)
{
#if !defined(SYS_WINNT) && !defined(VMS)
-# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
- timer_gettime(ntpd_timerid, &itimer);
+# ifdef HAVE_TIMER_CREATE
+ timer_gettime(timer_id, &itimer);
if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
}
}
itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
itimer.it_interval.tv_nsec = 0;
- timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
+ timer_settime(timer_id, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
# else
getitimer(ITIMER_REAL, &itimer);
if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
timer_xmtcalls = 0;
timer_timereset = 0;
-#if !defined(SYS_WINNT)
+#ifndef SYS_WINNT
/*
* Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
* seconds from now and they continue on every 2**EVENT_TIMEOUT
* seconds.
*/
-# if !defined(VMS)
-# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
- if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
-# ifdef SYS_VXWORKS
- ERROR
-# else
- -1
-# endif
- )
- {
+# ifndef VMS
+# ifdef HAVE_TIMER_CREATE
+ if (timer_create(CLOCK_REALTIME, NULL, &timer_id) == TC_ERR) {
fprintf (stderr, "timer create FAILED\n");
exit (0);
}
(void) signal_no_reset(SIGALRM, alarming);
itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
- timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
+ timer_settime(timer_id, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
# else
(void) signal_no_reset(SIGALRM, alarming);
itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
# endif
-# else /* VMS */
+# else /* VMS follows */
vmsinc[0] = 10000000; /* 1 sec */
vmsinc[1] = 0;
lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
lib$addx(&vmsinc, &vmstimer, &vmstimer);
sys$setimr(0, &vmstimer, alarming, alarming, 0);
-# endif /* VMS */
-#else /* SYS_WINNT */
+# endif /* VMS */
+#else /* SYS_WINNT follows */
/*
* Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
* Under Windows/NT,
}
}
-#endif /* SYS_WINNT */
+#endif /* SYS_WINNT */
}
+
#if defined(SYS_WINNT)
extern HANDLE
get_timer_handle(void)
}
#endif
+
/*
* timer - event timer
*/
{
register struct peer *peer, *next_peer;
u_int n;
+ l_fp now;
/*
- * The basic timerevent is one second. This is used to adjust
- * the system clock in time and frequency, implement the
- * kiss-o'-deatch function and implement the association
- * polling function..
+ * The basic timerevent is one second. This is used to adjust the
+ * system clock in time and frequency, implement the kiss-o'-death
+ * function and the association polling function.
*/
current_time++;
- get_systime(&sys_time);
if (adjust_timer <= current_time) {
adjust_timer += 1;
adj_host_clock();
}
/*
- * Garbage collect key list and generate new private value. The
- * timer runs only after initial synchronization and fires about
- * once per day.
+ * Generate new private value. The timer runs only after
+ * initial synchronization and fires about once per day.
*/
if (revoke_timer <= current_time && sys_leap !=
LEAP_NOTINSYNC) {
DPRINTF(2, ("timer: interface update\n"));
interface_update(NULL, NULL);
}
-
+
+ if (worker_idle_timer && worker_idle_timer <= current_time)
+ worker_idle_timer_fired();
+
/*
* Finally, write hourly stats.
*/
if (stats_timer <= current_time) {
stats_timer += HOUR;
write_stats();
- if (sys_tai != 0 && sys_time.l_ui > leap_expire)
- report_event(EVNT_LEAPVAL, NULL, NULL);
+ if (sys_tai != 0) {
+ get_systime(&now);
+ if (now.l_ui > leap_expire)
+ report_event(EVNT_LEAPVAL, NULL, NULL);
+ }
}
}
--- /dev/null
+/*
+ * ntp_worker.c
+ */
+#include <config.h>
+#include "ntp_workimpl.h"
+
+#ifdef WORKER
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include "iosignal.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 "ntp_unixtime.h"
+#include "ntp_intres.h"
+
+
+#define CHILD_MAX_IDLE 15 /* seconds, idle worker limit */
+
+int intres_req_pending;
+
+
+int
+queue_blocking_request(
+ blocking_work_req rtype,
+ void * req,
+ size_t reqsize,
+ blocking_work_callback done_func,
+ void * context
+ )
+{
+ 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;
+
+ if (0 == intres_req_pending)
+ worker_idle_timer = 0;
+ intres_req_pending++;
+
+ return send_blocking_req_internal(&req_hdr, req);
+}
+
+int queue_blocking_response(
+ 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(resp);
+}
+
+
+void
+process_blocking_response(
+ void
+ )
+{
+ blocking_pipe_header * resp;
+ void * data;
+
+ /*
+ * On Windows send_blocking_resp_internal() may signal the
+ * blocking_response_ready event multiple times while we're
+ * processing a response, so always consume all available
+ * responses before returning to test the event again.
+ */
+#ifdef SYS_WINNT
+ do {
+#endif
+ resp = receive_blocking_resp_internal();
+ if (NULL != resp) {
+ NTP_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);
+ if (0 == intres_req_pending)
+ worker_idle_timer = current_time
+ + CHILD_MAX_IDLE;
+ }
+#ifdef SYS_WINNT
+ } while (NULL != resp);
+#endif
+}
+
+
+/*
+ * blocking_child_common runs as a forked child or thread
+ */
+int
+blocking_child_common (
+ void
+ )
+{
+ int say_bye;
+ blocking_pipe_header *req;
+
+ NLOG(NLOG_SYSEVENT)
+ msyslog(LOG_NOTICE, "DNS worker started");
+
+ say_bye = 0;
+ while (!say_bye) {
+ req = receive_blocking_req_internal();
+ if (NULL == req) {
+ say_bye = 1;
+ break;
+ }
+
+ NTP_REQUIRE(BLOCKING_REQ_MAGIC == req->magic_sig);
+
+ switch (req->rtype) {
+ case BLOCKING_GETADDRINFO:
+ if (blocking_getaddrinfo(req))
+ say_bye = 1;
+ break;
+
+ case BLOCKING_GETNAMEINFO:
+ if (blocking_getnameinfo(req))
+ say_bye = 1;
+ break;
+
+ default:
+ msyslog(LOG_ERR, "unknown req %d to blocking worker", req->rtype);
+ say_bye = 1;
+ }
+
+ free(req);
+ }
+
+ NLOG(NLOG_SYSEVENT)
+ msyslog(LOG_NOTICE, "DNS worker finished");
+
+ return 0;
+}
+
+
+#else /* !WORKER follows */
+int ntp_worker_nonempty_compilation_unit;
+#endif
#include <ntp_random.h>
#include "ntp_syslog.h"
-#include "isc/assertions.h"
+#include "ntp_assert.h"
#include "isc/error.h"
#include "isc/strerror.h"
#include "isc/formatcheck.h"
#endif
int listen_to_virtual_ips = 1;
-const char *specific_interface = NULL; /* interface name or IP address to bind to */
/*
* No-fork flag. If set, we do not become a background daemon.
#endif /* HAVE_DNSREGISTRATION */
#ifdef HAVE_DROPROOT
-int droproot = 0;
+int droproot;
+int root_dropped;
char *user = NULL; /* User to switch to */
char *group = NULL; /* group to switch to */
const char *chrootdir = NULL; /* directory to chroot to */
int ntpdmain (int, char **);
static void set_process_priority (void);
void init_logging (char const *, int);
-void setup_logfile (void);
+void setup_logfile (int);
static void assertion_failed (const char *file, int line,
isc_assertiontype_t type, const char *cond);
/*
* Initialize the logging
+ *
+ * Called once per process, including forked children.
*/
void
init_logging(
- char const *name,
+ const char *name,
int log_version
)
{
const char *cp;
+ /*
+ * ntpd defaults to only logging sync-category events, when
+ * NLOG() is used to conditionalize. Other libntp clients
+ * leave it alone so that all NLOG() conditionals will fire.
+ * This presumes all bits lit in ntp_syslogmask can't be
+ * configured via logconfig and all lit is thereby a sentinel
+ * that ntp_syslogmask is still at its default from libntp,
+ * keeping in mind this function is called in forked children
+ * where it has already been called in the parent earlier.
+ */
+ if (~(u_long)0 == ntp_syslogmask)
+ ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */
+
/*
* Logging. This may actually work on the gizmo board. Find a name
* to log with by using the basename
cp = name;
else
cp++;
+ progname = cp;
#if !defined(VMS)
# ifndef LOG_DAEMON
- openlog(cp, LOG_PID);
+ openlog(progname, LOG_PID);
# else /* LOG_DAEMON */
# ifndef LOG_NTP
# define LOG_NTP LOG_DAEMON
# endif
- openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
+ openlog(progname, LOG_PID | LOG_NDELAY, LOG_NTP);
# ifdef DEBUG
if (debug)
setlogmask(LOG_UPTO(LOG_DEBUG));
#endif /* !VMS */
if (log_version)
- NLOG(NLOG_SYSINFO) /* 'if' clause for syslog */
msyslog(LOG_NOTICE, "%s", Version);
}
/*
- * Redirect logging to a file if requested with -l.
- * The ntp.conf logfile directive does not use this code, see
- * config_vars() in ntp_config.c.
+ * change_logfile()
+ *
+ * Used to change from syslog to a logfile, or from one logfile to
+ * another, and to reopen logfiles after forking. On systems where
+ * ntpd forks, deals with converting relative logfile paths to
+ * absolute (root-based) because we reopen logfiles after the current
+ * directory has changed.
+ */
+int
+change_logfile(
+ const char *fname,
+ int log_version
+ )
+{
+ FILE * new_file;
+ const char * log_fname;
+ char * abs_fname;
+#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
+ char curdir[512];
+ size_t cd_octets;
+ size_t octets;
+#endif /* POSIX */
+
+ NTP_REQUIRE(fname != NULL);
+ log_fname = fname;
+
+ /*
+ * In a forked child of a parent which is logging to a file
+ * instead of syslog, syslog_file will be NULL and both
+ * syslog_fname and syslog_abs_fname will be non-NULL.
+ * If we are given the same filename previously opened
+ * and it's still open, there's nothing to do here.
+ */
+ if (syslog_file != NULL && syslog_fname != NULL &&
+ (log_fname == syslog_fname ||
+ 0 == strcmp(syslog_fname, log_fname)))
+ return 0;
+
+ if (0 == strcmp(log_fname, "stderr")) {
+ new_file = stderr;
+ abs_fname = estrdup(log_fname);
+ } else if (0 == strcmp(log_fname, "stdout")) {
+ new_file = stdout;
+ abs_fname = estrdup(log_fname);
+ } else {
+ if (syslog_fname != NULL &&
+ 0 == strcmp(log_fname, syslog_fname))
+ log_fname = syslog_abs_fname;
+#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
+ if (log_fname != syslog_abs_fname &&
+ DIR_SEP != log_fname[0] &&
+ 0 != strcmp(log_fname, "stderr") &&
+ 0 != strcmp(log_fname, "stdout") &&
+ NULL != getcwd(curdir, sizeof(curdir))) {
+ cd_octets = strlen(curdir);
+ /* trim any trailing '/' */
+ if (cd_octets > 1 &&
+ DIR_SEP == curdir[cd_octets - 1])
+ cd_octets--;
+ octets = cd_octets;
+ octets += 1; /* separator '/' */
+ octets += strlen(syslog_fname);
+ octets += 1; /* NUL terminator */
+ abs_fname = emalloc(octets);
+ snprintf(abs_fname, octets, "%.*s%c%s",
+ cd_octets, curdir, DIR_SEP,
+ syslog_fname);
+ } else
+#endif
+ abs_fname = estrdup(log_fname);
+ msyslog(LOG_INFO, "attempting to open log %s", abs_fname);
+ new_file = fopen(abs_fname, "a");
+ }
+
+ if (NULL == new_file)
+ return -1;
+
+ /* leave a pointer in the old log */
+ if (log_fname != syslog_abs_fname)
+ msyslog(LOG_NOTICE, "switching logging to file %s",
+ abs_fname);
+
+ if (syslog_file != NULL &&
+ syslog_file != stderr && syslog_file != stdout &&
+ fileno(syslog_file) != fileno(new_file))
+ fclose(syslog_file);
+ syslog_file = new_file;
+ if (log_fname != syslog_abs_fname) {
+ if (syslog_abs_fname != NULL &&
+ syslog_abs_fname != syslog_fname)
+ free(syslog_abs_fname);
+ if (syslog_fname != NULL)
+ free(syslog_fname);
+ syslog_fname = estrdup(log_fname);
+ syslog_abs_fname = abs_fname;
+ }
+ syslogit = 0;
+ if (log_version)
+ msyslog(LOG_NOTICE, "%s", Version);
+
+ return 0;
+}
+
+
+/*
+ * setup_logfile()
+ *
+ * Redirect logging to a file if requested with -l/--logfile or via
+ * ntp.conf logfile directive.
+ *
+ * This routine is invoked three different times in the sequence of a
+ * typical daemon ntpd with DNS lookups to do. First it is invoked in
+ * the original ntpd process, then again in the daemon after closing
+ * all descriptors. In both of those cases, ntp.conf has not been
+ * processed, so only -l/--logfile will trigger logfile redirection in
+ * those invocations. Finally, if DNS names are resolved, the worker
+ * child invokes this routine after its fork and close of all
+ * descriptors. In this case, ntp.conf has been processed and any
+ * "logfile" directive needs to be honored in the child as well.
*/
void
setup_logfile(
- void
+ int log_version
)
{
- if (HAVE_OPT( LOGFILE )) {
- const char *my_optarg = OPT_ARG( LOGFILE );
- FILE *new_file;
-
- if(strcmp(my_optarg, "stderr") == 0)
- new_file = stderr;
- else if(strcmp(my_optarg, "stdout") == 0)
- new_file = stdout;
- else
- new_file = fopen(my_optarg, "a");
- if (new_file != NULL) {
- NLOG(NLOG_SYSINFO)
- msyslog(LOG_NOTICE, "logging to file %s", my_optarg);
- if (syslog_file != NULL &&
- fileno(syslog_file) != fileno(new_file))
- (void)fclose(syslog_file);
-
- syslog_file = new_file;
- syslogit = 0;
- }
- else
- msyslog(LOG_ERR,
- "Cannot open log file %s",
- my_optarg);
+ if (NULL == syslog_fname && HAVE_OPT(LOGFILE)) {
+ if (-1 == change_logfile(OPT_ARG(LOGFILE), log_version))
+ msyslog(LOG_ERR, "Cannot open log file %s, %m",
+ OPT_ARG(LOGFILE));
+ } else if (NULL != syslog_fname) {
+ if (-1 == change_logfile(syslog_fname, log_version))
+ msyslog(LOG_ERR, "Cannot reopen log file %s, %m",
+ syslog_fname);
}
}
parse_cmdline_opts(&argc, &argv);
init_logging(progname, 1); /* Open the log file */
+ /*
+ * Install trap handlers to log errors and assertion failures.
+ * Default handlers print to stderr which doesn't work if detached.
+ */
+ isc_assertion_setcallback(assertion_failed);
+ isc_error_setfatal(library_fatal_error);
+ isc_error_setunexpected(library_unexpected_error);
+
#ifdef HAVE_UMASK
{
mode_t uv;
#endif
/* honor -l/--logfile option to log to a file */
- setup_logfile();
+ setup_logfile(1);
/*
* Enable the Multi-Media Timer for Windows?
*/
if (!nofork) {
- /*
- * Install trap handlers to log errors and assertion
- * failures. Default handlers print to stderr which
- * doesn't work if detached.
- */
- isc_assertion_setcallback(assertion_failed);
- isc_error_setfatal(library_fatal_error);
- isc_error_setunexpected(library_unexpected_error);
-
# ifndef SYS_WINNT
# ifdef HAVE_DAEMON
daemon(0, 0);
if (fork()) /* HMS: What about a -1? */
exit(0);
- {
-#if !defined(F_CLOSEM)
- u_long s;
- int max_fd;
-#endif /* !FCLOSEM */
- if (syslog_file != NULL) {
- fclose(syslog_file);
- syslog_file = NULL;
- }
-#if defined(F_CLOSEM)
- /*
- * From 'Writing Reliable AIX Daemons,' SG24-4946-00,
- * by Eric Agar (saves us from doing 32767 system
- * calls)
- */
- if (fcntl(0, F_CLOSEM, 0) == -1)
- msyslog(LOG_ERR, "ntpd: failed to close open files(): %m");
-#else /* not F_CLOSEM */
-
-# if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
- max_fd = sysconf(_SC_OPEN_MAX);
-# else /* HAVE_SYSCONF && _SC_OPEN_MAX */
- max_fd = getdtablesize();
-# endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
- for (s = 0; s < max_fd; s++)
- (void) close((int)s);
-#endif /* not F_CLOSEM */
- (void) open("/", 0);
- (void) dup2(0, 1);
- (void) dup2(0, 2);
-
- init_logging(progname, 0);
- /* we lost our logfile (if any) daemonizing */
- setup_logfile();
+ if (syslog_file != NULL) {
+ fclose(syslog_file);
+ syslog_file = NULL;
+ syslogit = 1;
+ }
+ close_all_beyond(-1);
+ open("/", 0);
+ dup2(0, 1);
+ dup2(0, 2);
+
+ init_logging(progname, 0);
+ /* we lost our logfile (if any) daemonizing */
+ setup_logfile(0);
#ifdef SYS_DOMAINOS
- {
- uid_$t puid;
- status_$t st;
+ {
+ uid_$t puid;
+ status_$t st;
- proc2_$who_am_i(&puid);
- proc2_$make_server(&puid, &st);
- }
+ proc2_$who_am_i(&puid);
+ proc2_$make_server(&puid, &st);
+ }
#endif /* SYS_DOMAINOS */
#if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
# ifdef HAVE_SETSID
- if (setsid() == (pid_t)-1)
- msyslog(LOG_ERR, "ntpd: setsid(): %m");
+ if (setsid() == (pid_t)-1)
+ msyslog(LOG_ERR, "ntpd: setsid(): %m");
# else
- if (setpgid(0, 0) == -1)
- msyslog(LOG_ERR, "ntpd: setpgid(): %m");
+ if (setpgid(0, 0) == -1)
+ msyslog(LOG_ERR, "ntpd: setpgid(): %m");
# endif
#else /* HAVE_SETPGID || HAVE_SETSID */
- {
+ {
# if defined(TIOCNOTTY)
- int fid;
+ int fid;
- fid = open("/dev/tty", 2);
- if (fid >= 0)
- {
- (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
- (void) close(fid);
- }
+ fid = open("/dev/tty", 2);
+ if (fid >= 0) {
+ ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
+ close(fid);
+ }
# endif /* defined(TIOCNOTTY) */
# ifdef HAVE_SETPGRP_0
- (void) setpgrp();
+ setpgrp();
# else /* HAVE_SETPGRP_0 */
- (void) setpgrp(0, getpid());
+ setpgrp(0, getpid());
# endif /* HAVE_SETPGRP_0 */
- }
+ }
#endif /* HAVE_SETPGID || HAVE_SETSID */
#ifdef _AIX
- /* Don't get killed by low-on-memory signal. */
- sa.sa_handler = catch_danger;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
+ /* Don't get killed by low-on-memory signal. */
+ sa.sa_handler = catch_danger;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
- (void) sigaction(SIGDANGER, &sa, NULL);
+ sigaction(SIGDANGER, &sa, NULL);
#endif /* _AIX */
- }
# endif /* not HAVE_DAEMON */
# endif /* SYS_WINNT */
}
initializing = 0;
#ifdef HAVE_DROPROOT
- if( droproot ) {
+ if (droproot) {
/* Drop super-user privileges and chroot now if the OS supports this */
#ifdef HAVE_LINUX_CAPABILITIES
if (disable_dynamic_updates && interface_interval) {
interface_interval = 0;
- msyslog(LOG_INFO, "running in unprivileged mode disables dynamic interface tracking");
+ msyslog(LOG_INFO, "running as non-root disables dynamic interface tracking");
}
#ifdef HAVE_LINUX_CAPABILITIES
- do {
+ {
/*
* We may be running under non-root uid now, but we still hold full root privileges!
* We drop all of them, except for the crucial one or two: cap_sys_time and
* cap_net_bind_service if doing dynamic interface tracking.
*/
cap_t caps;
- char *captext = (interface_interval)
- ? "cap_sys_time,cap_net_bind_service=ipe"
- : "cap_sys_time=ipe";
- if( ! ( caps = cap_from_text( captext ) ) ) {
- msyslog( LOG_ERR, "cap_from_text() failed: %m" );
+ char *captext;
+
+ captext = (interface_interval)
+ ? "cap_sys_time,cap_net_bind_service=ipe"
+ : "cap_sys_time=ipe";
+ caps = cap_from_text(captext);
+ if (!caps) {
+ msyslog(LOG_ERR,
+ "cap_from_text(%s) failed: %m",
+ captext);
exit(-1);
}
- if( cap_set_proc( caps ) == -1 ) {
- msyslog( LOG_ERR, "cap_set_proc() failed to drop root privileges: %m" );
+ if (-1 == cap_set_proc(caps)) {
+ msyslog(LOG_ERR,
+ "cap_set_proc() failed to drop root privs: %m");
exit(-1);
}
- cap_free( caps );
- } while(0);
+ cap_free(caps);
+ }
#endif /* HAVE_LINUX_CAPABILITIES */
-
- } /* if( droproot ) */
+ root_dropped = 1;
+ fork_deferred_worker();
+ } /* if (droproot) */
#endif /* HAVE_DROPROOT */
/*
static void
assertion_failed(const char *file, int line, isc_assertiontype_t type,
- const char *cond)
+ const char *cond)
{
isc_assertion_setcallback(NULL); /* Avoid recursion */
file, line, isc_assertion_typetotext(type), cond);
msyslog(LOG_ERR, "exiting (due to assertion failure)");
+#if defined(DEBUG) && defined(SYS_WINNT)
+ if (debug)
+ DebugBreak();
+#endif
+
abort();
}
static void
library_fatal_error(const char *file, int line, const char *format,
- va_list args)
+ va_list args)
{
char errbuf[256];
msyslog(LOG_ERR, errbuf);
msyslog(LOG_ERR, "exiting (due to fatal error in library)");
+#if defined(DEBUG) && defined(SYS_WINNT)
+ if (debug)
+ DebugBreak();
+#endif
+
abort();
}
* (Some code shamelessly based on the original NTP discrete event simulator)
*/
+#include <config.h>
#ifdef SIM
#include "ntpd.h"
#include "ntpsim.h"
# include "ppsapi_timepps.h"
#endif
-#ifdef XNTP_BIG_ENDIAN
+#ifdef WORDS_BIGENDIAN
#define getshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
#define putshort(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
#else
}
else if ((up->rpt_buf[0] == PACKET_41A) & (up->type == CLK_ACUTIME)) {
#ifdef DEBUG
- printf("GPS TOW: %ld\n", getlong((u_char *) &mb(0)));
+ printf("GPS TOW: %ld\n", (long)getlong((u_char *) &mb(0)));
printf("GPS WN: %d\n", getint((u_char *) &mb(4)));
- printf("GPS UTC-GPS Offser: %ld\n", getlong((u_char *) &mb(6)));
+ printf("GPS UTC-GPS Offser: %ld\n", (long)getlong((u_char *) &mb(6)));
#endif
return 0;
}
return 0;
}
-#if 0 /* unused */
/*
- * this 'casts' a character array into a float
+ * copy/swap a big-endian palisade double into a host double
*/
-float
-getfloat (
- u_char *bp
- )
-{
- float sval;
-#ifdef WORDS_BIGENDIAN
- ((char *) &sval)[0] = *bp++;
- ((char *) &sval)[1] = *bp++;
- ((char *) &sval)[2] = *bp++;
- ((char *) &sval)[3] = *bp++;
-#else
- ((char *) &sval)[3] = *bp++;
- ((char *) &sval)[2] = *bp++;
- ((char *) &sval)[1] = *bp++;
- ((char *) &sval)[0] = *bp;
-#endif /* ! XNTP_BIG_ENDIAN */
- return sval;
-}
-#endif
-
-/*
- * this 'casts' a character array into a double
- */
-double
+static double
getdbl (
u_char *bp
)
{
- double dval;
-#ifdef WORDS_BIGENDIAN
- ((char *) &dval)[0] = *bp++;
- ((char *) &dval)[1] = *bp++;
- ((char *) &dval)[2] = *bp++;
- ((char *) &dval)[3] = *bp++;
- ((char *) &dval)[4] = *bp++;
- ((char *) &dval)[5] = *bp++;
- ((char *) &dval)[6] = *bp++;
- ((char *) &dval)[7] = *bp;
+#ifdef WORDS_BIGENDIAN
+ double out;
+
+ memcpy(&out, bp, sizeof(out));
+ return out;
#else
- ((char *) &dval)[7] = *bp++;
- ((char *) &dval)[6] = *bp++;
- ((char *) &dval)[5] = *bp++;
- ((char *) &dval)[4] = *bp++;
- ((char *) &dval)[3] = *bp++;
- ((char *) &dval)[2] = *bp++;
- ((char *) &dval)[1] = *bp++;
- ((char *) &dval)[0] = *bp;
-#endif /* ! XNTP_BIG_ENDIAN */
- return dval;
+ union {
+ u_char ch[8];
+ u_int32 u32[2];
+ } ui;
+
+ union {
+ double out;
+ u_int32 u32[2];
+ } uo;
+
+ memcpy(ui.ch, bp, sizeof(ui.ch));
+ /* least-significant 32 bits of double from swapped bp[4] to bp[7] */
+ uo.u32[0] = ntohl(ui.u32[1]);
+ /* most-significant 32 bits from swapped bp[0] to bp[3] */
+ uo.u32[1] = ntohl(ui.u32[0]);
+
+ return uo.out;
+#endif
}
/*
- * cast a 16 bit character array into a short (16 bit) int
+ * copy/swap a big-endian palisade short into a host short
*/
-short
+static short
getint (
u_char *bp
)
{
- return (short) (bp[1] + (bp[0] << 8));
+ return (short)ntohs(*(u_short *)bp);
}
/*
- * cast a 32 bit character array into a long (32 bit) int
+ * copy/swap a big-endian palisade 32-bit int into a host 32-bit int
*/
-long
+static int32
getlong(
u_char *bp
)
{
- return (long) (bp[0] << 24) |
- (bp[1] << 16) |
- (bp[2] << 8) |
- bp[3];
+ return (int32)(u_int32)ntohl(*(u_int32 *)bp);
}
int refclock_palisade_bs;
*
*/
-#ifndef _REFCLOCK_PALISADE_H
-#define _REFCLOCK_PALISADE_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#ifndef REFCLOCK_PALISADE_H
+#define REFCLOCK_PALISADE_H
#if defined HAVE_SYS_MODEM_H
#include <sys/modem.h>
static void palisade_shutdown (int, struct peer *);
static void palisade_receive (struct peer *);
static void palisade_poll (int, struct peer *);
-static void palisade_io (struct recvbuf *);
+static void palisade_io (struct recvbuf *);
int palisade_configure (int, struct peer *);
int TSIP_decode (struct peer *);
long HW_poll (struct refclockproc *);
-float getfloat (u_char *);
-double getdbl (u_char *);
-short getint (u_char *);
-long getlong (u_char *);
+static double getdbl (u_char *);
+static short getint (u_char *);
+static int32 getlong (u_char *);
#ifdef PALISADE_SENDCMD_RESURRECTED
static int sendetx (struct packettx *buffer, int fd);
static void init_thunderbolt (int fd);
static void init_acutime (int fd);
-#endif /* PALISADE_H */
+
+#endif /* REFCLOCK_PALISADE_H */
--- /dev/null
+/*
+ * work_fork.c - fork implementation for blocking worker child.
+ */
+#include <config.h>
+#include "ntp_workimpl.h"
+
+#ifdef WORK_FORK
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include "iosignal.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 "ntp_unixtime.h"
+#include "ntp_worker.h"
+
+/*
+ * pipe descriptors for both directions
+ * 0 indicates invalid/unopened, not descriptor 0.
+ */
+static int parent_req_write_pipe;
+ int parent_resp_read_pipe;
+static int child_req_read_pipe;
+static int child_resp_write_pipe;
+static int blocking_worker_pid;
+static volatile int worker_sighup_received;
+
+static void fork_blocking_child(void);
+static RETSIGTYPE worker_sighup(int);
+static void send_worker_home_atexit(void);
+
+
+/*
+ * exit_worker()
+ *
+ * On some systems _exit() is preferred to exit() for forked children.
+ * For example, http://netbsd.gw.com/cgi-bin/man-cgi?fork++NetBSD-5.0
+ * recommends _exit() to avoid double-flushing C runtime stream buffers
+ * and also to avoid calling the parent's atexit() routines in the
+ * child. On those systems WORKER_CHILD_EXIT is _exit. Since _exit
+ * bypasses CRT cleanup, fflush() files we know might have output
+ * buffered.
+ */
+void
+exit_worker(
+ int exitcode
+ )
+{
+ if (syslog_file != NULL)
+ fflush(syslog_file);
+ fflush(stdout);
+ fflush(stderr);
+ WORKER_CHILD_EXIT (exitcode); /* space before ( required */
+}
+
+
+static RETSIGTYPE
+worker_sighup(
+ int sig
+ )
+{
+ if (SIGHUP == sig)
+ worker_sighup_received = 1;
+}
+
+
+int
+worker_sleep(
+ time_t seconds
+ )
+{
+ u_int sleep_remain;
+
+ sleep_remain = (u_int)seconds;
+ do {
+ if (!worker_sighup_received)
+ sleep_remain = sleep(sleep_remain);
+ if (worker_sighup_received) {
+ DPRINTF(1, ("worker SIGHUP with %us left to sleep",
+ sleep_remain));
+ worker_sighup_received = 0;
+ return -1;
+ }
+ } while (sleep_remain);
+
+ return 0;
+}
+
+
+void
+interrupt_worker_sleep(void)
+{
+ if (blocking_worker_pid != 0 &&
+ -1 == kill(blocking_worker_pid, SIGHUP))
+ msyslog(LOG_ERR,
+ "Unable to signal HUP to wake child pid %d: %m",
+ blocking_worker_pid);
+}
+
+
+static void
+send_worker_home_atexit(void)
+{
+ if (!parent_req_write_pipe)
+ return;
+
+ close(parent_req_write_pipe);
+ parent_req_write_pipe = 0;
+ close(parent_resp_read_pipe);
+ parent_resp_read_pipe = 0;
+ interrupt_worker_sleep();
+ blocking_worker_pid = 0;
+}
+
+
+int
+send_blocking_req_internal(
+ blocking_pipe_header * hdr,
+ void * data
+ )
+{
+ int octets;
+ int rc;
+
+ NTP_REQUIRE(hdr != NULL);
+ NTP_REQUIRE(data != NULL);
+ NTP_REQUIRE(BLOCKING_REQ_MAGIC == hdr->magic_sig);
+
+ if (!parent_req_write_pipe) {
+ fork_blocking_child();
+ NTP_INSIST(parent_req_write_pipe);
+ }
+
+ octets = sizeof(*hdr);
+ rc = write(parent_req_write_pipe, hdr, octets);
+
+ if (rc == octets) {
+ octets = hdr->octets - sizeof(*hdr);
+ rc = write(parent_req_write_pipe, data,
+ octets);
+
+ if (rc == octets)
+ return 0;
+ }
+
+ if (rc < 0)
+ msyslog(LOG_ERR, "send_blocking_req_internal: pipe write: %m");
+ else
+ msyslog(LOG_ERR, "send_blocking_req_internal: short write %d of %d\n", rc, octets);
+
+ exit(1); /* otherwise would be return -1 */
+}
+
+
+blocking_pipe_header *
+receive_blocking_req_internal(
+ void
+ )
+{
+ blocking_pipe_header hdr;
+ blocking_pipe_header *req;
+ int trycount;
+ int rc;
+
+ NTP_REQUIRE(child_req_read_pipe);
+
+ req = NULL;
+
+ trycount = 3;
+ do
+ rc = read(child_req_read_pipe, &hdr, sizeof(hdr));
+ while (--trycount && !rc);
+
+ if (rc < 0)
+ msyslog(LOG_ERR,
+ "receive_blocking_req_internal: pipe read %m\n");
+ else if (0 == rc)
+ DPRINTF(1, ("parent closed request pipe\n"));
+ else if (rc != sizeof(hdr))
+ msyslog(LOG_ERR,
+ "receive_blocking_req_internal: short header read %d of %d\n",
+ rc, sizeof(hdr));
+ else {
+ req = emalloc(hdr.octets);
+ memcpy(req, &hdr, sizeof(*req));
+
+ rc = read(child_req_read_pipe,
+ (char *)req + sizeof(*req),
+ hdr.octets - sizeof(hdr));
+
+ if (rc < 0)
+ msyslog(LOG_ERR,
+ "receive_blocking_req_internal: pipe data read %m\n");
+ else if (rc != hdr.octets - sizeof(hdr))
+ msyslog(LOG_ERR,
+ "receive_blocking_req_internal: short read %d of %d\n",
+ rc, hdr.octets - sizeof(hdr));
+ else if (BLOCKING_REQ_MAGIC != req->magic_sig)
+ msyslog(LOG_ERR,
+ "receive_blocking_req_internal: packet header mismatch (0x%x)",
+ req->magic_sig);
+ else
+ return req;
+ }
+
+ if (req)
+ free(req);
+
+ return NULL;
+}
+
+
+int
+send_blocking_resp_internal(
+ blocking_pipe_header *resp
+ )
+{
+ int octets;
+ int rc;
+
+ NTP_REQUIRE(child_resp_write_pipe);
+
+ octets = resp->octets;
+ rc = write(child_resp_write_pipe, resp, octets);
+ free(resp);
+
+ if (octets == rc)
+ return 0;
+
+ if (rc < 0)
+ DPRINTF(1, ("send_blocking_resp_internal: pipe write %m\n"));
+ else
+ DPRINTF(1, ("send_blocking_resp_internal: short write %d of %d\n", rc, octets));
+
+ return -1;
+}
+
+
+blocking_pipe_header *
+receive_blocking_resp_internal(
+ void
+ )
+{
+ blocking_pipe_header hdr;
+ blocking_pipe_header *resp;
+ int rc;
+
+ NTP_REQUIRE(parent_resp_read_pipe);
+
+ resp = NULL;
+
+ rc = read(parent_resp_read_pipe, &hdr, sizeof(hdr));
+
+ if (rc < 0)
+ DPRINTF(1, ("receive_blocking_resp_internal: pipe read %m\n"));
+ else if (rc != sizeof(hdr))
+ DPRINTF(1, ("receive_blocking_resp_internal: short header read %d of %d\n",
+ rc, sizeof(hdr)));
+ else if (BLOCKING_RESP_MAGIC != hdr.magic_sig)
+ DPRINTF(1, ("receive_blocking_resp_internal: header mismatch (0x%x)\n",
+ hdr.magic_sig));
+ else {
+ resp = emalloc(hdr.octets);
+ memcpy(resp, &hdr, sizeof(*resp));
+
+ rc = read(parent_resp_read_pipe,
+ (char *)resp + sizeof(*resp),
+ hdr.octets - sizeof(hdr));
+
+ if (rc < 0)
+ DPRINTF(1, ("receive_blocking_resp_internal: pipe data read %m\n"));
+ else if (rc < hdr.octets - sizeof(hdr))
+ DPRINTF(1, ("receive_blocking_resp_internal: short read %d of %d\n",
+ rc, hdr.octets - sizeof(hdr)));
+ else
+ return resp;
+ }
+
+ if (resp)
+ free(resp);
+
+ return NULL;
+}
+
+
+#if defined(HAVE_DROPROOT) && defined(WORK_FORK)
+void
+fork_deferred_worker(void)
+{
+ NTP_REQUIRE(droproot);
+ NTP_REQUIRE(root_dropped);
+
+ if (parent_req_write_pipe && !blocking_worker_pid)
+ fork_blocking_child();
+}
+#endif
+
+
+static void
+fork_blocking_child(
+ void
+ )
+{
+ static int atexit_installed;
+ static int blocking_pipes[4];
+ int childpid;
+ int keep_fd;
+ int fd;
+
+ /*
+ * parent and child communicate via a pair of pipes.
+ *
+ * 0 child read request
+ * 1 parent write request
+ * 2 parent read response
+ * 3 child write response
+ */
+ if (!parent_req_write_pipe) {
+ if (pipe(&blocking_pipes[0]) < 0 ||
+ pipe(&blocking_pipes[2]) < 0) {
+ msyslog(LOG_ERR, "unable to create worker pipes: %m");
+ exit(1);
+ }
+
+ /*
+ * Move the descriptors the parent will keep open out of the
+ * low descriptors preferred by C runtime buffered FILE *.
+ */
+ parent_req_write_pipe = move_fd(blocking_pipes[1]);
+ parent_resp_read_pipe = move_fd(blocking_pipes[2]);
+ /* zero is reserved to mean invalid/not open */
+ NTP_INSIST(parent_req_write_pipe != 0);
+ NTP_INSIST(parent_resp_read_pipe != 0);
+ /*
+ * wake any worker child on orderly shutdown of the
+ * daemon so that it can notice the broken pipes and
+ * go away promptly.
+ */
+ if (!atexit_installed) {
+ atexit(&send_worker_home_atexit);
+ atexit_installed = 1;
+ }
+ }
+
+#ifdef HAVE_DROPROOT
+ /* defer the fork until after root is dropped */
+ if (droproot && !root_dropped)
+ return;
+#endif
+ if (syslog_file != NULL)
+ fflush(syslog_file);
+ fflush(stdout);
+ fflush(stderr);
+
+ signal_no_reset(SIGCHLD, SIG_IGN);
+
+ childpid = fork();
+ if (-1 == childpid) {
+ msyslog(LOG_ERR, "unable to fork worker: %m");
+ exit(1);
+ }
+
+ if (childpid) {
+ /* this is the parent */
+ NLOG(NLOG_SYSEVENT)
+ msyslog(LOG_INFO,
+ "forked worker child (pid %d)",
+ childpid);
+ blocking_worker_pid = childpid;
+
+ /* close the child's pipe descriptors. */
+ close(blocking_pipes[0]);
+ close(blocking_pipes[3]);
+
+ /* wire into I/O loop */
+ update_resp_pipe_fd(parent_resp_read_pipe, 0);
+
+ return; /* parent returns */
+ }
+
+ /*
+ * In the child, close all files except stdin, stdout, stderr,
+ * and the two child ends of the pipes.
+ */
+ child_req_read_pipe = blocking_pipes[0];
+ child_resp_write_pipe = blocking_pipes[3];
+
+ kill_asyncio(0);
+ if (syslog_file != NULL) {
+ fclose(syslog_file);
+ syslog_file = NULL;
+ syslogit = 1;
+ }
+ keep_fd = max(child_req_read_pipe, child_resp_write_pipe);
+ for (fd = 3; fd < keep_fd; fd++)
+ if (fd != child_req_read_pipe &&
+ fd != child_resp_write_pipe)
+ close(fd);
+ close_all_beyond(keep_fd);
+ /*
+ * We get signals from refclock serial I/O on NetBSD in the
+ * worker if we do not reset SIGIO's handler to the default.
+ * It is not conditionalized for NetBSD alone because on
+ * systems where it is not needed, it is harmless, and that
+ * allows us to handle unknown others with NetBSD behavior.
+ * [Bug 1386]
+ */
+#if defined(USE_SIGIO)
+ signal_no_reset(SIGIO, SIG_DFL);
+#elif defined(USE_SIGPOLL)
+ signal_no_reset(SIGPOLL, SIG_DFL);
+#endif
+ signal_no_reset(SIGHUP, worker_sighup);
+ init_logging("ntpd_intres", 0);
+ setup_logfile(0);
+
+ /*
+ * And now back to the portable code
+ */
+ exit_worker(blocking_child_common());
+}
+
+/*
+ * 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, and is responsible for resetting
+ * worker_idle_timer.
+ *
+ * Note there are implementations in both work_fork.c and work_thread.c
+ * that should remain in sync.
+ */
+void
+worker_idle_timer_fired(void)
+{
+ NTP_REQUIRE(0 == intres_req_pending);
+
+ worker_idle_timer = 0;
+ blocking_worker_pid = 0;
+ close(parent_req_write_pipe);
+ parent_req_write_pipe = 0;
+ update_resp_pipe_fd(parent_resp_read_pipe, 1);
+ close(parent_resp_read_pipe);
+ parent_resp_read_pipe = 0;
+}
+
+
+#else /* !WORK_FORK follows */
+char work_fork_nonempty_compilation_unit;
+#endif
--- /dev/null
+/*
+ * work_thread.c - threads implementation for blocking worker child.
+ */
+#include <config.h>
+#include "ntp_workimpl.h"
+
+#ifdef WORK_THREAD
+
+#include <stdio.h>
+#include <ctype.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 "ntp_unixtime.h"
+#include "ntp_worker.h"
+
+#define CHILD_EXIT_REQ ((blocking_pipe_header *)(intptr_t)-1)
+
+blocking_pipe_header *blocking_workitems[24];
+blocking_pipe_header *blocking_responses[8];
+HANDLE blocking_child_thread;
+HANDLE child_is_blocking;
+HANDLE wake_blocking_child;
+HANDLE blocking_response_ready;
+HANDLE wake_scheduled_sleep;
+
+static void start_blocking_thread(void);
+unsigned WINAPI blocking_thread(void *);
+static int queue_req_pointer(blocking_pipe_header *);
+
+
+void
+exit_worker(
+ int exitcode
+ )
+{
+ _endthreadex(exitcode);
+}
+
+
+int
+worker_sleep(
+ time_t seconds
+ )
+{
+ DWORD rc;
+
+ NTP_REQUIRE(seconds * 1000 < MAXDWORD);
+ rc = WaitForSingleObject(wake_scheduled_sleep, (DWORD)seconds * 1000);
+ NTP_INSIST(WAIT_FAILED != rc);
+ return (WAIT_TIMEOUT == rc)
+ ? 0
+ : -1;
+}
+
+
+void
+interrupt_worker_sleep(void)
+{
+ SetEvent(wake_scheduled_sleep);
+}
+
+
+/*
+ * queue_req_pointer() - append a work item or idle exit request to
+ * blocking_workitems[].
+ */
+static int
+queue_req_pointer(
+ blocking_pipe_header * hdr
+ )
+{
+ static int next_workitem;
+
+ if (NULL != blocking_workitems[next_workitem]) {
+ DPRINTF(1, ("blocking_workitems full, max %d items\n",
+ COUNTOF(blocking_workitems)));
+ return -1;
+ }
+
+ blocking_workitems[next_workitem++] = hdr;
+ if (COUNTOF(blocking_workitems) == next_workitem)
+ next_workitem = 0;
+
+ /*
+ * 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(child_is_blocking, 0))
+ SetEvent(wake_blocking_child);
+
+ return 0;
+}
+
+
+int
+send_blocking_req_internal(
+ blocking_pipe_header * hdr,
+ void * data
+ )
+{
+ blocking_pipe_header * threadcopy;
+
+ NTP_REQUIRE(hdr != NULL);
+ NTP_REQUIRE(data != NULL);
+ NTP_REQUIRE(BLOCKING_REQ_MAGIC == hdr->magic_sig);
+
+ if (NULL == blocking_child_thread)
+ start_blocking_thread();
+
+ threadcopy = emalloc(hdr->octets);
+ memcpy(threadcopy, hdr, sizeof(*hdr));
+ memcpy((char *)threadcopy + sizeof(*hdr),
+ data, hdr->octets - sizeof(*hdr));
+
+ return queue_req_pointer(threadcopy);
+}
+
+
+blocking_pipe_header *
+receive_blocking_req_internal(
+ void
+ )
+{
+ static int next_workitem;
+ blocking_pipe_header *req;
+ int once;
+
+ once = 1;
+
+ /* we block here when idle */
+ if (NULL == blocking_workitems[next_workitem]) {
+ SetEvent(child_is_blocking);
+ while (NULL == blocking_workitems[next_workitem])
+ if (WAIT_OBJECT_0 !=
+ WaitForSingleObject(wake_blocking_child, INFINITE)) {
+ DPRINTF(1, ("fatal receive_blocking_req_internal wait code\n"));
+ exit(-1);
+ }
+ ResetEvent(child_is_blocking);
+ }
+
+ req = blocking_workitems[next_workitem];
+ blocking_workitems[next_workitem] = NULL;
+ next_workitem++;
+ if (next_workitem >= COUNTOF(blocking_workitems))
+ next_workitem = 0;
+
+ if (CHILD_EXIT_REQ == req) /* idled out */
+ req = NULL;
+
+ return req;
+}
+
+
+int
+send_blocking_resp_internal(
+ blocking_pipe_header *resp
+ )
+{
+ static int next_blocking_response;
+
+ if (NULL != blocking_responses[next_blocking_response]) {
+ DPRINTF(1, ("blocking_responses full, max %d items\n",
+ COUNTOF(blocking_workitems)));
+ return -1;
+ }
+
+ blocking_responses[next_blocking_response] = resp;
+ next_blocking_response++;
+ if (COUNTOF(blocking_responses) == next_blocking_response)
+ next_blocking_response = 0;
+
+ SetEvent(blocking_response_ready);
+
+ return 0;
+}
+
+
+blocking_pipe_header *
+receive_blocking_resp_internal(
+ void
+ )
+{
+ static int next_blocking_response;
+ blocking_pipe_header * retval;
+
+ retval = blocking_responses[next_blocking_response];
+
+ if (NULL != retval) {
+ blocking_responses[next_blocking_response] = NULL;
+ next_blocking_response++;
+ if (next_blocking_response == COUNTOF(blocking_responses))
+ next_blocking_response = 0;
+ NTP_ENSURE(BLOCKING_RESP_MAGIC == retval->magic_sig);
+ }
+
+ return retval;
+}
+
+
+static void
+start_blocking_thread(
+ void
+ )
+{
+ unsigned blocking_thread_id;
+
+ /*
+ * create sync events (semaphores)
+ * child_is_blocking initially unset
+ * wake_blocking_child initially unset
+ *
+ * Child waits for wake_blocking_child to be set after
+ * setting child_is_blocking. wake_blocking_child and
+ * blocking_response_ready are auto-reset, so wake one
+ * waiter and become unset (unsignalled) in one operation.
+ * blocking_response_ready is created by the IO
+ * completion port initialization code and used before
+ * any blocking requests are made.
+ */
+ if (NULL == child_is_blocking) {
+ /* manual reset using ResetEvent() */
+ child_is_blocking = CreateEvent(NULL, TRUE, FALSE, NULL);
+ /* auto reset - release from wait resets it */
+ wake_blocking_child = CreateEvent(NULL, FALSE, FALSE, NULL);
+ wake_scheduled_sleep = CreateEvent(NULL, FALSE, FALSE, NULL);
+ /*
+ * blocking_response_ready event is created in
+ * init_io_completion_port(), so it can be waited on
+ * before any blocking worker is started.
+ */
+ } else {
+ ResetEvent(child_is_blocking);
+ ResetEvent(wake_scheduled_sleep);
+ ResetEvent(wake_blocking_child);
+ ResetEvent(blocking_response_ready);
+ }
+
+ blocking_child_thread =
+ (HANDLE)_beginthreadex(
+ NULL,
+ 0,
+ blocking_thread,
+ NULL,
+ CREATE_SUSPENDED,
+ &blocking_thread_id);
+
+ if (NULL == blocking_child_thread) {
+ DPRINTF(1, ("fatal can not start blocking thread\n"));
+ exit(-1);
+ }
+ /* remember the thread priority is only within the process class */
+ if (!SetThreadPriority(blocking_child_thread,
+ THREAD_PRIORITY_BELOW_NORMAL)) {
+ DPRINTF(1, ("Error setting blocking thread priority\n"));
+ }
+
+ ResumeThread(blocking_child_thread);
+
+ /* wait for the child to set child_is_blocking the first time */
+ while (WAIT_OBJECT_0 != WaitForSingleObject(child_is_blocking, INFINITE))
+ /* null stmt */;
+}
+
+/*
+ * blocking_thread - thread functions have WINAPI calling convention
+ */
+unsigned WINAPI
+blocking_thread(
+ void *UnusedThreadArg
+ )
+{
+ UNUSED_ARG(UnusedThreadArg);
+
+ return blocking_child_common();
+}
+
+/*
+ * 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, and is responsible for resetting
+ * worker_idle_timer.
+ *
+ * Note there are implementations in both work_fork.c and work_thread.c
+ * that should remain in sync.
+ */
+void
+worker_idle_timer_fired(void)
+{
+ NTP_REQUIRE(0 == intres_req_pending);
+
+ worker_idle_timer = 0;
+ if (NULL != blocking_child_thread) {
+ queue_req_pointer(CHILD_EXIT_REQ);
+ blocking_child_thread = NULL;
+ }
+}
+
+
+#else /* !WORK_THREAD follows */
+char work_thread_nonempty_compilation_unit;
+#endif
* ntpdc-layout - print layout of NTP mode 7 request/response packets
*/
+#include <config.h>
#include <stdio.h>
#include <stddef.h>
* ntpdc - control and monitor your ntpd daemon
*/
+#include <config.h>
#include <stdio.h>
#include <stddef.h>
#include <ctype.h>
/*
- * ntpq_ops.c - subroutines which are called to perform operations by ntpq
+ * ntpq-subs.c - subroutines which are called to perform operations by ntpq
*/
-
+#include <config.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
datap += sizeof(u_short);
assoc_cache[numassoc].status = ntohs(*((u_short *)datap));
datap += sizeof(u_short);
+ if (debug)
+ fprintf(stderr, "[%u] ", assoc_cache[numassoc].assid);
if (++numassoc >= MAXASSOC)
break;
dsize -= sizeof(u_short) + sizeof(u_short);
}
+ if (debug)
+ fprintf(stderr, "\n%d associations total\n", numassoc);
sortassoc();
return 1;
}
char whenbuf[8], pollbuf[8];
char clock_name[LENHOSTNAME];
- memset((char *)havevar, 0, sizeof(havevar));
get_systime(&ts);
+ memset(havevar, 0, sizeof(havevar));
ZERO_SOCK(&srcadr);
ZERO_SOCK(&dstadr);
/* Initialize by zeroing out estimate variables */
- memset((char *)&estoffset, 0, sizeof(l_fp));
- memset((char *)&estdelay, 0, sizeof(l_fp));
- memset((char *)&estjitter, 0, sizeof(l_fp));
- memset((char *)&estdisp, 0, sizeof(l_fp));
+ memset(&estoffset, 0, sizeof(estoffset));
+ memset(&estdelay, 0, sizeof(estdelay));
+ memset(&estjitter, 0, sizeof(estjitter));
+ memset(&estdisp, 0, sizeof(estdisp));
while (nextvar(&datalen, &data, &name, &value)) {
sockaddr_u dum_store;
if (i == 0)
continue; /* don't know this one */
switch (i) {
- case CP_SRCADR:
+ case CP_SRCADR:
if (decodenetnum(value, &srcadr)) {
havevar[HAVE_SRCADR] = 1;
}
break;
- case CP_DSTADR:
+ case CP_DSTADR:
if (decodenetnum(value, &dum_store)) {
type = decodeaddrtype(&dum_store);
if (pvl == opeervarlist) {
}
}
break;
- case CP_REFID:
+ case CP_REFID:
if (pvl == peervarlist) {
havevar[HAVE_REFID] = 1;
if (*value == '\0') {
}
}
break;
- case CP_STRATUM:
+ case CP_STRATUM:
if (decodeuint(value, &stratum))
havevar[HAVE_STRATUM] = 1;
break;
- case CP_HPOLL:
+ case CP_HPOLL:
if (decodeint(value, &hpoll)) {
havevar[HAVE_HPOLL] = 1;
if (hpoll < 0)
hpoll = NTP_MINPOLL;
}
break;
- case CP_PPOLL:
+ case CP_PPOLL:
if (decodeint(value, &ppoll)) {
havevar[HAVE_PPOLL] = 1;
if (ppoll < 0)
ppoll = NTP_MINPOLL;
}
break;
- case CP_REACH:
+ case CP_REACH:
if (decodeuint(value, &reach))
havevar[HAVE_REACH] = 1;
break;
- case CP_DELAY:
+ case CP_DELAY:
if (decodetime(value, &estdelay))
havevar[HAVE_DELAY] = 1;
break;
- case CP_OFFSET:
+ case CP_OFFSET:
if (decodetime(value, &estoffset))
havevar[HAVE_OFFSET] = 1;
break;
- case CP_JITTER:
+ case CP_JITTER:
if (pvl == peervarlist)
if (decodetime(value, &estjitter))
havevar[HAVE_JITTER] = 1;
break;
- case CP_DISPERSION:
+ case CP_DISPERSION:
if (decodetime(value, &estdisp))
havevar[HAVE_DISPERSION] = 1;
break;
- case CP_REC:
+ case CP_REC:
if (decodets(value, &rec))
havevar[HAVE_REC] = 1;
break;
- case CP_SRCPORT:
+ case CP_SRCPORT:
if (decodeuint(value, &srcport))
havevar[HAVE_SRCPORT] = 1;
break;
- case CP_REFTIME:
+ case CP_REFTIME:
havevar[HAVE_REFTIME] = 1;
if (!decodets(value, &reftime))
L_CLR(&reftime);
break;
- default:
+ default:
break;
}
}
- /*
- * Check to see if the srcport is NTP's port. If not this probably
- * isn't a valid peer association.
- */
- if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT)
- return (1);
-
/*
* Got everything, format the line
*/
else
c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
if (numhosts > 1)
- (void) fprintf(fp, "%-*s ", maxhostlen, currenthost);
+ fprintf(fp, "%-*s ", maxhostlen, currenthost);
if (af == 0 || AF(&srcadr) == af) {
- strcpy(clock_name, nntohost(&srcadr));
+ strncpy(clock_name, nntohost(&srcadr), sizeof(clock_name));
- (void) fprintf(fp,
+ fprintf(fp,
"%c%-15.15s %-15.15s %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
c, clock_name, dstadr_refid, stratum, type,
prettyinterval(whenbuf, when(&ts, &rec, &reftime)),
maxhostlen = strlen(fullname);
}
if (numhosts > 1)
- (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
- (void) fprintf(fp,
- " remote refid st t when poll reach delay offset jitter\n");
+ fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
+ fprintf(fp,
+ " remote refid st t when poll reach delay offset jitter\n");
if (numhosts > 1)
for (i = 0; i <= maxhostlen; ++i)
- (void) fprintf(fp, "=");
- (void) fprintf(fp,
- "==============================================================================\n");
+ fprintf(fp, "=");
+ fprintf(fp,
+ "==============================================================================\n");
for (i = 0; i < numassoc; i++) {
if (!showall &&
- !(CTL_PEER_STATVAL(assoc_cache[i].status)
- & (CTL_PST_CONFIG|CTL_PST_REACH)))
+ !(CTL_PEER_STATVAL(assoc_cache[i].status)
+ & (CTL_PST_CONFIG|CTL_PST_REACH))) {
+ if (debug)
+ fprintf(stderr, "eliding [%d]\n", assoc_cache[i].assid);
continue;
+ }
if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp, af)) {
return;
}
/*
* ntpq - query an NTP server using mode 6 commands
*/
-
+#include <config.h>
#include <stdio.h>
#include <ctype.h>
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#include <config.h>
#include "ntpSnmpSubagentObject.h"
#include <libntpq.h>
*
****************************************************************************/
+#include <config.h>
#include <signal.h>
#include <sys/time.h>
*
*/
+#include <config.h>
#include "ntp_stdlib.h"
#include <sys/ioctl.h>
-/* config.h for Windows NT */
+/*
+ * ports/winnt/include/config.h - static Windows config.h
+ *
+ * On most systems config.h is generated by the configure script.
+ * For the Windows port, it's hand-maintained.
+ */
#ifndef CONFIG_H
#define CONFIG_H
/*
- * For newer compilers we may we want newer prototypes from Windows
- * so we target _WIN32_WINNT at WINXP, but we also want our binary to
- * run on NT 4, so newer functions are runtime linked and the linker
- * /version:0x0400 * switch is used to override the .exe file minimum
- * version. For older compilers we leave it at NT 4.0.
+ * For newer compilers we want structures and prototypes added after
+ * Windows NT 4.0 exposed by Windows header files, so we define
+ * _WIN32_WINNT to target Windows XP (version 5.1). By default,
+ * _WIN32_WINNT also controls the minimum required Windows version to
+ * launch the .exe. As we want a single binary to work on all
+ * supported Windows versions, we runtime link newer functions, and use
+ * the linker /version:0x0400 option to override the .EXE header
+ * minimum Windows version.
+ *
+ * For compilers older than VS 2005, we assume the headers will not
+ * have what we need and leave _WIN32_WINNT targetting Windows NT 4.0.
+ * This could be modified to change #if _MSC_VER > 1400 to #ifdef _W64
+ * and achieve the same result with the default SDK headers and libs
+ * included with earlier compilers, while taking advantage of newer
+ * functions if an updated SDK is installed.
*/
#ifndef _WIN32_WINNT
#if _MSC_VER > 1400 /* At least VS 2005 */
long tv_usec;
};
+/*
+ * ntohl and friends are actual functions on Windows, use our own
+ * macros instead to save the function call overhead. All releases
+ * of Windows are little-endian.
+ */
+#ifdef ntohl
+#error ntohl is already defined in ports/winnt/include/config.h
+#else
+#define ntohl(ul) (((u_long)(ul) & 0xff) << 24 | \
+ ((u_long)(ul) & 0xff00) << 8 | \
+ ((u_long)(ul) & 0xff0000) >> 8 | \
+ ((u_long)(ul) & 0xff000000) >> 24)
+#define htonl(ul) ntohl(ul)
+#define ntohs(us) ((u_short) \
+ (((u_short)(us) & 0xff) << 8 | \
+ ((u_short)(us) & 0xff00) >> 8))
+#define htons(us) ntohs(us)
+#endif
+
/*
* On Unix open() works for tty (serial) devices just fine, while on
* Windows refclock serial devices are opened using CreateFile, a lower
#endif
#define write _write
#define strdup _strdup
+#define alloca _alloca
#define stat _stat /*struct stat from <sys/stat.h> */
#define fstat _fstat
#define unlink _unlink
# define HAVE_NO_NICE
# define HAVE_MKTIME
# define HAVE_STRUCT_TIMESPEC
-# define TIME_WITH_SYS_TIME
+# define HAVE_SYS_TIME_H
# define HAVE_IO_COMPLETION_PORT
# define ISC_PLATFORM_NEEDNTOP
# define ISC_PLATFORM_NEEDPTON
*/
#include <isc/stat.h>
-#endif /* CONFIG_H */
+#endif /* CONFIG_H */
#ifndef SYS_TIME_H
#define SYS_TIME_H
-#include <config.h>
-#include <windows.h>
#include "ntp_types.h"
#include <time.h>
#include <sys/timeb.h>
#define WIN32_IO_H
extern void InitSockets(void);
-void connection_reset_fix(SOCKET fd, sockaddr_u *addr)
+extern void connection_reset_fix(SOCKET fd, sockaddr_u *addr);
-#endif /* defined WIN32_IO_H */
-;
+#endif /* WIN32_IO_H */
+#include <config.h>
#include "clockstuff.h"
#include "ntp_stdlib.h"
#include "clockstuff.h"
#include "ntservice.h"
#include "ntpd.h"
-#include "../../../ntpd/ntpd-opts.h"
+#include "ntpd-opts.h"
extern double sys_residual; /* residual from previous adjustment */
#define WAITABLEIOEVENTHANDLE NULL
#endif
-#define MAXHANDLES 3
-HANDLE WaitHandles[MAXHANDLES] = { NULL, NULL, NULL };
+#define MAXHANDLES 4
+HANDLE WaitHandles[MAXHANDLES];
IoCompletionInfo *
GetHeapAlloc(char *fromfunc)
exit(1);
}
+ blocking_response_ready = CreateEvent(NULL, FALSE, FALSE, NULL);
+
/*
* Initialize the Wait Handles
*/
WaitHandles[0] = WaitableIoEventHandle;
WaitHandles[1] = WaitableExitEventHandle; /* exit request */
WaitHandles[2] = get_timer_handle();
+ WaitHandles[3] = blocking_response_ready;
/* Have one thread servicing I/O - there were 4, but this would
* somehow cause NTP to stop replying to ntpq requests; TODO
while (!have_packet) {
DWORD Index = WaitForMultipleObjects(MAXHANDLES, WaitHandles, FALSE, INFINITE);
switch (Index) {
- case WAIT_OBJECT_0 + 0 : /* Io event */
-# ifdef DEBUG
- if ( debug > 3 )
- {
- printf( "IoEvent occurred\n" );
- }
-# endif
+ case WAIT_OBJECT_0 + 0: /* Io event */
+ DPRINTF(4, ("IoEvent occurred\n"));
have_packet = ISC_TRUE;
break;
- case WAIT_OBJECT_0 + 1 : /* exit request */
+ case WAIT_OBJECT_0 + 1: /* exit request */
exit(0);
break;
- case WAIT_OBJECT_0 + 2 : /* timer */
+ case WAIT_OBJECT_0 + 2: /* timer */
timer();
break;
- case WAIT_IO_COMPLETION : /* loop */
- case WAIT_TIMEOUT :
+ case WAIT_OBJECT_0 + 3: /* blocking response */
+ process_blocking_response();
+ break;
+ case WAIT_IO_COMPLETION: /* loop */
+ break;
+ case WAIT_TIMEOUT:
+ msyslog(LOG_ERR, "ntpd: WaitForMultipleObjects INFINITE timed out.");
+ exit(1);
break;
case WAIT_FAILED:
msyslog(LOG_ERR, "ntpd: WaitForMultipleObjects Failed: Error: %m");
+ exit(1);
break;
/* For now do nothing if not expected */
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\..\ntpd\ntp_worker.c\r
+# SUBTRACT CPP /YX\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE="..\..\..\ntpd\ntpd-opts.c"\r
# End Source File\r
# Begin Source File\r
# Begin Source File\r
\r
SOURCE=..\ntpd\ntservice.c\r
+# SUBTRACT CPP /YX\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\ntpd\work_fork.c\r
+# SUBTRACT CPP /YX\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\..\ntpd\work_thread.c\r
+# SUBTRACT CPP /YX\r
+# End Source File\r
+\r
# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
# Begin Source File\r
\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\..\..\include\ntp_worker.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\..\include\ntp_workimpl.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE="..\..\..\ntpd\ntpd-opts.h"\r
# End Source File\r
# Begin Source File\r
BrowseInformation="1"/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\ntpd\ntp_worker.c">
+ </File>
<File
RelativePath="..\..\..\ntpd\ntpd-opts.c">
<FileConfiguration
BrowseInformation="1"/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\ntpd\work_fork.c">
+ </File>
+ <File
+ RelativePath="..\..\..\ntpd\work_thread.c">
+ </File>
</Filter>
<Filter
Name="Header Files"
<File
RelativePath="..\..\..\include\ntp_unixtime.h">
</File>
+ <File
+ RelativePath="..\..\..\include\ntp_worker.h">
+ </File>
+ <File
+ RelativePath="..\..\..\include\ntp_workimpl.h">
+ </File>
<File
RelativePath="..\..\..\ntpd\ntpd-opts.h">
</File>
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\ntpd\ntp_worker.c"
+ >
+ </File>
<File
RelativePath="..\..\..\ntpd\ntpd-opts.c"
>
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\ntpd\work_fork.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\ntpd\work_thread.c"
+ >
+ </File>
</Filter>
<Filter
Name="Header Files"
RelativePath="..\..\..\include\ntp_unixtime.h"
>
</File>
+ <File
+ RelativePath="..\..\..\include\ntp_worker.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\include\ntp_workimpl.h"
+ >
+ </File>
<File
RelativePath="..\..\..\ntpd\ntpd-opts.h"
>
RelativePath="..\..\..\..\libntp\humandate.c"
>
</File>
+ <File
+ RelativePath="..\..\..\..\libntp\icom.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
<File
RelativePath="..\..\..\..\lib\isc\inet_aton.c"
>
RelativePath="..\..\..\..\lib\isc\win32\stdtime.c"
>
</File>
+ <File
+ RelativePath="..\..\..\..\libntp\strdup.c"
+ >
+ </File>
<File
RelativePath="..\..\..\..\lib\isc\win32\strerror.c"
>
</File>
+ <File
+ RelativePath="..\..\..\..\libntp\strstr.c"
+ >
+ </File>
<File
RelativePath="..\..\libntp\syslog.c"
>
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\..\ntpd\ntp_worker.c"
+ >
+ </File>
<File
RelativePath="..\..\..\..\ntpd\ntpd-opts.c"
>
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\..\ntpd\ntpsim.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
<File
RelativePath="..\..\ntpd\ntservice.c"
>
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\..\ntpd\work_fork.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\ntpd\work_thread.c"
+ >
+ </File>
</Filter>
<Filter
Name="Header Files"
RelativePath="..\..\..\..\include\ntp_control.h"
>
</File>
+ <File
+ RelativePath="..\..\..\..\include\ntp_data_structures.h"
+ >
+ </File>
<File
RelativePath="..\..\..\..\include\ntp_debug.h"
>
RelativePath="..\..\..\..\include\ntp_unixtime.h"
>
</File>
+ <File
+ RelativePath="..\..\..\..\include\ntp_worker.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\include\ntp_workimpl.h"
+ >
+ </File>
<File
RelativePath="..\..\..\..\ntpd\ntpd-opts.h"
>
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\..\ntpd\refclock_ripencc.c"
+ >
+ </File>
<File
RelativePath="..\..\..\..\ntpd\refclock_shm.c"
>
<Filter
Name="Parse Lib"
>
+ <File
+ RelativePath="..\..\..\..\libparse\binio.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
<File
RelativePath="..\..\..\..\libparse\clk_computime.c"
>
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\..\libparse\gpstolfp.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\..\libparse\ieee754io.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\..\libparse\info_trimble.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\..\libparse\mfp_mul.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
<File
RelativePath="..\..\..\..\libparse\parse.c"
>
/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\..\..\libparse\parsesolaris.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\..\libparse\parsestreams.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\..\libparse\trim_info.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
</Filter>
<File
RelativePath="..\..\scripts\mkver.bat"
+#include <config.h>
#include "crypto.h"
struct key *key_ptr;
+#include <config.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <config.h>
#include "log.h"
#include "sntp-opts.h"
+#include <config.h>
#include <l_stdlib.h>
#include <ntp_fp.h>
#include <ntp.h>
+#include <config.h>
#include "networking.h"
char adr_buf[INET6_ADDRSTRLEN];
+#include <config.h>
#include "utilities.h"
/* Display a NTP packet in hex with leading address offset