From: Dave Hart Date: Wed, 27 Jan 2010 18:45:33 +0000 (+0000) Subject: [Bug 47] Debugging and logging do not work after a fork. X-Git-Tag: NTP_4_2_7P11~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=72f11084c274d2a8994c3d4f5690354a8b1842bf;p=thirdparty%2Fntp.git [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. #include from all .c files and do not include it from any .h files. Previously config.h appeared a dozen times in preprocessed output of some .c files. handle relative path to logfile correctly despite re-opening after fork() with a different curdir. eliminate hand-crafted byte-swapping code from refclock_palisade.c in preference to using htonl(), htons(). Tested by Fernando Hauscarriaga. bk: 4b6089cdjX3Zx7Mvzyik8kkO9L7RTA --- diff --git a/ChangeLog b/ChangeLog index b35a251d6..ef4bcb925 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +* [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 * [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 diff --git a/configure.ac b/configure.ac index 392b5c36c..a09ec3394 100644 --- a/configure.ac +++ b/configure.ac @@ -128,6 +128,7 @@ esac LIBOPTS_CHECK(libopts) AC_FUNC_FORK +AC_FUNC_ALLOCA AC_CACHE_CHECK( [if $CC can handle @%:@warning], @@ -1168,7 +1169,7 @@ case "$host" in 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 ]) @@ -1366,9 +1367,24 @@ case "$host" in *-*-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... @@ -2114,22 +2130,6 @@ case "$ans" in 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 diff --git a/include/Makefile.am b/include/Makefile.am index 80113226c..949d6920e 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -56,6 +56,8 @@ noinst_HEADERS = \ ntp_tty.h \ ntp_types.h \ ntp_unixtime.h \ + ntp_worker.h \ + ntp_workimpl.h \ ntpd.h \ ntpsim.h \ parse.h \ diff --git a/include/iosignal.h b/include/iosignal.h index 6c4052b7f..632ae7e02 100644 --- a/include/iosignal.h +++ b/include/iosignal.h @@ -1,9 +1,38 @@ -#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 *); @@ -14,10 +43,9 @@ RETSIGTYPE sigio_handler (int); # 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 */ diff --git a/include/l_stdlib.h b/include/l_stdlib.h index 0213d23c1..81e8f9e77 100644 --- a/include/l_stdlib.h +++ b/include/l_stdlib.h @@ -3,12 +3,8 @@ * This is optional */ -#ifndef _l_stdlib_h -#define _l_stdlib_h - -#ifdef HAVE_CONFIG_H -#include -#endif +#ifndef L_STDLIB_H +#define L_STDLIB_H #ifdef HAVE_STDLIB_H # include @@ -111,7 +107,7 @@ extern int rename (const char *, const char *); #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 @@ -235,4 +231,4 @@ extern int errno; extern int h_errno; #endif -#endif /* l_stdlib_h */ +#endif /* L_STDLIB_H */ diff --git a/include/ntp_data_structures.h b/include/ntp_data_structures.h index 363e0b47a..bf970a23a 100644 --- a/include/ntp_data_structures.h +++ b/include/ntp_data_structures.h @@ -4,14 +4,14 @@ * 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 @@ -25,29 +25,55 @@ typedef struct node { } 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 */ diff --git a/include/ntp_fp.h b/include/ntp_fp.h index 63b0f5dfb..de0919e74 100644 --- a/include/ntp_fp.h +++ b/include/ntp_fp.h @@ -342,12 +342,12 @@ extern int buftvtots (const char *, l_fp *); 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); diff --git a/include/ntp_intres.h b/include/ntp_intres.h index 53c8a63a4..fe63409a3 100644 --- a/include/ntp_intres.h +++ b/include/ntp_intres.h @@ -1,14 +1,23 @@ #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 */ diff --git a/include/ntp_io.h b/include/ntp_io.h index 692d4440f..685524895 100644 --- a/include/ntp_io.h +++ b/include/ntp_io.h @@ -1,13 +1,12 @@ #ifndef NTP_IO_H #define NTP_IO_H + +#include "ntp_workimpl.h" + /* * POSIX says use to get O_* symbols and * SEEK_SET symbol form . */ -#ifdef HAVE_CONFIG_H -# include -#endif - #include #ifdef HAVE_UNISTD_H # include @@ -69,7 +68,6 @@ typedef enum { MATCH_IFADDR } nic_rule_match; - /* * NIC rule actions */ @@ -80,10 +78,18 @@ typedef enum { } 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 */ diff --git a/include/ntp_lists.h b/include/ntp_lists.h index 2bac38a52..218b8fe40 100644 --- a/include/ntp_lists.h +++ b/include/ntp_lists.h @@ -38,10 +38,6 @@ #ifndef NTP_LISTS_H #define NTP_LISTS_H -#ifdef HAVE_CONFIG_H -# include -#endif - #include diff --git a/include/ntp_machine.h b/include/ntp_machine.h index 73fd172a2..4e4e4b15a 100644 --- a/include/ntp_machine.h +++ b/include/ntp_machine.h @@ -1,14 +1,15 @@ /* + * 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 -#endif - #ifdef TIME_WITH_SYS_TIME # include # include @@ -26,9 +27,6 @@ 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. @@ -84,141 +82,6 @@ MISC # 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 -# include -# include -#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 @@ -502,34 +365,7 @@ extern time_t timegm (struct tm *); && !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 */ diff --git a/include/ntp_malloc.h b/include/ntp_malloc.h index 0dbcbeed4..9203c53f0 100644 --- a/include/ntp_malloc.h +++ b/include/ntp_malloc.h @@ -4,10 +4,6 @@ #ifndef NTP_MALLOC_H #define NTP_MALLOC_H -#ifdef HAVE_CONFIG_H -# include -#endif - #ifdef HAVE_STDLIB_H # include #else @@ -16,4 +12,33 @@ # 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 +#elif defined __GNUC__ +# ifndef alloca +# define alloca __builtin_alloca +# endif +#elif defined _AIX +# ifndef alloca +# define alloca __alloca +# endif +#elif defined _MSC_VER +# include +# ifndef alloca +# define alloca _alloca +# endif +#else +# include +void * alloca(size_t); +#endif + #endif /* NTP_MALLOC_H */ diff --git a/include/ntp_proto.h b/include/ntp_proto.h index e6e785533..1d04b78ab 100644 --- a/include/ntp_proto.h +++ b/include/ntp_proto.h @@ -1,10 +1,6 @@ -#ifndef __ntp_proto_h -#define __ntp_proto_h - -#ifdef HAVE_CONFIG_H -#include -#endif +#ifndef NTP_PROTO_H +#define NTP_PROTO_H #define NTP_MAXFREQ 500e-6 -#endif /* __ntp_proto_h */ +#endif /* NTP_PROTO_H */ diff --git a/include/ntp_rfc2553.h b/include/ntp_rfc2553.h index 4ed1b657c..703e972a9 100644 --- a/include/ntp_rfc2553.h +++ b/include/ntp_rfc2553.h @@ -68,11 +68,6 @@ #ifndef NTP_RFC2553_H #define NTP_RFC2553_H -/* - * Ensure that we include the configuration file before we check - * for IPV6 - */ -#include #include #include diff --git a/include/ntp_select.h b/include/ntp_select.h index dc60f70b3..2c0fbeec9 100644 --- a/include/ntp_select.h +++ b/include/ntp_select.h @@ -2,39 +2,34 @@ * 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 -#else -#include -extern int select (int width, fd_set *pReadFds, fd_set *pWriteFds, - fd_set *pExceptFds, struct timeval *pTimeOut); - -#endif +# ifndef SYS_VXWORKS +# include +# else +# include +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 */ diff --git a/include/ntp_stdlib.h b/include/ntp_stdlib.h index f2024fb16..f88965eb0 100644 --- a/include/ntp_stdlib.h +++ b/include/ntp_stdlib.h @@ -10,7 +10,6 @@ #endif #include "l_stdlib.h" -#include "ntp_rfc2553.h" #include "ntp_types.h" #include "ntp_string.h" #include "ntp_net.h" @@ -88,6 +87,7 @@ extern int atoint (const char *, long *); 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); diff --git a/include/ntp_string.h b/include/ntp_string.h index aab7084b0..b96802437 100644 --- a/include/ntp_string.h +++ b/include/ntp_string.h @@ -2,12 +2,8 @@ * Define string ops: strchr strrchr memcmp memmove memset */ -#ifndef _ntp_string_h -#define _ntp_string_h - -#ifdef HAVE_CONFIG_H -#include -#endif +#ifndef NTP_STRING_H +#define NTP_STRING_H #ifdef HAVE_MEMORY_H # include @@ -52,4 +48,4 @@ void ntp_memset (char *, int, int); ntp_memset((char *)(a), x, c) #endif /* NTP_NEED_BOPS */ -#endif /* _ntp_string_h */ +#endif /* NTP_STRING_H */ diff --git a/include/ntp_syscall.h b/include/ntp_syscall.h index c255cee46..df2452caa 100644 --- a/include/ntp_syscall.h +++ b/include/ntp_syscall.h @@ -6,10 +6,6 @@ #ifndef NTP_SYSCALL_H #define NTP_SYSCALL_H -#ifdef HAVE_CONFIG_H -#include -#endif - #ifdef HAVE_SYS_TIMEX_H # include #endif diff --git a/include/ntp_syslog.h b/include/ntp_syslog.h index 38021e251..3e486b517 100644 --- a/include/ntp_syslog.h +++ b/include/ntp_syslog.h @@ -5,17 +5,19 @@ #ifndef NTP_SYSLOG_H #define NTP_SYSLOG_H -# ifdef VMS +#ifdef VMS extern void msyslog(); -# else -# ifndef SYS_VXWORKS -# include -# endif -# endif /* VMS */ -# include +#else +# ifndef SYS_VXWORKS +# include +# endif +#endif /* VMS */ +#include -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 */ diff --git a/include/ntp_types.h b/include/ntp_types.h index ed6a2ca4b..c526df0af 100644 --- a/include/ntp_types.h +++ b/include/ntp_types.h @@ -49,23 +49,23 @@ typedef unsigned int u_int; #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; diff --git a/include/ntp_worker.h b/include/ntp_worker.h new file mode 100644 index 000000000..23032587c --- /dev/null +++ b/include/ntp_worker.h @@ -0,0 +1,52 @@ +/* + * 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 */ diff --git a/include/ntp_workimpl.h b/include/ntp_workimpl.h new file mode 100644 index 000000000..ddba76a74 --- /dev/null +++ b/include/ntp_workimpl.h @@ -0,0 +1,25 @@ +/* + * 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 */ diff --git a/include/ntpd.h b/include/ntpd.h index 10fb7d057..3c5e4a617 100644 --- a/include/ntpd.h +++ b/include/ntpd.h @@ -9,6 +9,7 @@ #include "ntp_select.h" #include "ntp_malloc.h" #include "ntp_refclock.h" +#include "ntp_workimpl.h" #include "recvbuff.h" /* ntp_config.c */ @@ -24,8 +25,9 @@ extern u_short ctlpeerstatus (struct peer *); 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 *); @@ -53,18 +55,33 @@ struct ctl_var { #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 { @@ -221,14 +238,15 @@ extern void init_timer (void); 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 */ @@ -247,10 +265,22 @@ extern void record_timing_stats (const char *); #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. @@ -300,17 +330,6 @@ extern u_long numctldatatooshort; /* data too short for count */ 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 */ @@ -470,20 +489,31 @@ extern u_long timer_overflows; 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 */ diff --git a/include/recvbuff.h b/include/recvbuff.h index 1fdc54a4d..efb637fdb 100644 --- a/include/recvbuff.h +++ b/include/recvbuff.h @@ -1,10 +1,6 @@ #ifndef RECVBUFF_H #define RECVBUFF_H -#ifdef HAVE_CONFIG_H -# include -#endif - #include "ntp.h" #include "ntp_fp.h" #include "ntp_lists.h" @@ -21,7 +17,7 @@ #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) diff --git a/libntp/atoint.c b/libntp/atoint.c index 46cd96d19..1064b366a 100644 --- a/libntp/atoint.c +++ b/libntp/atoint.c @@ -1,6 +1,7 @@ /* * atoint - convert an ascii string to a signed long, with error checking */ +#include #include #include diff --git a/libntp/atolfp.c b/libntp/atolfp.c index adb67936f..4afeb23d3 100644 --- a/libntp/atolfp.c +++ b/libntp/atolfp.c @@ -1,6 +1,7 @@ /* * atolfp - convert an ascii string to an l_fp number */ +#include #include #include diff --git a/libntp/atouint.c b/libntp/atouint.c index c25e3a0c5..98f6671d9 100644 --- a/libntp/atouint.c +++ b/libntp/atouint.c @@ -1,6 +1,7 @@ /* * atouint - convert an ascii string to an unsigned long, with error checking */ +#include #include #include diff --git a/libntp/authusekey.c b/libntp/authusekey.c index bef7b8473..ba7a0a18d 100644 --- a/libntp/authusekey.c +++ b/libntp/authusekey.c @@ -1,6 +1,7 @@ /* * authusekey - decode a key from ascii and use it */ +#include #include #include diff --git a/libntp/caljulian.c b/libntp/caljulian.c index 7673061b5..9c44277a1 100644 --- a/libntp/caljulian.c +++ b/libntp/caljulian.c @@ -1,6 +1,7 @@ /* * caljulian - determine the Julian date from an NTP time. */ +#include #include #include "ntp_types.h" diff --git a/libntp/caltontp.c b/libntp/caltontp.c index 9c4136842..9e7aa99e2 100644 --- a/libntp/caltontp.c +++ b/libntp/caltontp.c @@ -1,6 +1,7 @@ /* * caltontp - convert a date to an NTP time */ +#include #include #include "ntp_types.h" diff --git a/libntp/calyearstart.c b/libntp/calyearstart.c index c5a63f729..c0925c149 100644 --- a/libntp/calyearstart.c +++ b/libntp/calyearstart.c @@ -2,6 +2,7 @@ * calyearstart - determine the NTP time at midnight of January 1 in * the year of the given date. */ +#include #include #include "ntp_types.h" diff --git a/libntp/clocktime.c b/libntp/clocktime.c index 371859cda..6133f0003 100644 --- a/libntp/clocktime.c +++ b/libntp/clocktime.c @@ -2,6 +2,7 @@ * clocktime - compute the NTP date from a day of year, hour, minute * and second. */ +#include #include "ntp_fp.h" #include "ntp_unixtime.h" #include "ntp_stdlib.h" diff --git a/libntp/clocktypes.c b/libntp/clocktypes.c index 4459830ed..c9e242e67 100644 --- a/libntp/clocktypes.c +++ b/libntp/clocktypes.c @@ -1,6 +1,7 @@ /* * Data for pretty printing clock types */ +#include #include #include "ntp_fp.h" diff --git a/libntp/dofptoa.c b/libntp/dofptoa.c index 0f96909f1..1d60fe939 100644 --- a/libntp/dofptoa.c +++ b/libntp/dofptoa.c @@ -1,6 +1,7 @@ /* * dofptoa - do the grunge work to convert an fp number to ascii */ +#include #include #include "ntp_fp.h" diff --git a/libntp/dolfptoa.c b/libntp/dolfptoa.c index f68679cf0..865da9159 100644 --- a/libntp/dolfptoa.c +++ b/libntp/dolfptoa.c @@ -1,6 +1,7 @@ /* * dolfptoa - do the grunge work of converting an l_fp number to decimal */ +#include #include #include "ntp_fp.h" diff --git a/libntp/emalloc.c b/libntp/emalloc.c index 5c40f4ee0..63761305c 100644 --- a/libntp/emalloc.c +++ b/libntp/emalloc.c @@ -1,6 +1,7 @@ /* * emalloc - return new memory obtained from the system. Belch if none. */ +#include #include "ntp_types.h" #include "ntp_malloc.h" #include "ntp_syslog.h" diff --git a/libntp/fptoa.c b/libntp/fptoa.c index 025ad21e5..771c6dfce 100644 --- a/libntp/fptoa.c +++ b/libntp/fptoa.c @@ -1,6 +1,7 @@ /* * fptoa - return an asciized representation of an s_fp number */ +#include #include "ntp_fp.h" #include "ntp_stdlib.h" diff --git a/libntp/fptoms.c b/libntp/fptoms.c index 0bfca5556..9a1ab77ac 100644 --- a/libntp/fptoms.c +++ b/libntp/fptoms.c @@ -1,6 +1,7 @@ /* * fptoms - return an asciized s_fp number in milliseconds */ +#include #include "ntp_fp.h" char * diff --git a/libntp/getopt.c b/libntp/getopt.c index 7b344f0dc..63c82faa6 100644 --- a/libntp/getopt.c +++ b/libntp/getopt.c @@ -13,6 +13,7 @@ /*LINTLIBRARY*/ +#include #include #include "ntp_stdlib.h" diff --git a/libntp/hextoint.c b/libntp/hextoint.c index a2e8c043f..d24b5a0bf 100644 --- a/libntp/hextoint.c +++ b/libntp/hextoint.c @@ -2,6 +2,7 @@ * hextoint - convert an ascii string in hex to an unsigned * long, with error checking */ +#include #include #include "ntp_stdlib.h" diff --git a/libntp/hextolfp.c b/libntp/hextolfp.c index d0b624340..8fbce2e5b 100644 --- a/libntp/hextolfp.c +++ b/libntp/hextolfp.c @@ -1,6 +1,7 @@ /* * hextolfp - convert an ascii hex string to an l_fp number */ +#include #include #include diff --git a/libntp/humandate.c b/libntp/humandate.c index e3614cf20..008152263 100644 --- a/libntp/humandate.c +++ b/libntp/humandate.c @@ -1,6 +1,7 @@ /* * humandate - convert an NTP (or the current) time to something readable */ +#include #include #include "ntp_fp.h" #include "ntp_unixtime.h" /* includes and */ @@ -15,19 +16,45 @@ extern const char *months[]; /* prettydate.c */ 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; } diff --git a/libntp/icom.c b/libntp/icom.c index 557fc06ae..f45a591fe 100644 --- a/libntp/icom.c +++ b/libntp/icom.c @@ -5,6 +5,7 @@ * distribution. The only function provided is to load the radio * frequency. All other parameters must be manually set before use. */ +#include #include "icom.h" #include #include diff --git a/libntp/iosignal.c b/libntp/iosignal.c index 5859e40e0..b10a161e9 100644 --- a/libntp/iosignal.c +++ b/libntp/iosignal.c @@ -65,34 +65,6 @@ extern void input_handler (l_fp *); * 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 */ /* diff --git a/libntp/mfptoa.c b/libntp/mfptoa.c index 6450b2c13..af83d00be 100644 --- a/libntp/mfptoa.c +++ b/libntp/mfptoa.c @@ -1,6 +1,7 @@ /* * mfptoa - Return an asciized representation of a signed long fp number */ +#include #include "ntp_fp.h" #include "ntp_stdlib.h" diff --git a/libntp/mfptoms.c b/libntp/mfptoms.c index d2bfd71ee..678eacc11 100644 --- a/libntp/mfptoms.c +++ b/libntp/mfptoms.c @@ -1,6 +1,7 @@ /* * mfptoms - Return an asciized signed long fp number in milliseconds */ +#include #include "ntp_fp.h" #include "ntp_stdlib.h" diff --git a/libntp/mktime.c b/libntp/mktime.c index 91be60015..2ba9ed85a 100644 --- a/libntp/mktime.c +++ b/libntp/mktime.c @@ -59,6 +59,7 @@ * by hand. Sorry about that. */ +#include #include "ntp_machine.h" #if !defined(HAVE_MKTIME) || !defined(HAVE_TIMEGM) diff --git a/libntp/modetoa.c b/libntp/modetoa.c index 405aef855..6515880f4 100644 --- a/libntp/modetoa.c +++ b/libntp/modetoa.c @@ -1,6 +1,7 @@ /* * modetoa - return an asciized mode */ +#include #include #include "lib_strbuf.h" diff --git a/libntp/mstolfp.c b/libntp/mstolfp.c index e4e909df7..1a1a02b5f 100644 --- a/libntp/mstolfp.c +++ b/libntp/mstolfp.c @@ -1,6 +1,7 @@ /* * mstolfp - convert an ascii string in milliseconds to an l_fp number */ +#include #include #include diff --git a/libntp/msutotsf.c b/libntp/msutotsf.c index eb3babe9c..2182d9f26 100644 --- a/libntp/msutotsf.c +++ b/libntp/msutotsf.c @@ -2,6 +2,7 @@ * msutotsf - tables for converting from a subsecond millisecond value * to a time stamp fraction. */ +#include #include #include "ntp_types.h" diff --git a/libntp/msyslog.c b/libntp/msyslog.c index 43466b81c..78a0f67fa 100644 --- a/libntp/msyslog.c +++ b/libntp/msyslog.c @@ -28,15 +28,12 @@ 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 */ @@ -50,32 +47,45 @@ void format_errmsg (char *, int, const char *, int); 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) { @@ -106,26 +116,18 @@ 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; diff --git a/libntp/netof.c b/libntp/netof.c index 55a4092be..edd65c931 100644 --- a/libntp/netof.c +++ b/libntp/netof.c @@ -2,6 +2,7 @@ * netof - return the net address part of an ip address in a sockaddr_storage structure * (zero out host part) */ +#include #include #include diff --git a/libntp/octtoint.c b/libntp/octtoint.c index f792b2bd6..d189e40c4 100644 --- a/libntp/octtoint.c +++ b/libntp/octtoint.c @@ -2,6 +2,7 @@ * octtoint - convert an ascii string in octal to an unsigned * long, with error checking */ +#include #include #include diff --git a/libntp/prettydate.c b/libntp/prettydate.c index 09f358fe5..806bffb9c 100644 --- a/libntp/prettydate.c +++ b/libntp/prettydate.c @@ -1,6 +1,7 @@ /* * prettydate - convert a time stamp to something readable */ +#include #include #include "ntp_fp.h" diff --git a/libntp/refnumtoa.c b/libntp/refnumtoa.c index c52bc28b6..32bdc6979 100644 --- a/libntp/refnumtoa.c +++ b/libntp/refnumtoa.c @@ -1,6 +1,7 @@ /* * refnumtoa - return asciized refclock addresses stored in local array space */ +#include #include #include "ntp_net.h" diff --git a/libntp/socktohost.c b/libntp/socktohost.c index 325eea40d..8120b91fa 100644 --- a/libntp/socktohost.c +++ b/libntp/socktohost.c @@ -1,6 +1,7 @@ /* * socktoa - return a numeric host name from a sockaddr_storage structure */ +#include #include #ifdef HAVE_SYS_SOCKET_H #include diff --git a/libntp/strdup.c b/libntp/strdup.c index 2e26ba7a5..7d23d7e5d 100644 --- a/libntp/strdup.c +++ b/libntp/strdup.c @@ -1,3 +1,4 @@ +#include #include "ntp_malloc.h" #if !HAVE_STRDUP diff --git a/libntp/syssignal.c b/libntp/syssignal.c index 68099f5fb..983e930ab 100644 --- a/libntp/syssignal.c +++ b/libntp/syssignal.c @@ -9,67 +9,59 @@ #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 @@ -77,16 +69,16 @@ signal_no_reset( 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); } @@ -97,13 +89,13 @@ signal_no_reset( 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); } @@ -115,16 +107,13 @@ signal_no_reset( 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); } diff --git a/libntp/systime.c b/libntp/systime.c index e45c4d626..da5a54c3b 100644 --- a/libntp/systime.c +++ b/libntp/systime.c @@ -4,6 +4,7 @@ * ATTENTION: Get approval from Dave Mills on all changes to this file! * */ +#include #include "ntp_machine.h" #include "ntp_fp.h" #include "ntp_syslog.h" diff --git a/libntp/tsftomsu.c b/libntp/tsftomsu.c index 5926aabc7..2d8c6084a 100644 --- a/libntp/tsftomsu.c +++ b/libntp/tsftomsu.c @@ -1,6 +1,7 @@ /* * tsftomsu - convert from a time stamp fraction to milliseconds */ +#include #include "ntp_fp.h" #include "ntp_stdlib.h" diff --git a/libntp/tstotv.c b/libntp/tstotv.c index be4bdd441..278dadfd0 100644 --- a/libntp/tstotv.c +++ b/libntp/tstotv.c @@ -2,6 +2,7 @@ * tstotv - tables for converting from NTP time stamps to struct timeval */ +#include #include "ntp_types.h" /* diff --git a/libntp/tvtots.c b/libntp/tvtots.c index 0bd2b6911..3983e28f1 100644 --- a/libntp/tvtots.c +++ b/libntp/tvtots.c @@ -2,6 +2,7 @@ * tvtots - tables for converting from Unix struct timeval's to * NTP time stamp format. */ +#include #include #include "ntp_types.h" diff --git a/libntp/uglydate.c b/libntp/uglydate.c index 676a5fdde..ce21be621 100644 --- a/libntp/uglydate.c +++ b/libntp/uglydate.c @@ -2,6 +2,7 @@ * uglydate - convert a time stamp to something barely readable * The string returned is 37 characters long. */ +#include #include #include "ntp_fp.h" diff --git a/libntp/uinttoa.c b/libntp/uinttoa.c index be48ea514..f1925f4bf 100644 --- a/libntp/uinttoa.c +++ b/libntp/uinttoa.c @@ -1,6 +1,7 @@ /* * uinttoa - return an asciized unsigned integer */ +#include #include #include "lib_strbuf.h" @@ -14,7 +15,7 @@ uinttoa( register char *buf; LIB_GETBUF(buf); + snprintf(buf, LIB_BUFLENGTH, "%lu", uval); - (void) sprintf(buf, "%lu", (u_long)uval); return buf; } diff --git a/libntp/ymd2yd.c b/libntp/ymd2yd.c index 796ce4094..5a9d4c3e3 100644 --- a/libntp/ymd2yd.c +++ b/libntp/ymd2yd.c @@ -2,6 +2,7 @@ * ymd2yd - compute the date in the year from y/m/d */ +#include #include "ntp_fp.h" #include "ntp_unixtime.h" #include "ntp_stdlib.h" diff --git a/libparse/Makefile.am b/libparse/Makefile.am index 12b47967d..d18c61f26 100644 --- a/libparse/Makefile.am +++ b/libparse/Makefile.am @@ -1,15 +1,37 @@ 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 \ @@ -24,7 +46,7 @@ libparse_a_SOURCES = parse.c \ clk_wharton.c \ clk_varitext.c \ data_mbg.c \ - info_trimble.c \ + $(srcdir)/info_trimble.c \ trim_info.c \ binio.c \ ieee754io.c \ @@ -62,104 +84,74 @@ ETAGS_ARGS = Makefile.am 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 @@ -172,7 +164,7 @@ parse: $(parsesolaris_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 diff --git a/libparse/binio.c b/libparse/binio.c index 2f8546b4a..1d3ea2c79 100644 --- a/libparse/binio.c +++ b/libparse/binio.c @@ -33,6 +33,7 @@ * */ +#include #include "binio.h" long diff --git a/libparse/data_mbg.c b/libparse/data_mbg.c index 991f1e90e..65534b05c 100644 --- a/libparse/data_mbg.c +++ b/libparse/data_mbg.c @@ -33,6 +33,7 @@ * */ +#include #ifdef PARSESTREAM #define NEED_BOPS #include "ntp_string.h" diff --git a/libparse/gpstolfp.c b/libparse/gpstolfp.c index 9f1a9bfd6..5354dd322 100644 --- a/libparse/gpstolfp.c +++ b/libparse/gpstolfp.c @@ -32,6 +32,7 @@ * SUCH DAMAGE. * */ +#include #include "ntp_fp.h" #define GPSORIGIN 2524953600UL /* NTP origin - GPS origin in seconds */ diff --git a/libparse/info_trimble.c b/libparse/info_trimble.c index eea6cbd3f..6456e0f9f 100644 --- a/libparse/info_trimble.c +++ b/libparse/info_trimble.c @@ -2,6 +2,7 @@ * Automatically generated - do not modify */ +#include #include "ntp_types.h" #include "ntpd.h" #include "trimble.h" @@ -91,4 +92,3 @@ cmd_info_t trimble_rcmds[] = { { CMD_RSUPER, "CMD_RSUPER", "super paket (0x8F)", "", 0 }, { 0xFF, "", "" } }; - diff --git a/libparse/mfp_mul.c b/libparse/mfp_mul.c index 677ed181f..43c1e39fa 100644 --- a/libparse/mfp_mul.c +++ b/libparse/mfp_mul.c @@ -32,6 +32,7 @@ * SUCH DAMAGE. * */ +#include #include #include "ntp_stdlib.h" #include "ntp_types.h" diff --git a/libparse/mkinfo_rcmd.sed b/libparse/mkinfo_rcmd.sed index 570c7a0b8..5238d5c4e 100644 --- a/libparse/mkinfo_rcmd.sed +++ b/libparse/mkinfo_rcmd.sed @@ -1,8 +1,8 @@ 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, "", "" }\ +}; diff --git a/libparse/mkinfo_scmd.sed b/libparse/mkinfo_scmd.sed index cabe06545..9c17f39ed 100644 --- a/libparse/mkinfo_scmd.sed +++ b/libparse/mkinfo_scmd.sed @@ -1,8 +1,9 @@ 1i\ /*\ - * Automatically generated - do not modify\ - */\ +\ * Automatically generated - do not modify\ +\ */\ \ +#include \ #include "ntp_types.h"\ #include "ntpd.h"\ #include "trimble.h"\ @@ -10,7 +11,5 @@ cmd_info_t trimble_scmds[] = { s!^#define[ ][ ]*\(CMD_C[^ ]*\)[ ][ ]*\([^ ]*\)[ ][ ]*/\*[ ][ ]*\(.*\)[ ][ ]*\*/! { \1, "\1", "\3 (\2)", "", 0 },!p $a\ - { 0xFF, "", "" }\ -};\ - - +\ { 0xFF, "", "" }\ +}; diff --git a/libparse/parsesolaris.c b/libparse/parsesolaris.c index 2d499f0f6..aa3572d60 100644 --- a/libparse/parsesolaris.c +++ b/libparse/parsesolaris.c @@ -40,6 +40,7 @@ static char rcsid[] = "parsesolaris.c,v 4.11 2005/04/16 17:32:10 kardel RELEASE_20050508_A"; #endif +#include #include #include #include diff --git a/libparse/trim_info.c b/libparse/trim_info.c index 8fdc4f61e..619e23861 100644 --- a/libparse/trim_info.c +++ b/libparse/trim_info.c @@ -33,6 +33,7 @@ * SUCH DAMAGE. * */ +#include #include "ntp_types.h" #include "trimble.h" diff --git a/ntpd/Makefile.am b/ntpd/Makefile.am index b0bc10c24..479ce526a 100644 --- a/ntpd/Makefile.am +++ b/ntpd/Makefile.am @@ -36,7 +36,7 @@ endif # # 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 @@ -165,6 +165,7 @@ libntpd_a_SOURCES = \ ntp_signd.c \ ntp_timer.c \ ntp_util.c \ + ntp_worker.c \ ppsapi_timepps.h \ refclock_acts.c \ refclock_arbiter.c \ @@ -206,6 +207,8 @@ libntpd_a_SOURCES = \ refclock_wwv.c \ refclock_wwvb.c \ refclock_zyfer.c \ + work_fork.c \ + work_thread.c \ $(NULL) ntp_keyword.out: keyword-gen diff --git a/ntpd/cmd_args.c b/ntpd/cmd_args.c index 98236f944..71374de3d 100644 --- a/ntpd/cmd_args.c +++ b/ntpd/cmd_args.c @@ -15,7 +15,6 @@ * 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; @@ -133,8 +132,8 @@ getCmdOpts( 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 diff --git a/ntpd/ntp_config.c b/ntpd/ntp_config.c index 1ab1e4174..859ae597c 100644 --- a/ntpd/ntp_config.c +++ b/ntpd/ntp_config.c @@ -17,6 +17,19 @@ # include #endif +#include +#include +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#include +#ifndef SIGCHLD +# define SIGCHLD SIGCLD +#endif +#ifdef HAVE_SYS_WAIT_H +# include +#endif + #include "ntp.h" #include "ntpd.h" #include "ntp_io.h" @@ -26,38 +39,11 @@ #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 -#include "ntp_intres.h" +#include "ntp_random.h" +#include "ntp_workimpl.h" #include #include -#include -#include -#ifdef HAVE_SYS_PARAM_H -# include -#endif -#include -#ifndef SIGCHLD -# define SIGCHLD SIGCLD -#endif -#if !defined(VMS) -# ifdef HAVE_SYS_WAIT_H -# include -# endif -#endif /* VMS */ - -#ifdef SYS_WINNT -# include -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 @@ -76,16 +62,16 @@ int resolver_pipe_fd[2]; /* used to let the resolver process alert the parent p * "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[] = { @@ -102,7 +88,7 @@ static struct masks logcfg_item[] = { { "allsys", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<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 */ - } @@ -3126,7 +3065,6 @@ config_vars( ) { struct attr_val *curr_var; - FILE *new_file; int len; curr_var = queue_head(ptree->vars); @@ -3159,20 +3097,9 @@ config_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; @@ -3278,12 +3205,13 @@ is_sane_resolved_address( 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: @@ -3300,166 +3228,229 @@ get_correct_host_mode( } } -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 @@ -3484,11 +3475,11 @@ config_unpeers( 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); @@ -3509,63 +3500,128 @@ config_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 @@ -3703,6 +3759,19 @@ config_ntpd( 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 */ @@ -3791,10 +3860,7 @@ getconfig( 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 @@ -3880,19 +3946,6 @@ getconfig( 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(); - } - } } @@ -4362,286 +4415,3 @@ get_multiple_netnums( } -#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 -} diff --git a/ntpd/ntp_control.c b/ntpd/ntp_control.c index 7a32ddc38..43a68fc77 100644 --- a/ntpd/ntp_control.c +++ b/ntpd/ntp_control.c @@ -770,7 +770,6 @@ process_control( 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)); @@ -780,11 +779,11 @@ process_control( 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")); } } diff --git a/ntpd/ntp_data_structures.c b/ntpd/ntp_data_structures.c index fb21529be..be55b429a 100644 --- a/ntpd/ntp_data_structures.c +++ b/ntpd/ntp_data_structures.c @@ -3,14 +3,15 @@ * 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 +#endif - -#include /* Needed for malloc */ #include "ntp_data_structures.h" #include "ntp_stdlib.h" @@ -22,13 +23,27 @@ */ -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; } @@ -36,7 +51,9 @@ queue *create_priority_queue(int (*get_order)(void *, void *)) * all the allocated resources in the process */ -void destroy_queue(queue *my_queue) +void destroy_queue( + queue *my_queue + ) { node *temp = NULL; @@ -57,18 +74,35 @@ void destroy_queue(queue *my_queue) * 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); } @@ -90,9 +124,11 @@ next_node( /* 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); } @@ -112,55 +148,63 @@ queue_head( * 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 @@ -170,14 +214,17 @@ int get_no_of_elements(queue *my_queue) * 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. @@ -187,13 +234,7 @@ void append_queue(queue *q1, queue *q2) /* 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; } diff --git a/ntpd/ntp_intres.c b/ntpd/ntp_intres.c index a3c66117d..df30a3e06 100644 --- a/ntpd/ntp_intres.c +++ b/ntpd/ntp_intres.c @@ -1,28 +1,56 @@ /* - * 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 #endif -#include "ntp_intres.h" +#include "ntp_workimpl.h" -#ifndef NO_INTRES +#ifdef WORKER #include #include @@ -53,1247 +81,865 @@ # include # endif # include +# 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 -#include - -#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<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 diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index f15783951..ba64bcc36 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -174,6 +174,13 @@ static struct refclockio *refio; */ 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 */ @@ -185,7 +192,6 @@ static int update_interfaces(u_short, interface_receiver_t, void *); 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 *); @@ -301,6 +307,53 @@ static inline int read_refclock_packet (SOCKET, struct refclockio *, l_fp); #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 @@ -314,7 +367,7 @@ static inline int read_refclock_packet (SOCKET, struct refclockio *, l_fp); * 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 @@ -330,7 +383,7 @@ static inline int read_refclock_packet (SOCKET, struct refclockio *, l_fp); * allocation is possible or 0 is reached - at this * point the algrithm will be disabled */ -static int +SOCKET move_fd( SOCKET fd ) @@ -339,6 +392,9 @@ move_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. @@ -352,17 +408,16 @@ move_fd( #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; @@ -373,12 +428,12 @@ move_fd( * 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 } @@ -413,10 +468,45 @@ move_fd( 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 @@ -487,7 +577,7 @@ init_io(void) #ifdef SYS_WINNT init_io_completion_port(); -#endif /* SYS_WINNT */ +#endif #if defined(HAVE_SIGNALED_IO) (void) set_signal(); @@ -691,26 +781,30 @@ is_ip_address( * 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 */ @@ -1334,14 +1428,7 @@ interface_update( #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(); } @@ -3323,6 +3410,15 @@ input_handler( } #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. */ @@ -3831,23 +3927,7 @@ add_fd_to_list( 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 @@ -3878,26 +3958,10 @@ close_and_delete_fd_from_list( } 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); } } diff --git a/ntpd/ntp_timer.c b/ntpd/ntp_timer.c index d5a1206d0..626ea3dde 100644 --- a/ntpd/ntp_timer.c +++ b/ntpd/ntp_timer.c @@ -31,15 +31,23 @@ #include #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 */ @@ -56,7 +64,7 @@ static u_long adjust_timer; /* second timer */ 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 */ @@ -95,24 +103,24 @@ static RETSIGTYPE alarming (int); #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< (1< 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); + } } } diff --git a/ntpd/ntp_worker.c b/ntpd/ntp_worker.c new file mode 100644 index 000000000..b4d816873 --- /dev/null +++ b/ntpd/ntp_worker.c @@ -0,0 +1,155 @@ +/* + * ntp_worker.c + */ +#include +#include "ntp_workimpl.h" + +#ifdef WORKER + +#include +#include +#include + +#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 diff --git a/ntpd/ntpd.c b/ntpd/ntpd.c index 040a48a0d..1f33dcb98 100644 --- a/ntpd/ntpd.c +++ b/ntpd/ntpd.c @@ -13,7 +13,7 @@ #include #include "ntp_syslog.h" -#include "isc/assertions.h" +#include "ntp_assert.h" #include "isc/error.h" #include "isc/strerror.h" #include "isc/formatcheck.h" @@ -153,7 +153,6 @@ volatile int debug = 0; /* No debugging by default */ #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. @@ -171,7 +170,8 @@ int mdnstries = 5; #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 */ @@ -221,7 +221,7 @@ static RETSIGTYPE no_debug (int); 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); @@ -233,15 +233,30 @@ static void library_unexpected_error(const char *file, int line, /* * 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 @@ -251,17 +266,18 @@ init_logging( 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)); @@ -272,45 +288,144 @@ init_logging( #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); } } @@ -503,6 +618,14 @@ ntpdmain( 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; @@ -534,7 +657,7 @@ ntpdmain( #endif /* honor -l/--logfile option to log to a file */ - setup_logfile(); + setup_logfile(1); /* * Enable the Multi-Media Timer for Windows? @@ -604,15 +727,6 @@ ntpdmain( */ 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); @@ -620,86 +734,63 @@ ntpdmain( 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 */ } @@ -867,7 +958,7 @@ ntpdmain( 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 @@ -982,33 +1073,40 @@ getgroup: 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 */ /* @@ -1237,7 +1335,7 @@ finish( 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 */ @@ -1245,6 +1343,11 @@ assertion_failed(const char *file, int line, isc_assertiontype_t type, 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(); } @@ -1254,7 +1357,7 @@ assertion_failed(const char *file, int line, isc_assertiontype_t type, static void library_fatal_error(const char *file, int line, const char *format, - va_list args) + va_list args) { char errbuf[256]; @@ -1265,6 +1368,11 @@ library_fatal_error(const char *file, int line, const char *format, 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(); } diff --git a/ntpd/ntpsim.c b/ntpd/ntpsim.c index e7c0d9a58..01500c519 100644 --- a/ntpd/ntpsim.c +++ b/ntpd/ntpsim.c @@ -9,6 +9,7 @@ * (Some code shamelessly based on the original NTP discrete event simulator) */ +#include #ifdef SIM #include "ntpd.h" #include "ntpsim.h" diff --git a/ntpd/refclock_jupiter.c b/ntpd/refclock_jupiter.c index 583e31bc0..2e0bf8c63 100644 --- a/ntpd/refclock_jupiter.c +++ b/ntpd/refclock_jupiter.c @@ -52,7 +52,7 @@ # 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 diff --git a/ntpd/refclock_palisade.c b/ntpd/refclock_palisade.c index ff7ab8bad..3fe5290c3 100644 --- a/ntpd/refclock_palisade.c +++ b/ntpd/refclock_palisade.c @@ -786,9 +786,9 @@ TSIP_decode ( } 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; } @@ -1185,85 +1185,60 @@ HW_poll ( 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; diff --git a/ntpd/refclock_palisade.h b/ntpd/refclock_palisade.h index c2d4476a9..4f1ab266e 100644 --- a/ntpd/refclock_palisade.h +++ b/ntpd/refclock_palisade.h @@ -50,12 +50,8 @@ * */ -#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 @@ -183,14 +179,13 @@ static int palisade_start (int, struct peer *); 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 @@ -202,4 +197,5 @@ static void sendint (struct packettx *buffer, int a); 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 */ diff --git a/ntpd/work_fork.c b/ntpd/work_fork.c new file mode 100644 index 000000000..ba93550c1 --- /dev/null +++ b/ntpd/work_fork.c @@ -0,0 +1,460 @@ +/* + * work_fork.c - fork implementation for blocking worker child. + */ +#include +#include "ntp_workimpl.h" + +#ifdef WORK_FORK +#include +#include +#include + +#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 diff --git a/ntpd/work_thread.c b/ntpd/work_thread.c new file mode 100644 index 000000000..cef624425 --- /dev/null +++ b/ntpd/work_thread.c @@ -0,0 +1,314 @@ +/* + * work_thread.c - threads implementation for blocking worker child. + */ +#include +#include "ntp_workimpl.h" + +#ifdef WORK_THREAD + +#include +#include + +#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 diff --git a/ntpdc/ntpdc-layout.c b/ntpdc/ntpdc-layout.c index b05fbf384..017148884 100644 --- a/ntpdc/ntpdc-layout.c +++ b/ntpdc/ntpdc-layout.c @@ -2,6 +2,7 @@ * ntpdc-layout - print layout of NTP mode 7 request/response packets */ +#include #include #include diff --git a/ntpdc/ntpdc.c b/ntpdc/ntpdc.c index bbab73cce..66e50991c 100644 --- a/ntpdc/ntpdc.c +++ b/ntpdc/ntpdc.c @@ -2,6 +2,7 @@ * ntpdc - control and monitor your ntpd daemon */ +#include #include #include #include diff --git a/ntpq/ntpq-subs.c b/ntpq/ntpq-subs.c index c016c79a7..11a79f57e 100644 --- a/ntpq/ntpq-subs.c +++ b/ntpq/ntpq-subs.c @@ -1,7 +1,7 @@ /* - * 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 #include #include #include @@ -907,10 +907,14 @@ dogetassoc( 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; } @@ -1451,17 +1455,17 @@ doprintpeers( 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; @@ -1470,12 +1474,12 @@ doprintpeers( 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) { @@ -1485,7 +1489,7 @@ doprintpeers( } } break; - case CP_REFID: + case CP_REFID: if (pvl == peervarlist) { havevar[HAVE_REFID] = 1; if (*value == '\0') { @@ -1511,70 +1515,63 @@ doprintpeers( } } 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 */ @@ -1584,11 +1581,11 @@ doprintpeers( 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)), @@ -1686,20 +1683,23 @@ dopeers( 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; } diff --git a/ntpq/ntpq.c b/ntpq/ntpq.c index 03a3af7f1..1f3525685 100644 --- a/ntpq/ntpq.c +++ b/ntpq/ntpq.c @@ -1,7 +1,7 @@ /* * ntpq - query an NTP server using mode 6 commands */ - +#include #include #include diff --git a/ntpsnmpd/ntpSnmpSubagentObject.c b/ntpsnmpd/ntpSnmpSubagentObject.c index 3a5815a45..7b94286ca 100644 --- a/ntpsnmpd/ntpSnmpSubagentObject.c +++ b/ntpsnmpd/ntpSnmpSubagentObject.c @@ -18,6 +18,12 @@ #include #include #include +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#include #include "ntpSnmpSubagentObject.h" #include diff --git a/ntpsnmpd/ntpsnmpd.c b/ntpsnmpd/ntpsnmpd.c index 449631b47..9c2d49847 100644 --- a/ntpsnmpd/ntpsnmpd.c +++ b/ntpsnmpd/ntpsnmpd.c @@ -20,6 +20,7 @@ * ****************************************************************************/ +#include #include #include diff --git a/parseutil/testdcf.c b/parseutil/testdcf.c index 223ab3083..c78c2424e 100644 --- a/parseutil/testdcf.c +++ b/parseutil/testdcf.c @@ -34,6 +34,7 @@ * */ +#include #include "ntp_stdlib.h" #include diff --git a/ports/winnt/include/config.h b/ports/winnt/include/config.h index 43ad004c6..f75ee0b57 100644 --- a/ports/winnt/include/config.h +++ b/ports/winnt/include/config.h @@ -1,14 +1,29 @@ -/* 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 */ @@ -110,6 +125,25 @@ struct timeval { 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 @@ -241,6 +275,7 @@ typedef int socklen_t; #endif #define write _write #define strdup _strdup +#define alloca _alloca #define stat _stat /*struct stat from */ #define fstat _fstat #define unlink _unlink @@ -331,7 +366,7 @@ typedef __int32 int32_t; /* define a typedef for int32_t */ # 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 @@ -437,4 +472,4 @@ typedef unsigned long uintptr_t; */ #include -#endif /* CONFIG_H */ +#endif /* CONFIG_H */ diff --git a/ports/winnt/include/sys/time.h b/ports/winnt/include/sys/time.h index d8f734c76..315247035 100644 --- a/ports/winnt/include/sys/time.h +++ b/ports/winnt/include/sys/time.h @@ -7,8 +7,6 @@ #ifndef SYS_TIME_H #define SYS_TIME_H -#include -#include #include "ntp_types.h" #include #include diff --git a/ports/winnt/include/win32_io.h b/ports/winnt/include/win32_io.h index 129c8ff2a..8f67ca1d1 100644 --- a/ports/winnt/include/win32_io.h +++ b/ports/winnt/include/win32_io.h @@ -2,7 +2,6 @@ #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 */ diff --git a/ports/winnt/libntp/SetSystemTime.c b/ports/winnt/libntp/SetSystemTime.c index 3bc99382a..6b5444f39 100644 --- a/ports/winnt/libntp/SetSystemTime.c +++ b/ports/winnt/libntp/SetSystemTime.c @@ -1,4 +1,5 @@ +#include #include "clockstuff.h" #include "ntp_stdlib.h" diff --git a/ports/winnt/ntpd/nt_clockstuff.c b/ports/winnt/ntpd/nt_clockstuff.c index b0e298e4b..21c3fb013 100644 --- a/ports/winnt/ntpd/nt_clockstuff.c +++ b/ports/winnt/ntpd/nt_clockstuff.c @@ -35,7 +35,7 @@ #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 */ diff --git a/ports/winnt/ntpd/ntp_iocompletionport.c b/ports/winnt/ntpd/ntp_iocompletionport.c index 8680ee5b8..5323acdbb 100644 --- a/ports/winnt/ntpd/ntp_iocompletionport.c +++ b/ports/winnt/ntpd/ntp_iocompletionport.c @@ -91,8 +91,8 @@ static HANDLE WaitableExitEventHandle = NULL; #define WAITABLEIOEVENTHANDLE NULL #endif -#define MAXHANDLES 3 -HANDLE WaitHandles[MAXHANDLES] = { NULL, NULL, NULL }; +#define MAXHANDLES 4 +HANDLE WaitHandles[MAXHANDLES]; IoCompletionInfo * GetHeapAlloc(char *fromfunc) @@ -294,12 +294,15 @@ init_io_completion_port( 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 @@ -888,26 +891,28 @@ int GetReceivedBuffers() 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 */ diff --git a/ports/winnt/vc6/ntpd.dsp b/ports/winnt/vc6/ntpd.dsp index 032873278..f99e01996 100644 --- a/ports/winnt/vc6/ntpd.dsp +++ b/ports/winnt/vc6/ntpd.dsp @@ -190,6 +190,11 @@ SOURCE=..\..\..\ntpd\ntp_util.c # End Source File # Begin Source File +SOURCE=..\..\..\ntpd\ntp_worker.c +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + SOURCE="..\..\..\ntpd\ntpd-opts.c" # End Source File # Begin Source File @@ -200,9 +205,19 @@ SOURCE=..\..\..\ntpd\ntpd.c # Begin Source File SOURCE=..\ntpd\ntservice.c +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=..\..\..\ntpd\work_fork.c +# SUBTRACT CPP /YX # End Source File # Begin Source File +SOURCE=..\..\..\ntpd\work_thread.c +# SUBTRACT CPP /YX +# End Source File + # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File @@ -394,6 +409,14 @@ SOURCE=..\..\..\include\ntp_unixtime.h # End Source File # Begin Source File +SOURCE=..\..\..\include\ntp_worker.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\include\ntp_workimpl.h +# End Source File +# Begin Source File + SOURCE="..\..\..\ntpd\ntpd-opts.h" # End Source File # Begin Source File diff --git a/ports/winnt/vs2003/ntpd.vcproj b/ports/winnt/vs2003/ntpd.vcproj index 975297aa3..599c36a04 100644 --- a/ports/winnt/vs2003/ntpd.vcproj +++ b/ports/winnt/vs2003/ntpd.vcproj @@ -621,6 +621,9 @@ BrowseInformation="1"/> + + + + + + + + + + diff --git a/ports/winnt/vs2005/ntpd.vcproj b/ports/winnt/vs2005/ntpd.vcproj index f1f3abeb2..2803d8f73 100644 --- a/ports/winnt/vs2005/ntpd.vcproj +++ b/ports/winnt/vs2005/ntpd.vcproj @@ -668,6 +668,10 @@ /> + + @@ -734,6 +738,14 @@ /> + + + + + + + + diff --git a/ports/winnt/vs2008/libntp/libntp.vcproj b/ports/winnt/vs2008/libntp/libntp.vcproj index 49f5327e1..b0c61783a 100644 --- a/ports/winnt/vs2008/libntp/libntp.vcproj +++ b/ports/winnt/vs2008/libntp/libntp.vcproj @@ -307,6 +307,26 @@ RelativePath="..\..\..\..\libntp\humandate.c" > + + + + + + + + @@ -487,10 +507,18 @@ RelativePath="..\..\..\..\lib\isc\win32\stdtime.c" > + + + + diff --git a/ports/winnt/vs2008/ntpd/ntpd.vcproj b/ports/winnt/vs2008/ntpd/ntpd.vcproj index 8c3f0c5e7..d7aa513b4 100644 --- a/ports/winnt/vs2008/ntpd/ntpd.vcproj +++ b/ports/winnt/vs2008/ntpd/ntpd.vcproj @@ -627,6 +627,10 @@ /> + + @@ -671,6 +675,26 @@ /> + + + + + + + + @@ -693,6 +717,14 @@ /> + + + + + + @@ -910,6 +946,14 @@ RelativePath="..\..\..\..\include\ntp_unixtime.h" > + + + + @@ -1716,6 +1760,10 @@ /> + + @@ -1862,6 +1910,18 @@ + + + + + @@ -2114,6 +2174,86 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2162,6 +2302,66 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + #include "crypto.h" struct key *key_ptr; diff --git a/sntp/kod_management.c b/sntp/kod_management.c index 878a2a0c1..12bc1562c 100644 --- a/sntp/kod_management.c +++ b/sntp/kod_management.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/sntp/log.c b/sntp/log.c index c6bfe2228..ec3c5388b 100644 --- a/sntp/log.c +++ b/sntp/log.c @@ -1,3 +1,4 @@ +#include #include "log.h" #include "sntp-opts.h" diff --git a/sntp/main.c b/sntp/main.c index 3348f79d7..1a14b6c96 100644 --- a/sntp/main.c +++ b/sntp/main.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/sntp/networking.c b/sntp/networking.c index 9aaff7a1b..a37eb6c41 100644 --- a/sntp/networking.c +++ b/sntp/networking.c @@ -1,3 +1,4 @@ +#include #include "networking.h" char adr_buf[INET6_ADDRSTRLEN]; diff --git a/sntp/utilities.c b/sntp/utilities.c index 23d957f3c..8039bac04 100644 --- a/sntp/utilities.c +++ b/sntp/utilities.c @@ -1,3 +1,4 @@ +#include #include "utilities.h" /* Display a NTP packet in hex with leading address offset