diff options
Diffstat (limited to 'contrib/ntp/ntpd/ntpd.c')
-rw-r--r-- | contrib/ntp/ntpd/ntpd.c | 1121 |
1 files changed, 1121 insertions, 0 deletions
diff --git a/contrib/ntp/ntpd/ntpd.c b/contrib/ntp/ntpd/ntpd.c new file mode 100644 index 000000000000..923b1f702653 --- /dev/null +++ b/contrib/ntp/ntpd/ntpd.c @@ -0,0 +1,1121 @@ +/* + * ntpd.c - main program for the fixed point NTP daemon + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#include <stdio.h> +#ifndef SYS_WINNT +# if !defined(VMS) /*wjm*/ +# include <sys/param.h> +# endif /* VMS */ +# include <sys/signal.h> +# ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +# endif /* HAVE_SYS_IOCTL_H */ +# include <sys/time.h> +# ifdef HAVE_SYS_RESOURCE_H +# include <sys/resource.h> +# endif /* HAVE_SYS_RESOURCE_H */ +#else +# include <signal.h> +# include <process.h> +# include <io.h> +# include "../libntp/log.h" +# include <crtdbg.h> +#endif /* SYS_WINNT */ +#if defined(HAVE_RTPRIO) +# ifdef HAVE_SYS_RESOURCE_H +# include <sys/resource.h> +# endif +# ifdef HAVE_SYS_LOCK_H +# include <sys/lock.h> +# endif +# include <sys/rtprio.h> +#else +# ifdef HAVE_PLOCK +# ifdef HAVE_SYS_LOCK_H +# include <sys/lock.h> +# endif +# endif +#endif +#if defined(HAVE_SCHED_SETSCHEDULER) +# ifdef HAVE_SCHED_H +# include <sched.h> +# else +# ifdef HAVE_SYS_SCHED_H +# include <sys/sched.h> +# endif +# endif +#endif +#if defined(HAVE_SYS_MMAN_H) +# include <sys/mman.h> +#endif + +#ifdef HAVE_TERMIOS_H +# include <termios.h> +#endif + +#ifdef SYS_DOMAINOS +# include <apollo/base.h> +#endif /* SYS_DOMAINOS */ + +#include "ntpd.h" +#include "ntp_io.h" + +#include "ntp_stdlib.h" +#include "recvbuff.h" + +#if 0 /* HMS: I don't think we need this. 961223 */ +#ifdef LOCK_PROCESS +# ifdef SYS_SOLARIS +# include <sys/mman.h> +# else +# include <sys/lock.h> +# endif +#endif +#endif + +#ifdef _AIX +#include <ulimit.h> +#endif /* _AIX */ + +#ifdef SCO5_CLOCK +#include <sys/ci/ciioctl.h> +#endif + +/* + * Signals we catch for debugging. If not debugging we ignore them. + */ +#define MOREDEBUGSIG SIGUSR1 +#define LESSDEBUGSIG SIGUSR2 + +/* + * Signals which terminate us gracefully. + */ +#ifndef SYS_WINNT +#define SIGDIE1 SIGHUP +#define SIGDIE3 SIGQUIT +#define SIGDIE2 SIGINT +#define SIGDIE4 SIGTERM +#endif /* SYS_WINNT */ + +#if defined SYS_WINNT || defined SYS_CYGWIN32 +/* handles for various threads, process, and objects */ +HANDLE ResolverThreadHandle = NULL; +/* variables used to inform the Service Control Manager of our current state */ +SERVICE_STATUS ssStatus; +SERVICE_STATUS_HANDLE sshStatusHandle; +HANDLE WaitHandles[3] = { NULL, NULL, NULL }; +char szMsgPath[255]; +static BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType); +#endif /* SYS_WINNT */ + +/* + * Scheduling priority we run at + */ +#if !defined SYS_WINNT +# define NTPD_PRIO (-12) +#else +# define NTPD_PRIO REALTIME_PRIORITY_CLASS +#endif + +/* + * Debugging flag + */ +volatile int debug; + +/* + * No-fork flag. If set, we do not become a background daemon. + */ +int nofork; + +/* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ +int initializing; + +/* + * Version declaration + */ +extern const char *Version; + +int was_alarmed; + +#ifdef DECL_SYSCALL +/* + * We put this here, since the argument profile is syscall-specific + */ +extern int syscall P((int, ...)); +#endif /* DECL_SYSCALL */ + + +#ifdef SIGDIE2 +static RETSIGTYPE finish P((int)); +#endif /* SIGDIE2 */ + +#ifdef DEBUG +static RETSIGTYPE moredebug P((int)); +static RETSIGTYPE lessdebug P((int)); +#else /* not DEBUG */ +static RETSIGTYPE no_debug P((int)); +#endif /* not DEBUG */ + +int ntpdmain P((int, char **)); +static void set_process_priority P((void)); + + +#ifdef NO_MAIN_ALLOWED +CALL(ntpd,"ntpd",ntpdmain); +#else +int +main( + int argc, + char *argv[] + ) +{ + return ntpdmain(argc, argv); +} +#endif + +#ifdef _AIX +/* + * OK. AIX is different than solaris in how it implements plock(). + * If you do NOT adjust the stack limit, you will get the MAXIMUM + * stack size allocated and PINNED with you program. To check the + * value, use ulimit -a. + * + * To fix this, we create an automatic variable and set our stack limit + * to that PLUS 32KB of extra space (we need some headroom). + * + * This subroutine gets the stack address. + * + * Grover Davidson and Matt Ladendorf + * + */ +static char * +get_aix_stack(void) +{ + char ch; + return (&ch); +} + +/* + * Signal handler for SIGDANGER. + */ +static void +catch_danger(int signo) +{ + msyslog(LOG_INFO, "ntpd: setpgid(): %m"); + /* Make the system believe we'll free something, but don't do it! */ + return; +} +#endif /* _AIX */ + +/* + * Set the process priority + */ +static void +set_process_priority(void) +{ + int done = 0; + +#ifdef SYS_WINNT + if (!SetPriorityClass(GetCurrentProcess(), (DWORD) REALTIME_PRIORITY_CLASS)) + msyslog(LOG_ERR, "SetPriorityClass: %m"); + else + ++done; +#else /* not SYS_WINNT */ +# if defined(HAVE_SCHED_SETSCHEDULER) + + if (!done) { + extern int config_priority_override, config_priority; + int pmax, pmin; + struct sched_param sched; + + pmax = sched_get_priority_max(SCHED_FIFO); + sched.sched_priority = pmax; + if ( config_priority_override ) { + pmin = sched_get_priority_min(SCHED_FIFO); + if ( config_priority > pmax ) + sched.sched_priority = pmax; + else if ( config_priority < pmin ) + sched.sched_priority = pmin; + else + sched.sched_priority = config_priority; + } + if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) + msyslog(LOG_ERR, "sched_setscheduler(): %m"); + else + ++done; + } +# endif /* HAVE_SCHED_SETSCHEDULER */ +# if defined(HAVE_RTPRIO) +# ifdef RTP_SET + if (!done) { + struct rtprio srtp; + + srtp.type = RTP_PRIO_REALTIME; /* was: RTP_PRIO_NORMAL */ + srtp.prio = 0; /* 0 (hi) -> RTP_PRIO_MAX (31,lo) */ + + if (rtprio(RTP_SET, getpid(), &srtp) < 0) + msyslog(LOG_ERR, "rtprio() error: %m"); + else + ++done; + } +# else /* not RTP_SET */ + if (!done) { + if (rtprio(0, 120) < 0) + msyslog(LOG_ERR, "rtprio() error: %m"); + else + ++done; + } +# endif /* not RTP_SET */ +# endif /* HAVE_RTPRIO */ +# if defined(NTPD_PRIO) && NTPD_PRIO != 0 +# ifdef HAVE_ATT_NICE + if (!done) { + errno = 0; + if (-1 == nice (NTPD_PRIO) && errno != 0) + msyslog(LOG_ERR, "nice() error: %m"); + else + ++done; + } +# endif /* HAVE_ATT_NICE */ +# ifdef HAVE_BSD_NICE + if (!done) { + if (-1 == setpriority(PRIO_PROCESS, 0, NTPD_PRIO)) + msyslog(LOG_ERR, "setpriority() error: %m"); + else + ++done; + } +# endif /* HAVE_BSD_NICE */ +# endif /* NTPD_PRIO && NTPD_PRIO != 0 */ +#endif /* not SYS_WINNT */ + if (!done) + msyslog(LOG_ERR, "set_process_priority: No way found to improve our priority"); +} + +/* + * Main program. Initialize us, disconnect us from the tty if necessary, + * and loop waiting for I/O and/or timer expiries. + */ +int +ntpdmain( + int argc, + char *argv[] + ) +{ + l_fp now; + char *cp; + struct recvbuf *rbuflist; + struct recvbuf *rbuf; +#ifdef _AIX /* HMS: ifdef SIGDANGER? */ + struct sigaction sa; +#endif + + initializing = 1; /* mark that we are initializing */ + debug = 0; /* no debugging by default */ + nofork = 0; /* will fork by default */ + +#ifdef HAVE_UMASK + { + unsigned int uv; + + uv = umask(0); + if(uv) + (void) umask(uv); + else + (void) umask(022); + } +#endif + +#ifdef HAVE_GETUID + { + uid_t uid; + + uid = getuid(); + if (uid) + { + msyslog(LOG_ERR, "ntpd: must be run as root, not uid %ld", (long)uid); + exit(1); + } + } +#endif + +#ifdef SYS_WINNT + /* Set the Event-ID message-file name. */ + if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) { + msyslog(LOG_ERR, "GetModuleFileName(PGM_EXE_FILE) failed: %m\n"); + exit(1); + } + addSourceToRegistry("NTP", szMsgPath); +#endif + + get_systime(&now); + SRANDOM((int)(now.l_i * now.l_uf)); + getstartup(argc, argv); /* startup configuration, may set debug */ + +#if !defined(VMS) +# ifndef NODETACH + /* + * Detach us from the terminal. May need an #ifndef GIZMO. + */ +# ifdef DEBUG + if (!debug && !nofork) +# else /* DEBUG */ + if (!nofork) +# endif /* DEBUG */ + { +# ifndef SYS_WINNT +# ifdef HAVE_DAEMON + daemon(0, 0); +# else /* not HAVE_DAEMON */ + if (fork()) /* HMS: What about a -1? */ + exit(0); + + { +#if !defined(F_CLOSEM) + u_long s; + int max_fd; +#endif /* not F_CLOSEM */ + + /* + * From 'Writing Reliable AIX Daemons,' SG24-4946-00, + * by Eric Agar (saves us from doing 32767 system + * calls) + */ +#if defined(F_CLOSEM) + 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); +#ifdef SYS_DOMAINOS + { + uid_$t puid; + status_$t 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"); +# else + if (setpgid(0, 0) == -1) + msyslog(LOG_ERR, "ntpd: setpgid(): %m"); +# endif +#else /* HAVE_SETPGID || HAVE_SETSID */ + { +# if defined(TIOCNOTTY) + int fid; + + fid = open("/dev/tty", 2); + if (fid >= 0) + { + (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0); + (void) close(fid); + } +# endif /* defined(TIOCNOTTY) */ +# ifdef HAVE_SETPGRP_0 + (void) setpgrp(); +# else /* HAVE_SETPGRP_0 */ + (void) 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; + + (void) sigaction(SIGDANGER, &sa, NULL); +#endif /* _AIX */ + } +#endif /* not HAVE_DAEMON */ +#else /* SYS_WINNT */ + + { + SERVICE_TABLE_ENTRY dispatchTable[] = { + { TEXT("NetworkTimeProtocol"), (LPSERVICE_MAIN_FUNCTION)service_main }, + { NULL, NULL } + }; + + /* daemonize */ + if (!StartServiceCtrlDispatcher(dispatchTable)) + { + msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m"); + ExitProcess(2); + } + } +#endif /* SYS_WINNT */ + } +#endif /* NODETACH */ +#if defined(SYS_WINNT) && !defined(NODETACH) + else + service_main(argc, argv); + return 0; /* must return a value */ +} /* end main */ + +/* + * If this runs as a service under NT, the main thread will block at + * StartServiceCtrlDispatcher() and another thread will be started by the + * Service Control Dispatcher which will begin execution at the routine + * specified in that call (viz. service_main) + */ +void +service_main( + DWORD argc, + LPTSTR *argv + ) +{ + char *cp; + struct recvbuf *rbuflist; + struct recvbuf *rbuf; + + if(!debug) + { + /* register our service control handler */ + if (!(sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"), + (LPHANDLER_FUNCTION)service_ctrl))) + { + msyslog(LOG_ERR, "RegisterServiceCtrlHandler failed: %m"); + return; + } + + /* report pending status to Service Control Manager */ + ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ssStatus.dwCurrentState = SERVICE_START_PENDING; + ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + ssStatus.dwWin32ExitCode = NO_ERROR; + ssStatus.dwServiceSpecificExitCode = 0; + ssStatus.dwCheckPoint = 1; + ssStatus.dwWaitHint = 5000; + if (!SetServiceStatus(sshStatusHandle, &ssStatus)) + { + msyslog(LOG_ERR, "SetServiceStatus: %m"); + ssStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(sshStatusHandle, &ssStatus); + return; + } + + } /* debug */ +#endif /* defined(SYS_WINNT) && !defined(NODETACH) */ +#endif /* VMS */ + + /* + * Logging. This may actually work on the gizmo board. Find a name + * to log with by using the basename of argv[0] + */ + cp = strrchr(argv[0], '/'); + if (cp == 0) + cp = argv[0]; + else + cp++; + + debug = 0; /* will be immediately re-initialized 8-( */ + getstartup(argc, argv); /* startup configuration, catch logfile this time */ + +#if !defined(SYS_WINNT) && !defined(VMS) + +# ifndef LOG_DAEMON + openlog(cp, LOG_PID); +# else /* LOG_DAEMON */ + +# ifndef LOG_NTP +# define LOG_NTP LOG_DAEMON +# endif + openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP); +#ifndef SYS_CYGWIN32 +# ifdef DEBUG + if (debug) + setlogmask(LOG_UPTO(LOG_DEBUG)); + else +# endif /* DEBUG */ + setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ +# endif /* LOG_DAEMON */ +#endif + +#endif /* !SYS_WINNT && !VMS */ + + NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, "%s", Version); + +#ifdef SYS_WINNT + /* GMS 1/18/1997 + * TODO: lock the process in memory using SetProcessWorkingSetSize() and VirtualLock() functions + * + process_handle = GetCurrentProcess(); + if (SetProcessWorkingSetSize(process_handle, 2097152 , 4194304 ) == TRUE) { + if (VirtualLock(0 , 4194304) == FALSE) + msyslog(LOG_ERR, "VirtualLock() failed: %m"); + } else { + msyslog(LOG_ERR, "SetProcessWorkingSetSize() failed: %m"); + } + */ +#endif /* SYS_WINNT */ + +#ifdef SCO5_CLOCK + /* + * SCO OpenServer's system clock offers much more precise timekeeping + * on the base CPU than the other CPUs (for multiprocessor systems), + * so we must lock to the base CPU. + */ + { + int fd = open("/dev/at1", O_RDONLY); + if (fd >= 0) { + int zero = 0; + if (ioctl(fd, ACPU_LOCK, &zero) < 0) + msyslog(LOG_ERR, "cannot lock to base CPU: %m\n"); + close( fd ); + } /* else ... + * If we can't open the device, this probably just isn't + * a multiprocessor system, so we're A-OK. + */ + } +#endif + +#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE) + /* + * lock the process into memory + */ + if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) + msyslog(LOG_ERR, "mlockall(): %m"); +#else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */ +# ifdef HAVE_PLOCK +# ifdef PROCLOCK +# ifdef _AIX + /* + * set the stack limit for AIX for plock(). + * see get_aix_stack for more info. + */ + if (ulimit(SET_STACKLIM, (get_aix_stack() - 8*4096)) < 0) + { + msyslog(LOG_ERR,"Cannot adjust stack limit for plock on AIX: %m"); + } +# endif /* _AIX */ + /* + * lock the process into memory + */ + if (plock(PROCLOCK) < 0) + msyslog(LOG_ERR, "plock(PROCLOCK): %m"); +# else /* not PROCLOCK */ +# ifdef TXTLOCK + /* + * Lock text into ram + */ + if (plock(TXTLOCK) < 0) + msyslog(LOG_ERR, "plock(TXTLOCK) error: %m"); +# else /* not TXTLOCK */ + msyslog(LOG_ERR, "plock() - don't know what to lock!"); +# endif /* not TXTLOCK */ +# endif /* not PROCLOCK */ +# endif /* HAVE_PLOCK */ +#endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */ + + /* + * Set up signals we pay attention to locally. + */ +#ifdef SIGDIE1 + (void) signal_no_reset(SIGDIE1, finish); +#endif /* SIGDIE1 */ +#ifdef SIGDIE2 + (void) signal_no_reset(SIGDIE2, finish); +#endif /* SIGDIE2 */ +#ifdef SIGDIE3 + (void) signal_no_reset(SIGDIE3, finish); +#endif /* SIGDIE3 */ +#ifdef SIGDIE4 + (void) signal_no_reset(SIGDIE4, finish); +#endif /* SIGDIE4 */ + +#ifdef SIGBUS + (void) signal_no_reset(SIGBUS, finish); +#endif /* SIGBUS */ + +#if !defined(SYS_WINNT) && !defined(VMS) +# ifdef DEBUG + (void) signal_no_reset(MOREDEBUGSIG, moredebug); + (void) signal_no_reset(LESSDEBUGSIG, lessdebug); +# else + (void) signal_no_reset(MOREDEBUGSIG, no_debug); + (void) signal_no_reset(LESSDEBUGSIG, no_debug); +# endif /* DEBUG */ +#endif /* !SYS_WINNT && !VMS */ + + /* + * Set up signals we should never pay attention to. + */ +#if defined SIGPIPE && !defined SYS_CYGWIN32 + (void) signal_no_reset(SIGPIPE, SIG_IGN); +#endif /* SIGPIPE */ + +#if defined SYS_WINNT + if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE)) { + msyslog(LOG_ERR, "Can't set console control handler: %m"); + } +#endif + + /* + * Call the init_ routines to initialize the data structures. + */ +#if defined (HAVE_IO_COMPLETION_PORT) + init_io_completion_port(); + init_winnt_time(); +#endif + init_auth(); + init_util(); + init_restrict(); + init_mon(); + init_timer(); + init_lib(); + init_random(); + init_request(); + init_control(); + init_peer(); +#ifdef REFCLOCK + init_refclock(); +#endif + set_process_priority(); + init_proto(); + init_io(); + init_loopfilter(); + + mon_start(MON_ON); /* monitor on by default now */ + /* turn off in config if unwanted */ + + /* + * Get configuration. This (including argument list parsing) is + * done in a separate module since this will definitely be different + * for the gizmo board. + */ + getconfig(argc, argv); + + initializing = 0; + +#if defined(SYS_WINNT) && !defined(NODETACH) +# if defined(DEBUG) + if(!debug) + { +#endif + /* report to the service control manager that the service is running */ + ssStatus.dwCurrentState = SERVICE_RUNNING; + ssStatus.dwWin32ExitCode = NO_ERROR; + if (!SetServiceStatus(sshStatusHandle, &ssStatus)) + { + msyslog(LOG_ERR, "SetServiceStatus: %m"); + if (ResolverThreadHandle != NULL) + CloseHandle(ResolverThreadHandle); + ssStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(sshStatusHandle, &ssStatus); + return; + } +# if defined(DEBUG) + } +#endif +#endif + + /* + * Report that we're up to any trappers + */ + report_event(EVNT_SYSRESTART, (struct peer *)0); + + /* + * Use select() on all on all input fd's for unlimited + * time. select() will terminate on SIGALARM or on the + * reception of input. Using select() means we can't do + * robust signal handling and we get a potential race + * between checking for alarms and doing the select(). + * Mostly harmless, I think. + */ + /* On VMS, I suspect that select() can't be interrupted + * by a "signal" either, so I take the easy way out and + * have select() time out after one second. + * System clock updates really aren't time-critical, + * and - lacking a hardware reference clock - I have + * yet to learn about anything else that is. + */ +# if defined(HAVE_IO_COMPLETION_PORT) + { + WaitHandles[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* exit reques */ + WaitHandles[1] = get_recv_buff_event(); + WaitHandles[2] = get_timer_handle(); + + for (;;) { + DWORD Index = MsgWaitForMultipleObjectsEx(sizeof(WaitHandles)/sizeof(WaitHandles[0]), WaitHandles, INFINITE, QS_ALLEVENTS, MWMO_ALERTABLE); + switch (Index) { + case WAIT_OBJECT_0 + 0 : /* exit request */ + exit(0); + break; + + case WAIT_OBJECT_0 + 1 : {/* recv buffer */ + if (NULL != (rbuf = get_full_recv_buffer())) { + if (rbuf->receiver != NULL) { + rbuf->receiver(rbuf); + } + freerecvbuf(rbuf); + } + } + break; + + case WAIT_OBJECT_0 + 2 : /* 1 second timer */ + timer(); + break; + + case WAIT_OBJECT_0 + 3 : { /* Windows message */ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + exit(0); + } + DispatchMessage(&msg); + } + } + break; + + case WAIT_IO_COMPLETION : /* loop */ + case WAIT_TIMEOUT : + break; + + } + + } + } +# else /* normal I/O */ + + was_alarmed = 0; + rbuflist = (struct recvbuf *)0; + for (;;) + { +# if !defined(HAVE_SIGNALED_IO) + extern fd_set activefds; + extern int maxactivefd; + + fd_set rdfdes; + int nfound; +# elif defined(HAVE_SIGNALED_IO) + block_io_and_alarm(); +# endif + + rbuflist = getrecvbufs(); /* get received buffers */ + if (alarm_flag) /* alarmed? */ + { + was_alarmed = 1; + alarm_flag = 0; + } + + if (!was_alarmed && rbuflist == (struct recvbuf *)0) + { + /* + * Nothing to do. Wait for something. + */ +#ifndef HAVE_SIGNALED_IO + rdfdes = activefds; +# if defined(VMS) || defined(SYS_VXWORKS) + /* make select() wake up after one second */ + { + struct timeval t1; + + t1.tv_sec = 1; t1.tv_usec = 0; + nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, &t1); + } +# else + nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, (struct timeval *)0); +# endif /* VMS */ + if (nfound > 0) + { + l_fp ts; + + get_systime(&ts); + + (void)input_handler(&ts); + } + else if (nfound == -1 && errno != EINTR) + msyslog(LOG_ERR, "select() error: %m"); + else if (debug) { +# if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 && !defined SCO5_CLOCK /* to unclutter log */ + msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); +# endif + } +# else /* HAVE_SIGNALED_IO */ + + wait_for_signal(); +# endif /* HAVE_SIGNALED_IO */ + if (alarm_flag) /* alarmed? */ + { + was_alarmed = 1; + alarm_flag = 0; + } + rbuflist = getrecvbufs(); /* get received buffers */ + } +# ifdef HAVE_SIGNALED_IO + unblock_io_and_alarm(); +# endif /* HAVE_SIGNALED_IO */ + + /* + * Out here, signals are unblocked. Call timer routine + * to process expiry. + */ + if (was_alarmed) + { + timer(); + was_alarmed = 0; + } + + /* + * Call the data procedure to handle each received + * packet. + */ + while (rbuflist != (struct recvbuf *)0) + { + rbuf = rbuflist; + rbuflist = rbuf->next; + (rbuf->receiver)(rbuf); + freerecvbuf(rbuf); + } +# if defined DEBUG && defined SYS_WINNT + if (debug > 4) + printf("getrecvbufs: %ld handler interrupts, %ld frames\n", + handler_calls, handler_pkts); +# endif + + /* + * Go around again + */ + } +# endif /* HAVE_IO_COMPLETION_PORT */ + exit(1); /* unreachable */ + return 1; /* DEC OSF cc braindamage */ +} + + +#ifdef SIGDIE2 +/* + * finish - exit gracefully + */ +static RETSIGTYPE +finish( + int sig + ) +{ + + msyslog(LOG_NOTICE, "ntpd exiting on signal %d", sig); + + switch (sig) + { +#ifdef SIGBUS + case SIGBUS: + printf("\nfinish(SIGBUS)\n"); + exit(0); +#endif + case 0: /* Should never happen... */ + return; + default: + exit(0); + } +} +#endif /* SIGDIE2 */ + + +#ifdef DEBUG +/* + * moredebug - increase debugging verbosity + */ +static RETSIGTYPE +moredebug( + int sig + ) +{ + int saved_errno = errno; + + if (debug < 255) + { + debug++; + msyslog(LOG_DEBUG, "debug raised to %d", debug); + } + errno = saved_errno; +} + +/* + * lessdebug - decrease debugging verbosity + */ +static RETSIGTYPE +lessdebug( + int sig + ) +{ + int saved_errno = errno; + + if (debug > 0) + { + debug--; + msyslog(LOG_DEBUG, "debug lowered to %d", debug); + } + errno = saved_errno; +} +#else /* not DEBUG */ +/* + * no_debug - We don't do the debug here. + */ +static RETSIGTYPE +no_debug( + int sig + ) +{ + int saved_errno = errno; + + msyslog(LOG_DEBUG, "ntpd not compiled for debugging (signal %d)", sig); + errno = saved_errno; +} +#endif /* not DEBUG */ + +#ifdef SYS_WINNT +/* service_ctrl - control handler for NTP service + * signals the service_main routine of start/stop requests + * from the control panel or other applications making + * win32API calls + */ +void +service_ctrl( + DWORD dwCtrlCode + ) +{ + DWORD dwState = SERVICE_RUNNING; + + /* Handle the requested control code */ + switch(dwCtrlCode) + { + case SERVICE_CONTROL_PAUSE: + /* see no reason to support this */ + break; + + case SERVICE_CONTROL_CONTINUE: + /* see no reason to support this */ + break; + + case SERVICE_CONTROL_STOP: + dwState = SERVICE_STOP_PENDING; + /* + * Report the status, specifying the checkpoint and waithint, + * before setting the termination event. + */ + ssStatus.dwCurrentState = dwState; + ssStatus.dwWin32ExitCode = NO_ERROR; + ssStatus.dwWaitHint = 3000; + if (!SetServiceStatus(sshStatusHandle, &ssStatus)) + { + msyslog(LOG_ERR, "SetServiceStatus: %m"); + } + if (WaitHandles[0] != NULL) { + SetEvent(WaitHandles[0]); + } + return; + + case SERVICE_CONTROL_INTERROGATE: + /* Update the service status */ + break; + + default: + /* invalid control code */ + break; + + } + + ssStatus.dwCurrentState = dwState; + ssStatus.dwWin32ExitCode = NO_ERROR; + if (!SetServiceStatus(sshStatusHandle, &ssStatus)) + { + msyslog(LOG_ERR, "SetServiceStatus: %m"); + } +} + +static BOOL WINAPI +OnConsoleEvent( + DWORD dwCtrlType + ) +{ + switch (dwCtrlType) { + case CTRL_BREAK_EVENT : + if (debug > 0) { + debug <<= 1; + } + else { + debug = 1; + } + if (debug > 8) { + debug = 0; + } + printf("debug level %d\n", debug); + break ; + + case CTRL_C_EVENT : + case CTRL_CLOSE_EVENT : + case CTRL_SHUTDOWN_EVENT : + if (WaitHandles[0] != NULL) { + SetEvent(WaitHandles[0]); + } + break; + + default : + return FALSE; + + + } + return TRUE;; +} + + +/* + * NT version of exit() - all calls to exit() should be routed to + * this function. + */ +void +service_exit( + int status + ) +{ + if (!debug) { /* did not become a service, simply exit */ + /* service mode, need to have the service_main routine + * register with the service control manager that the + * service has stopped running, before exiting + */ + ssStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(sshStatusHandle, &ssStatus); + + } + uninit_io_completion_port(); + reset_winnt_time(); + +# if defined _MSC_VER + _CrtDumpMemoryLeaks(); +# endif +#undef exit + exit(status); +} + +#endif /* SYS_WINNT */ |