summaryrefslogtreecommitdiffstats
path: root/ntpd/ntp_timer.c
diff options
context:
space:
mode:
authorroberto <roberto@FreeBSD.org>2008-08-17 17:37:33 +0000
committerroberto <roberto@FreeBSD.org>2008-08-17 17:37:33 +0000
commit4ded1c1fa0bc21c61f91a2dbe864835986745121 (patch)
tree16d100fbc9dae63888d48b464e471ba0e5065193 /ntpd/ntp_timer.c
parent8b5a86d4fda08a9c68231415812edcb26be52f79 (diff)
downloadFreeBSD-src-4ded1c1fa0bc21c61f91a2dbe864835986745121.zip
FreeBSD-src-4ded1c1fa0bc21c61f91a2dbe864835986745121.tar.gz
Flatten the dist and various 4.n.n trees in preparation of future ntp imports.
Diffstat (limited to 'ntpd/ntp_timer.c')
-rw-r--r--ntpd/ntp_timer.c377
1 files changed, 377 insertions, 0 deletions
diff --git a/ntpd/ntp_timer.c b/ntpd/ntp_timer.c
new file mode 100644
index 0000000..6f0f18b
--- /dev/null
+++ b/ntpd/ntp_timer.c
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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 hourly_timer; /* hour timer */
+static u_long huffpuff_timer; /* huff-n'-puff 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;
+ TOKEN_PRIVILEGES tkp;
+# endif /* SYS_WINNT */
+
+ /*
+ * Initialize...
+ */
+ alarm_flag = 0;
+ alarm_overflow = 0;
+ adjust_timer = 1;
+ hourly_timer = HOUR;
+ huffpuff_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();
+ }
+
+ /*
+ * 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 < 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 */
+
+ /*
+ * Finally, call the hourly routine.
+ */
+ if (hourly_timer <= current_time) {
+ hourly_timer += HOUR;
+ hourly_stats();
+ }
+}
+
+
+#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 */
+
+
+/*
+ * timer_clr_stats - clear timer module stat counters
+ */
+void
+timer_clr_stats(void)
+{
+ timer_overflows = 0;
+ timer_xmtcalls = 0;
+ timer_timereset = current_time;
+}
+
OpenPOWER on IntegriCloud