source: trunk/third/xntp/xntpd/ntpd.c @ 10832

Revision 10832, 22.9 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10831, which included commits to RCS files with non-trunk default branches.
Line 
1#define HAVE_POSIX_MMAN
2/*
3 * ntpd.c - main program for the fixed point NTP daemon
4 */
5#ifdef HAVE_CONFIG_H
6# include <config.h>
7#endif
8
9#include <sys/types.h>
10#ifdef HAVE_UNISTD_H
11# include <unistd.h>
12#endif
13#ifdef HAVE_SYS_STAT_H
14# include <sys/stat.h>
15#endif
16#include <stdio.h>
17#include <errno.h>
18#ifndef SYS_WINNT
19# if !defined(VMS)      /*wjm*/
20#  include <sys/param.h>
21# endif /* VMS */
22# include <sys/signal.h>
23# ifdef HAVE_SYS_IOCTL_H
24#  include <sys/ioctl.h>
25# endif /* HAVE_SYS_IOCTL_H */
26# include <sys/time.h>
27# if !defined(VMS)      /*wjm*/
28#  include <sys/resource.h>
29# endif /* VMS */
30#else
31# include <signal.h>
32# include <process.h>
33# include <io.h>
34# include "../libntp/log.h"
35#endif /* SYS_WINNT */
36#if defined(HAVE_RTPRIO)
37# ifdef HAVE_SYS_RESOURCE_H
38#  include <sys/resource.h>
39# endif
40# ifdef HAVE_SYS_LOCK_H
41#  include <sys/lock.h>
42# endif
43# include <sys/rtprio.h>
44#else
45# ifdef HAVE_PLOCK
46#  ifdef HAVE_SYS_LOCK_H
47#   include <sys/lock.h>
48#  endif
49# endif
50#endif
51#if defined(HAVE_SCHED_SETSCHEDULER)
52# include <sched.h>
53#endif
54#if defined(HAVE_SYS_MMAN_H)
55# include <sys/mman.h>
56#endif
57
58#ifdef HAVE_TERMIOS_H
59# include <termios.h>
60#endif
61
62#ifdef SYS_DOMAINOS
63# include <apollo/base.h>
64#endif /* SYS_DOMAINOS */
65
66#include "ntpd.h"
67#include "ntp_select.h"
68#include "ntp_io.h"
69#include "ntp_stdlib.h"
70
71#if 0                           /* HMS: I don't think we need this. 961223 */
72#ifdef LOCK_PROCESS
73# ifdef SYS_SOLARIS
74#  include <sys/mman.h>
75# else
76#  include <sys/lock.h>
77# endif
78#endif
79#endif
80
81/*
82 * Signals we catch for debugging.  If not debugging we ignore them.
83 */
84#define MOREDEBUGSIG    SIGUSR1
85#define LESSDEBUGSIG    SIGUSR2
86
87/*
88 * Signals which terminate us gracefully.
89 */
90#ifndef SYS_WINNT
91# define        SIGDIE1         SIGHUP
92# define        SIGDIE3         SIGQUIT
93#endif /* SYS_WINNT */
94#define SIGDIE2         SIGINT
95#define SIGDIE4         SIGTERM
96
97#ifdef SYS_WINNT
98/* handles for various threads, process, and objects */
99extern HANDLE hServDoneEvent;
100HANDLE  process_handle = NULL, WorkerThreadHandle = NULL,
101  ResolverThreadHandle = NULL, TimerThreadHandle = NULL,
102  hMutex = NULL;
103/* variables used to inform the Service Control Manager of our current state */
104SERVICE_STATUS ssStatus;
105SERVICE_STATUS_HANDLE   sshStatusHandle;
106int was_stopped = 0;
107char szMsgPath[255];
108#endif /* SYS_WINNT */
109
110/*
111 * Scheduling priority we run at
112 */
113#define NTPD_PRIO       (-12)
114
115/*
116 * Debugging flag
117 */
118volatile int debug;
119
120/*
121 * -x and -g flags
122*/
123extern int allow_set_backward;
124int correct_any;
125/*
126 * Initializing flag.  All async routines watch this and only do their
127 * thing when it is clear.
128 */
129int initializing;
130
131/*
132 * Version declaration
133 */
134extern char *Version;
135
136/* Added mutex to prevent race condition among threads under Windows NT */
137#ifdef SYS_WINNT
138HANDLE m_hListMutex;
139#endif /* SYS_WINNT */
140
141/*
142 * Alarm flag.  Imported from timer module
143 */
144extern int alarm_flag;
145
146int was_alarmed;
147
148#ifdef DECL_SYSCALL
149/*
150 * We put this here, since the argument profile is syscall-specific
151 */
152extern int syscall      P((int, struct timeval *, struct timeval *));
153#endif /* DECL_SYSCALL */
154
155#ifdef SYS_WINNT
156extern void worker_thread(void *);
157#endif /* SYS_WINNT */
158       
159#ifdef  SIGDIE2
160static  RETSIGTYPE      finish          P((int));
161#endif  /* SIGDIE2 */
162
163#ifdef  DEBUG
164static  RETSIGTYPE      moredebug       P((int));
165static  RETSIGTYPE      lessdebug       P((int));
166#else /* not DEBUG */
167static  RETSIGTYPE      no_debug        P((int));
168#endif  /* not DEBUG */
169
170#ifdef NO_MAIN_ALLOWED
171CALL(xntpd,"xntpd",xntpdmain);
172#endif
173
174/*
175 * Main program.  Initialize us, disconnect us from the tty if necessary,
176 * and loop waiting for I/O and/or timer expiries.
177 */
178#if !defined(VMS)
179void
180#endif /* VMS */
181#ifndef NO_MAIN_ALLOWED
182main
183#else
184xntpdmain
185#endif
186(argc, argv)
187     int argc;
188     char *argv[];
189{
190#ifndef SYS_WINNT
191  char *cp;
192  struct recvbuf *rbuflist;
193  struct recvbuf *rbuf;
194#endif
195
196  initializing = 1;             /* mark that we are initializing */
197  debug = 0;                    /* no debugging by default */
198
199#ifdef HAVE_UMASK     
200  /* vxWorks does not have umask */
201  {
202    int uv;
203
204    uv = umask(0);
205    if(uv)
206      (void) umask(uv);
207    else
208      (void) umask(022);
209  }
210#endif
211
212#ifdef HAVE_GETUID
213  {
214    uid_t uid;
215
216    uid = getuid();
217    if (uid)
218      {
219        msyslog(LOG_ERR, "xntpd: must be run as root, not uid %d", uid);
220        exit(1);
221      }
222  }
223#endif
224
225#ifdef SYS_WINNT
226  /* Set the Event-ID message-file name. */
227  if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) {
228    msyslog(LOG_ERR, "GetModuleFileName(PGM_EXE_FILE) failed: %m\n");
229    exit(1);
230  }
231  addSourceToRegistry("NTP", szMsgPath);
232#endif
233
234  getstartup(argc, argv);       /* startup configuration, may set debug */
235
236#if !defined(VMS)
237# ifndef NODETACH
238  /*
239   * Detach us from the terminal.  May need an #ifndef GIZMO.
240   */
241#  ifdef DEBUG
242  if (!debug)
243    {
244#  endif /* DEBUG */
245#  ifndef SYS_WINNT
246#   ifdef HAVE_DAEMON
247      daemon(0, 0);
248#   else /* not HAVE_DAEMON */
249      if (fork())
250        exit(0);
251
252      {
253        u_long s;
254        int max_fd;
255
256#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
257        max_fd = sysconf(_SC_OPEN_MAX);
258#else /* HAVE_SYSCONF && _SC_OPEN_MAX */
259        max_fd = getdtablesize();
260#endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
261        for (s = 0; s < max_fd; s++)
262          (void) close(s);
263        (void) open("/", 0);
264        (void) dup2(0, 1);
265        (void) dup2(0, 2);
266#ifdef SYS_DOMAINOS
267        {
268          uid_$t puid;
269          status_$t st;
270
271          proc2_$who_am_i(&puid);
272          proc2_$make_server(&puid, &st);
273        }
274#endif /* SYS_DOMAINOS */
275#if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
276# ifdef HAVE_SETSID
277        if (setsid() == (pid_t)-1)
278          msyslog(LOG_ERR, "xntpd: setsid(): %m");
279# else
280        if (setpgid(0, 0) == -1)
281          msyslog(LOG_ERR, "xntpd: setpgid(): %m");
282# endif
283#else /* HAVE_SETPGID || HAVE_SETSID */
284        {
285          int fid;
286
287          fid = open("/dev/tty", 2);
288          if (fid >= 0)
289            {
290              (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
291              (void) close(fid);
292            }
293# ifdef HAVE_SETPGRP_O
294          (void) setpgrp();
295# else /* HAVE_SETPGRP_0 */
296          (void) setpgrp(0, getpid());
297# endif /* HAVE_SETPGRP_0 */
298        }
299#endif /* HAVE_SETPGID || HAVE_SETSID */
300      }
301#endif /* not HAVE_DAEMON */
302#else /* SYS_WINNT */
303
304      {
305        SERVICE_TABLE_ENTRY dispatchTable[] = {
306          { TEXT("NetworkTimeProtocol"), (LPSERVICE_MAIN_FUNCTION)service_main },
307          { NULL, NULL }
308        };
309
310      /* daemonize */
311      if (!StartServiceCtrlDispatcher(dispatchTable))
312        {
313          if (!was_stopped)
314            {
315              msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m");
316              ExitProcess(2);
317            }
318          else
319            {
320              NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
321                msyslog(LOG_INFO, "StartServiceCtrlDispatcher: service stopped");
322              ExitProcess(0);
323            }
324        }
325      }
326#endif /* SYS_WINNT */
327#ifdef  DEBUG
328    }
329#endif /* DEBUG */
330#endif /* NODETACH */
331#if defined(SYS_WINNT) && !defined(NODETACH)
332#if defined(DEBUG)
333  else
334    service_main(argc, argv);
335#endif
336} /* end main */
337
338/*
339 * If this runs as a service under NT, the main thread will block at
340 * StartServiceCtrlDispatcher() and another thread will be started by the
341 * Service Control Dispatcher which will begin execution at the routine
342 * specified in that call (viz. service_main)
343 */
344void
345service_main(argc, argv)
346     DWORD argc;
347     LPTSTR *argv;
348{
349  char *cp;
350  DWORD dwWait;
351
352  if(!debug)
353    {
354      /* register our service control handler */
355      if (!(sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"),
356                                                          (LPHANDLER_FUNCTION)service_ctrl)))
357        {
358          msyslog(LOG_ERR, "RegisterServiceCtrlHandler failed: %m");
359          return;
360        }
361
362      /* report pending status to Service Control Manager */
363      ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
364      ssStatus.dwCurrentState = SERVICE_START_PENDING;
365      ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
366      ssStatus.dwWin32ExitCode = NO_ERROR;
367      ssStatus.dwServiceSpecificExitCode = 0;
368      ssStatus.dwCheckPoint = 1;
369      ssStatus.dwWaitHint = 5000;
370      if (!SetServiceStatus(sshStatusHandle, &ssStatus))
371        {
372          msyslog(LOG_ERR, "SetServiceStatus: %m");
373          ssStatus.dwCurrentState = SERVICE_STOPPED;
374          SetServiceStatus(sshStatusHandle, &ssStatus);
375          return;
376        }
377
378    /*
379     * create an event object that the control handler function
380     * will signal when it receives the "stop" control code
381     */
382    if (!(hServDoneEvent = CreateEvent(
383                                       NULL,    /* no security attributes */
384                                       TRUE,    /* manual reset event */
385                                       FALSE,   /* not-signalled */
386                                       NULL)))  /* no name */
387      {
388        msyslog(LOG_ERR, "CreateEvent failed: %m");
389        ssStatus.dwCurrentState = SERVICE_STOPPED;
390        SetServiceStatus(sshStatusHandle, &ssStatus);
391        return;
392      }
393    }  /* debug */
394#endif /* defined(SYS_WINNT) && !defined(NODETACH) */
395#endif /* VMS */
396
397  /*
398   * Logging.  This may actually work on the gizmo board.  Find a name
399   * to log with by using the basename of argv[0]
400   */
401  cp = strrchr(argv[0], '/');
402  if (cp == 0)
403    cp = argv[0];
404  else
405    cp++;
406
407  debug = 0; /* will be immediately re-initialized 8-( */
408  getstartup(argc, argv);       /* startup configuration, catch logfile this time */
409
410#if !defined(SYS_WINNT) && !defined(VMS)
411
412# ifndef LOG_DAEMON
413  openlog(cp, LOG_PID);
414# else /* LOG_DAEMON */
415
416#  ifndef LOG_NTP
417#   define      LOG_NTP LOG_DAEMON
418#  endif
419  openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
420#  ifdef DEBUG
421  if (debug)
422    setlogmask(LOG_UPTO(LOG_DEBUG));
423  else
424#  endif /* DEBUG */
425    setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
426# endif /* LOG_DAEMON */
427
428#endif  /* !SYS_WINNT && !VMS */
429
430  NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
431    msyslog(LOG_NOTICE, "%s", Version);
432
433#ifdef SYS_WINNT
434  /* GMS 1/18/1997
435   * TODO: lock the process in memory using SetProcessWorkingSetSize() and VirtualLock() functions
436   *
437    process_handle = GetCurrentProcess();
438        if (SetProcessWorkingSetSize(process_handle, 2097152 , 4194304 ) == TRUE) {
439                if (VirtualLock(0 , 4194304) == FALSE)
440                        msyslog(LOG_ERR, "VirtualLock() failed: %m");
441        } else {
442                msyslog(LOG_ERR, "SetProcessWorkingSetSize() failed: %m");
443        }
444        */
445#endif /* SYS_WINNT */
446
447#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE)
448  /*
449   * lock the process into memory
450   */
451  if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0)
452    msyslog(LOG_ERR, "mlockall(): %m");
453#else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
454# ifdef HAVE_PLOCK
455#  ifdef PROCLOCK
456  /*
457   * lock the process into memory
458   */
459  if (plock(PROCLOCK) < 0)
460    msyslog(LOG_ERR, "plock(PROCLOCK): %m");
461#  else /* not PROCLOCK */
462#   ifdef TXTLOCK
463  /*
464   * Lock text into ram
465   */
466  if (plock(TXTLOCK) < 0)
467    msyslog(LOG_ERR, "plock(TXTLOCK) error: %m");
468#   else /* not TXTLOCK */
469  msyslog(LOG_ERR, "plock() - don't know what to lock!");
470#   endif /* not TXTLOCK */
471#  endif /* not PROCLOCK */
472# endif /* HAVE_PLOCK */
473#endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
474
475  /*
476   * Set the priority.
477   */
478#ifdef SYS_WINNT
479  process_handle = GetCurrentProcess();
480  if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS))
481    {
482      msyslog(LOG_ERR, "SetPriorityClass: %m");
483    }
484
485  /* Added mutex to prevent race condition among threads under Windows NT */
486  if ((m_hListMutex = CreateMutex(NULL,FALSE,NULL)) == NULL)
487    msyslog(LOG_ERR, "CreateMutex: %m");
488#else  /* not SYS_WINNT */
489# if defined(HAVE_SCHED_SETSCHEDULER)
490  {
491    struct sched_param sched;
492    sched.sched_priority = sched_get_priority_min(SCHED_FIFO);
493    if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 )
494    {
495      msyslog(LOG_ERR, "sched_setscheduler(): %m");
496    }
497  }
498# else /* not HAVE_SCHED_SETSCHEDULER */
499#  if defined(HAVE_RTPRIO)
500#   ifdef RTP_SET
501  {
502    struct rtprio srtp;
503
504    srtp.type = RTP_PRIO_REALTIME;      /* was: RTP_PRIO_NORMAL */
505    srtp.prio = 0;              /* 0 (hi) -> RTP_PRIO_MAX (31,lo) */
506
507    if (rtprio(RTP_SET, getpid(), &srtp) < 0)
508      msyslog(LOG_ERR, "rtprio() error: %m");
509  }
510#   else /* not RTP_SET */
511  if (rtprio(0, 120) < 0)
512    msyslog(LOG_ERR, "rtprio() error: %m");
513#   endif /* not RTP_SET */
514#  else  /* not HAVE_RTPRIO */
515#   if defined(NTPD_PRIO) && NTPD_PRIO != 0
516#    ifdef HAVE_ATT_NICE
517  nice (NTPD_PRIO);
518#    endif /* HAVE_ATT_NICE */
519#    ifdef HAVE_BSD_NICE
520  (void) setpriority(PRIO_PROCESS, 0, NTPD_PRIO);
521#    endif /* HAVE_BSD_NICE */
522#   endif /* NTPD_PRIO && NTPD_PRIO != 0 */
523#  endif /* not HAVE_RTPRIO */
524# endif /* not HAVE_SCHED_SETSCHEDULER */
525#endif /* not SYS_WINNT */
526
527  /*
528   * Set up signals we pay attention to locally.
529   */
530# ifdef SIGDIE1
531  (void) signal_no_reset(SIGDIE1, finish);
532# endif /* SIGDIE1 */
533# ifdef SIGDIE2
534  (void) signal_no_reset(SIGDIE2, finish);
535# endif /* SIGDIE2 */
536# ifdef SIGDIE3
537  (void) signal_no_reset(SIGDIE3, finish);
538# endif /* SIGDIE3 */
539# ifdef SIGDIE4
540  (void) signal_no_reset(SIGDIE4, finish);
541# endif /* SIGDIE4 */
542
543#ifdef SIGBUS
544  (void) signal_no_reset(SIGBUS, finish);
545#endif /* SIGBUS */
546
547#if !defined(SYS_WINNT) && !defined(VMS)
548# ifdef DEBUG
549  (void) signal_no_reset(MOREDEBUGSIG, moredebug);
550  (void) signal_no_reset(LESSDEBUGSIG, lessdebug);
551# else
552  (void) signal_no_reset(MOREDEBUGSIG, no_debug);
553  (void) signal_no_reset(LESSDEBUGSIG, no_debug);
554# endif /* DEBUG */
555#endif /* !SYS_WINNT && !VMS */
556
557  /*
558   * Set up signals we should never pay attention to.
559   */
560#ifdef SIGPIPE
561  (void) signal_no_reset(SIGPIPE, SIG_IGN);
562#endif  /* SIGPIPE */
563
564  /*
565   * Call the init_ routines to initialize the data structures.
566   * Note that init_systime() may run a protocol to get a crude
567   * estimate of the time as an NTP client when running on the
568   * gizmo board.  It is important that this be run before
569   * init_subs() since the latter uses the time of day to seed
570   * the random number generator.  That is not the only
571   * dependency between these, either, be real careful about
572   * reordering.
573   */
574  init_auth();
575  init_util();
576  init_restrict();
577  init_mon();
578  init_systime();
579  init_timer();
580  init_lib();
581  init_random();
582  init_request();
583  init_control();
584  init_leap();
585  init_peer();
586#ifdef REFCLOCK
587  init_refclock();
588#endif
589  init_proto();
590  init_io();
591  init_loopfilter();
592
593  mon_start(MON_ON);            /* monitor on by default now      */
594                                /* turn off in config if unwanted */
595
596  /*
597   * Get configuration.  This (including argument list parsing) is
598   * done in a separate module since this will definitely be different
599   * for the gizmo board.
600   */
601  getconfig(argc, argv);
602  initializing = 0;
603
604#if defined(SYS_WINNT) && !defined(NODETACH)
605# if defined(DEBUG)
606  if(!debug)
607    {
608# endif
609
610      /*
611       * the service_main() thread will have to wait for requests to
612       * start/stop/pause/continue from the services icon in the Control
613       * Panel or from any WIN32 application start a new thread to perform
614       * all the work of the NTP service
615       */
616      if (!(WorkerThreadHandle = (HANDLE)_beginthread(
617                                                      worker_thread,
618                                                      0,      /* stack size             */
619                                                      NULL))) /* argument to thread     */
620        {
621          msyslog(LOG_ERR, "_beginthread: %m");
622          if (hServDoneEvent != NULL)
623            CloseHandle(hServDoneEvent);
624          if (ResolverThreadHandle != NULL)
625            CloseHandle(ResolverThreadHandle);
626          ssStatus.dwCurrentState = SERVICE_STOPPED;
627          SetServiceStatus(sshStatusHandle, &ssStatus);
628          return;
629        }
630
631      /* report to the service control manager that the service is running */
632      ssStatus.dwCurrentState = SERVICE_RUNNING;
633      ssStatus.dwWin32ExitCode = NO_ERROR;
634      if (!SetServiceStatus(sshStatusHandle, &ssStatus))
635        {
636          msyslog(LOG_ERR, "SetServiceStatus: %m");
637          if (hServDoneEvent != NULL)
638            CloseHandle(hServDoneEvent);
639          if (ResolverThreadHandle != NULL)
640            CloseHandle(ResolverThreadHandle);
641          ssStatus.dwCurrentState = SERVICE_STOPPED;
642          SetServiceStatus(sshStatusHandle, &ssStatus);
643          return;
644        }
645
646      /* wait indefinitely until hServDoneEvent is signaled */
647      dwWait = WaitForSingleObject(hServDoneEvent,INFINITE);
648      if (hServDoneEvent != NULL)
649        CloseHandle(hServDoneEvent);
650      if (ResolverThreadHandle != NULL)
651        CloseHandle(ResolverThreadHandle);
652      if (WorkerThreadHandle != NULL)
653        CloseHandle(WorkerThreadHandle);
654      if (TimerThreadHandle != NULL)
655        CloseHandle(TimerThreadHandle);
656      /* restore the clock frequency back to its original value */
657      if (!SetSystemTimeAdjustment((DWORD)0, TRUE))
658        msyslog(LOG_ERR, "Failed to reset clock frequency, SetSystemTimeAdjustment(): %m");
659      ssStatus.dwCurrentState = SERVICE_STOPPED;
660      SetServiceStatus(sshStatusHandle, &ssStatus);
661      return;
662# if defined(DEBUG)
663    }
664  else
665    worker_thread( (void *) 0 );
666# endif
667} /* end service_main() */
668
669
670/*
671 * worker_thread - perform all remaining functions after initialization and and becoming a service
672 */
673void
674worker_thread(notUsed)
675     void *notUsed;
676{
677  struct recvbuf *rbuflist;
678  struct recvbuf *rbuf;
679
680#endif /* defined(SYS_WINNT) && !defined(NODETACH) */
681
682  /*
683   * Report that we're up to any trappers
684   */
685  report_event(EVNT_SYSRESTART, (struct peer *)0);
686
687  /*
688   * Use select() on all on all input fd's for unlimited
689   * time.  select() will terminate on SIGALARM or on the
690   * reception of input.  Using select() means we can't do
691   * robust signal handling and we get a potential race
692   * between checking for alarms and doing the select().
693   * Mostly harmless, I think.
694   */
695  /*
696   * Under NT, a timer periodically invokes a callback function
697   * on a different thread. This callback function has no way
698   * of interrupting a winsock "select" call on a different
699   * thread. A mutex is used to synchronize access to clock
700   * related variables between the two threads (one blocking
701   * on a select or processing the received packets and the
702   * other that calls the timer callback function, timer(),
703   * every second). Due to this change, timer() routine can
704   * be invoked between  processing two or more received
705   * packets, or even during processing a single received
706   * packet before entering the clock_update routine (if
707   * needed). The potential race condition is also avoided.
708   */
709  /* On VMS, I suspect that select() can't be interrupted
710   * by a "signal" either, so I take the easy way out and
711   * have select() time out after one second.
712   * System clock updates really aren't time-critical,
713   * and - lacking a hardware reference clock - I have
714   * yet to learn about anything else that is.
715   */
716  was_alarmed = 0;
717  rbuflist = (struct recvbuf *)0;
718  for (;;)
719    {
720#ifndef HAVE_SIGNALED_IO
721      extern fd_set activefds;
722      extern int maxactivefd;
723
724      fd_set rdfdes;
725      int nfound;
726#else
727      block_io_and_alarm();
728#endif
729
730      rbuflist = getrecvbufs(); /* get received buffers */
731      if (alarm_flag)           /* alarmed? */
732        {
733          was_alarmed = 1;
734          alarm_flag = 0;
735        }
736
737      if (!was_alarmed && rbuflist == (struct recvbuf *)0)
738        {
739          /*
740           * Nothing to do.  Wait for something.
741           */
742#ifndef HAVE_SIGNALED_IO
743          rdfdes = activefds;
744#if defined(VMS) || defined(SYS_VXWORKS)
745          /* make select() wake up after one second */
746          {
747            struct timeval t1;
748
749            t1.tv_sec = 1; t1.tv_usec = 0;
750            nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
751                            (fd_set *)0, &t1);
752          }
753#else
754          nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
755                          (fd_set *)0, (struct timeval *)0);
756#endif /* VMS */
757          if (nfound > 0)
758            {
759              l_fp ts;
760
761              get_systime(&ts);
762         
763              (void)input_handler(&ts);
764            }
765          else if (
766#ifndef SYS_WINNT
767                   (nfound == -1 && errno != EINTR)
768#else /* SYS_WINNT */
769                   (nfound == SOCKET_ERROR && WSAGetLastError() != WSAEINTR)
770#endif /* SYS_WINNT */
771                   )
772            msyslog(LOG_ERR, "select() error: %m");
773          else if (debug)
774#ifndef SYS_VXWORKS
775            msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
776#endif
777#else
778          wait_for_signal();
779#endif
780          if (alarm_flag)               /* alarmed? */
781            {
782              was_alarmed = 1;
783              alarm_flag = 0;
784            }
785          rbuflist = getrecvbufs();  /* get received buffers */
786        }
787#ifdef HAVE_SIGNALED_IO
788      unblock_io_and_alarm();
789#endif /* HAVE_SIGNALED_IO */
790
791      /*
792       * Out here, signals are unblocked.  Call timer routine
793       * to process expiry.
794       */
795#ifndef SYS_WINNT
796      /*
797       * under WinNT, the timer() routine is directly called
798       * by the timer callback function (alarming)
799       * was_alarmed should have never been set, but don't
800       * want to risk timer() being accidently called here
801       */
802      if (was_alarmed)
803        {
804          timer();
805          was_alarmed = 0;
806        }
807#endif /* SYS_WINNT */
808
809      /*
810       * Call the data procedure to handle each received
811       * packet.
812       */
813      while (rbuflist != (struct recvbuf *)0)
814        {
815          rbuf = rbuflist;
816          rbuflist = rbuf->next;
817          (rbuf->receiver)(rbuf);
818          freerecvbuf(rbuf);
819        }
820      /*
821       * Go around again
822       */
823    }
824}
825
826
827#ifdef SIGDIE2
828/*
829 * finish - exit gracefully
830 */
831static RETSIGTYPE
832finish(sig)
833     int sig;
834{
835
836  msyslog(LOG_NOTICE, "xntpd exiting on signal %d", sig);
837
838#ifdef SYS_WINNT
839  /*
840   * with any exit(0)'s in the worker_thread, the service_main()
841   * thread needs to be informed to quit also
842   */
843  SetEvent(hServDoneEvent);
844#endif /* SYS_WINNT */
845
846  switch (sig)
847    {
848#ifdef SIGBUS
849    case SIGBUS:
850        printf("\nfinish(SIGBUS)\n");
851#endif
852    case 0:                     /* Should never happen... */
853      return;
854    default:
855      exit(0);
856    }
857}
858#endif  /* SIGDIE2 */
859
860
861#ifdef DEBUG
862/*
863 * moredebug - increase debugging verbosity
864 */
865static RETSIGTYPE
866moredebug(sig)
867     int sig;
868{
869  int saved_errno = errno;
870
871  if (debug < 255)
872    {
873      debug++;
874      msyslog(LOG_DEBUG, "debug raised to %d", debug);
875    }
876  errno = saved_errno;
877}
878
879/*
880 * lessdebug - decrease debugging verbosity
881 */
882static RETSIGTYPE
883lessdebug(sig)
884     int sig;
885{
886  int saved_errno = errno;
887
888  if (debug > 0)
889    {
890      debug--;
891      msyslog(LOG_DEBUG, "debug lowered to %d", debug);
892    }
893  errno = saved_errno;
894}
895#else /* not DEBUG */
896/*
897 * no_debug - We don't do the debug here.
898 */
899static RETSIGTYPE
900no_debug(sig)
901     int sig;
902{
903  int saved_errno = errno;
904
905  msyslog(LOG_DEBUG, "xntpd not compiled for debugging (signal %d)", sig);
906  errno = saved_errno;
907}
908#endif  /* not DEBUG */
909
910#ifdef SYS_WINNT
911/* service_ctrl - control handler for NTP service
912 * signals the service_main routine of start/stop requests
913 * from the control panel or other applications making
914 * win32API calls
915 */
916void
917service_ctrl(dwCtrlCode)
918     DWORD dwCtrlCode;
919{
920  DWORD  dwState = SERVICE_RUNNING;
921
922  /* Handle the requested control code */
923  switch(dwCtrlCode)
924    {
925    case SERVICE_CONTROL_PAUSE:
926      /* see no reason to support this */
927      break;
928
929    case SERVICE_CONTROL_CONTINUE:
930      /* see no reason to support this */
931      break;
932
933    case SERVICE_CONTROL_STOP:
934      dwState = SERVICE_STOP_PENDING;
935      /*
936       * Report the status, specifying the checkpoint and waithint,
937       *  before setting the termination event.
938       */
939      ssStatus.dwCurrentState = dwState;
940      ssStatus.dwWin32ExitCode = NO_ERROR;
941      ssStatus.dwWaitHint = 3000;
942      if (!SetServiceStatus(sshStatusHandle, &ssStatus))
943        {
944          msyslog(LOG_ERR, "SetServiceStatus: %m");
945        }
946      was_stopped = 1;
947      SetEvent(hServDoneEvent);
948      return;
949
950    case SERVICE_CONTROL_INTERROGATE:
951      /* Update the service status */
952      break;
953
954    default:
955      /* invalid control code */
956      break;
957
958    }
959
960  ssStatus.dwCurrentState = dwState;
961  ssStatus.dwWin32ExitCode = NO_ERROR;
962  if (!SetServiceStatus(sshStatusHandle, &ssStatus))
963    {
964      msyslog(LOG_ERR, "SetServiceStatus: %m");
965    }
966}
967#endif /* SYS_WINNT */
Note: See TracBrowser for help on using the repository browser.