/contrib/ntp/ntpd/ntp_timer.c
https://bitbucket.org/freebsd/freebsd-head/ · C · 407 lines · 283 code · 42 blank · 82 comment · 60 complexity · 11a832ddbdc6c696ad9a46d0f21b0a01 MD5 · raw file
- /*
- * ntp_timer.c - event timer support routines
- */
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include "ntp_machine.h"
- #include "ntpd.h"
- #include "ntp_stdlib.h"
- #include <stdio.h>
- #include <signal.h>
- #ifdef HAVE_SYS_SIGNAL_H
- # include <sys/signal.h>
- #endif
- #ifdef HAVE_UNISTD_H
- # include <unistd.h>
- #endif
- #if defined(HAVE_IO_COMPLETION_PORT)
- # include "ntp_iocompletionport.h"
- # include "ntp_timer.h"
- #endif
- /*
- * 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.
- */
- volatile int interface_interval = 300; /* update interface every 5 minutes as default */
-
- /*
- * Alarm flag. The mainline code imports this.
- */
- volatile int alarm_flag;
- /*
- * The counters
- */
- static u_long adjust_timer; /* second timer */
- static u_long keys_timer; /* minute timer */
- static u_long stats_timer; /* stats timer */
- static u_long huffpuff_timer; /* huff-n'-puff timer */
- static u_long interface_timer; /* interface update timer */
- #ifdef OPENSSL
- static u_long revoke_timer; /* keys revoke timer */
- u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
- #endif /* OPENSSL */
- /*
- * Statistics counter for the interested.
- */
- volatile u_long alarm_overflow;
- #define MINUTE 60
- #define HOUR (60*60)
- u_long current_time;
- /*
- * Stats. Number of overflows and number of calls to transmit().
- */
- u_long timer_timereset;
- u_long timer_overflows;
- u_long timer_xmtcalls;
- #if defined(VMS)
- static int vmstimer[2]; /* time for next timer AST */
- static int vmsinc[2]; /* timer increment */
- #endif /* VMS */
- #if defined SYS_WINNT
- static HANDLE WaitableTimerHandle = NULL;
- #else
- static RETSIGTYPE alarming P((int));
- #endif /* SYS_WINNT */
- #if !defined(VMS)
- # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
- # ifndef HAVE_TIMER_SETTIME
- struct itimerval itimer;
- # else
- static timer_t ntpd_timerid;
- struct itimerspec itimer;
- # endif /* HAVE_TIMER_SETTIME */
- # endif /* SYS_WINNT */
- #endif /* VMS */
- /*
- * reinit_timer - reinitialize interval timer.
- */
- void
- reinit_timer(void)
- {
- #if !defined(SYS_WINNT) && !defined(VMS)
- # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
- timer_gettime(ntpd_timerid, &itimer);
- if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
- itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- }
- if (itimer.it_value.tv_nsec < 0 ) {
- itimer.it_value.tv_nsec = 0;
- }
- if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
- itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_value.tv_nsec = 0;
- }
- itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_interval.tv_nsec = 0;
- timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
- # else
- getitimer(ITIMER_REAL, &itimer);
- if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
- itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- }
- if (itimer.it_value.tv_usec < 0 ) {
- itimer.it_value.tv_usec = 0;
- }
- if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
- itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_value.tv_usec = 0;
- }
- itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_interval.tv_usec = 0;
- setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
- # endif
- # endif /* VMS */
- }
- /*
- * init_timer - initialize the timer data structures
- */
- void
- init_timer(void)
- {
- # if defined SYS_WINNT & !defined(SYS_CYGWIN32)
- HANDLE hToken = INVALID_HANDLE_VALUE;
- TOKEN_PRIVILEGES tkp;
- # endif /* SYS_WINNT */
- /*
- * Initialize...
- */
- alarm_flag = 0;
- alarm_overflow = 0;
- adjust_timer = 1;
- stats_timer = 0;
- huffpuff_timer = 0;
- interface_timer = 0;
- current_time = 0;
- timer_overflows = 0;
- timer_xmtcalls = 0;
- timer_timereset = 0;
- #if !defined(SYS_WINNT)
- /*
- * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
- * seconds from now and they continue on every 2**EVENT_TIMEOUT
- * seconds.
- */
- # if !defined(VMS)
- # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
- if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
- # ifdef SYS_VXWORKS
- ERROR
- # else
- -1
- # endif
- )
- {
- fprintf (stderr, "timer create FAILED\n");
- exit (0);
- }
- (void) signal_no_reset(SIGALRM, alarming);
- itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
- timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
- # else
- (void) signal_no_reset(SIGALRM, alarming);
- itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
- itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
- setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
- # endif
- # else /* VMS */
- vmsinc[0] = 10000000; /* 1 sec */
- vmsinc[1] = 0;
- lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
- sys$gettim(&vmstimer); /* that's "now" as abstime */
- lib$addx(&vmsinc, &vmstimer, &vmstimer);
- sys$setimr(0, &vmstimer, alarming, alarming, 0);
- # endif /* VMS */
- #else /* SYS_WINNT */
- _tzset();
- /*
- * Get privileges needed for fiddling with the clock
- */
- /* get the current process token handle */
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
- msyslog(LOG_ERR, "OpenProcessToken failed: %m");
- exit(1);
- }
- /* get the LUID for system-time privilege. */
- LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
- tkp.PrivilegeCount = 1; /* one privilege to set */
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- /* get set-time privilege for this process. */
- AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
- /* cannot test return value of AdjustTokenPrivileges. */
- if (GetLastError() != ERROR_SUCCESS) {
- msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
- }
- /*
- * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
- * Under Windows/NT,
- */
- WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
- if (WaitableTimerHandle == NULL) {
- msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
- exit(1);
- }
- else {
- DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
- LARGE_INTEGER DueTime;
- DueTime.QuadPart = Period * 10000i64;
- if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
- msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
- exit(1);
- }
- }
- #endif /* SYS_WINNT */
- }
- #if defined(SYS_WINNT)
- extern HANDLE
- get_timer_handle(void)
- {
- return WaitableTimerHandle;
- }
- #endif
- /*
- * timer - dispatch anyone who needs to be
- */
- void
- timer(void)
- {
- register struct peer *peer, *next_peer;
- #ifdef OPENSSL
- char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
- #endif /* OPENSSL */
- u_int n;
- current_time += (1<<EVENT_TIMEOUT);
- /*
- * Adjustment timeout first.
- */
- if (adjust_timer <= current_time) {
- adjust_timer += 1;
- adj_host_clock();
- kod_proto();
- #ifdef REFCLOCK
- for (n = 0; n < NTP_HASH_SIZE; n++) {
- for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
- next_peer = peer->next;
- if (peer->flags & FLAG_REFCLOCK)
- refclock_timer(peer);
- }
- }
- #endif /* REFCLOCK */
- }
- /*
- * Now dispatch any peers whose event timer has expired. Be careful
- * here, since the peer structure might go away as the result of
- * the call.
- */
- for (n = 0; n < NTP_HASH_SIZE; n++) {
- for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
- next_peer = peer->next;
- if (peer->action && peer->nextaction <= current_time)
- peer->action(peer);
- if (peer->nextdate <= current_time) {
- #ifdef REFCLOCK
- if (peer->flags & FLAG_REFCLOCK)
- refclock_transmit(peer);
- else
- transmit(peer);
- #else /* REFCLOCK */
- transmit(peer);
- #endif /* REFCLOCK */
- }
- }
- }
- /*
- * Garbage collect expired keys.
- */
- if (keys_timer <= current_time) {
- keys_timer += MINUTE;
- auth_agekeys();
- }
- /*
- * Huff-n'-puff filter
- */
- if (huffpuff_timer <= current_time) {
- huffpuff_timer += HUFFPUFF;
- huffpuff();
- }
- #ifdef OPENSSL
- /*
- * Garbage collect old keys and generate new private value
- */
- if (revoke_timer <= current_time) {
- revoke_timer += RANDPOLL(sys_revoke);
- expire_all();
- sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp));
- record_crypto_stats(NULL, statstr);
- #ifdef DEBUG
- if (debug)
- printf("timer: %s\n", statstr);
- #endif
- }
- #endif /* OPENSSL */
- /*
- * interface update timer
- */
- if (interface_interval && interface_timer <= current_time) {
- timer_interfacetimeout(current_time + interface_interval);
- DPRINTF(1, ("timer: interface update\n"));
- interface_update(NULL, NULL);
- }
-
- /*
- * Finally, periodically write stats.
- */
- if (stats_timer <= current_time) {
- if (stats_timer != 0)
- write_stats();
- stats_timer += stats_write_period;
- }
- }
- #ifndef SYS_WINNT
- /*
- * alarming - tell the world we've been alarmed
- */
- static RETSIGTYPE
- alarming(
- int sig
- )
- {
- #if !defined(VMS)
- if (initializing)
- return;
- if (alarm_flag)
- alarm_overflow++;
- else
- alarm_flag++;
- #else /* VMS AST routine */
- if (!initializing) {
- if (alarm_flag) alarm_overflow++;
- else alarm_flag = 1; /* increment is no good */
- }
- lib$addx(&vmsinc,&vmstimer,&vmstimer);
- sys$setimr(0,&vmstimer,alarming,alarming,0);
- #endif /* VMS */
- }
- #endif /* SYS_WINNT */
- void
- timer_interfacetimeout(u_long timeout)
- {
- interface_timer = timeout;
- }
- /*
- * timer_clr_stats - clear timer module stat counters
- */
- void
- timer_clr_stats(void)
- {
- timer_overflows = 0;
- timer_xmtcalls = 0;
- timer_timereset = current_time;
- }