/*
* These routines provide support for the event timer. The timer is
* implemented by a signal routine which sets a flag once every
* 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.
*/
/*
* Initializing flag. All async routines watch this and only do their
* thing when it is clear.
*/
int initializing;
/*
* Alarm flag. The mainline code imports this.
*/
volatile int alarm_flag;
/*
* The counters and timeouts
*/
u_long endpt_scan_timer; /* interface update timer */
static u_long adjust_timer; /* second timer */
static u_long stats_timer; /* stats timer */
static u_long leapf_timer; /* Report leapfile problems once/day */
static u_long huffpuff_timer; /* huff-n'-puff timer */
static u_long worker_idle_timer;/* next check for idle intres */
int endpt_scan_period; /* init_io() sets def. 301s */
u_long leapsec; /* seconds to next leap (proximity class) */
int leapdif; /* TAI difference step at next leap second*/
u_long orphwait; /* orphan wait time */
#ifdef AUTOKEY
static u_long revoke_timer; /* keys revoke timer */
static u_long keys_timer; /* session key timer */
u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
u_char sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */
#endif /* AUTOKEY */
/*
* Statistics counter for the interested.
*/
volatile u_long alarm_overflow;
u_long current_time; /* seconds since startup */
/*
* 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 */
Period = (1 << EVENT_TIMEOUT) * 1000;
DueTime.QuadPart = Period * 10000ll;
rc = SetWaitableTimer(WaitableTimerHandle, &DueTime,
Period, NULL, NULL, FALSE);
if (!rc) {
msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
exit(1);
}
}
#endif /* SYS_WINNT */
}
/*
* intres_timeout_req(s) is invoked in the parent to schedule an idle
* timeout to fire in s seconds, if not reset earlier by a call to
* intres_timeout_req(0), which clears any pending timeout. When the
* timeout expires, worker_idle_timer_fired() is invoked (again, in the
* parent).
*
* sntp and ntpd each provide implementations adapted to their timers.
*/
void
intres_timeout_req(
u_int seconds /* 0 cancels */
)
{
#if defined(HAVE_DROPROOT) && defined(NEED_EARLY_FORK)
if (droproot) {
worker_idle_timer = 0;
return;
}
#endif
if (0 == seconds) {
worker_idle_timer = 0;
return;
}
worker_idle_timer = current_time + seconds;
}
/*
* The basic timerevent is one second. This is used to adjust the
* system clock in time and frequency, implement the kiss-o'-death
* function and the association polling function.
*/
current_time++;
if (adjust_timer <= current_time) {
adjust_timer += 1;
adj_host_clock();
#ifdef REFCLOCK
for (p = peer_list; p != NULL; p = next_peer) {
next_peer = p->p_link;
if (FLAG_REFCLOCK & p->flags)
refclock_timer(p);
}
#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 (p = peer_list; p != NULL; p = next_peer) {
next_peer = p->p_link;
/*
* Restrain the non-burst packet rate not more
* than one packet every 16 seconds. This is
* usually tripped using iburst and minpoll of
* 128 s or less.
*/
if (p->throttle > 0) {
p->throttle--;
}
if (p->nextdate <= current_time) {
#ifdef REFCLOCK
if (FLAG_REFCLOCK & p->flags) {
refclock_transmit(p);
} else
#endif /* REFCLOCK */
{
transmit(p);
}
}
}
/*
* Orphan mode is active when enabled and when no servers less
* than the orphan stratum are available. A server with no other
* synchronization source is an orphan. It shows offset zero and
* reference ID the loopback address.
*
* [bug 3644] If the orphan stratum is >= STRATUM_UNSPEC, we
* have to do it a bit different. 'clock_select()' simply
* tiptoed home, but since we're unsync'd and have no peer, we
* should eventually declare we're out of sync. Otherwise we
* would persistently claim we're good, and we're everything but
* that...
*
* XXX: do we want to log an event about this?
*/
if (sys_peer == NULL && current_time > orphwait) {
if (sys_orphan < STRATUM_UNSPEC) {
if (sys_leap == LEAP_NOTINSYNC) {
set_sys_leap(LEAP_NOWARNING);
#ifdef AUTOKEY
if (crypto_flags)
crypto_update();
#endif /* AUTOKEY */
}
sys_stratum = (u_char)sys_orphan;
}
else {
if (sys_leap != LEAP_NOTINSYNC) {
set_sys_leap(LEAP_NOTINSYNC);
msyslog(LOG_WARNING, "%s",
"no peer for too long, server running free now");
}
sys_stratum = STRATUM_UNSPEC;
}
if (sys_stratum > 1)
sys_refid = htonl(LOOPBACKADR);
else
memcpy(&sys_refid, "ORPH", 4);
sys_offset = 0;
sys_rootdelay = 0;
sys_rootdisp = 0;
}
get_systime(&now);
time(&tnow);
/*
* Leapseconds. Get time and defer to worker if either something
* is imminent or every 8th second.
*/
if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7))
check_leapsec( now.l_ui
, &tnow
, (sys_leap == LEAP_NOTINSYNC));
if (sys_leap != LEAP_NOTINSYNC) {
if (leapsec >= LSPROX_ANNOUNCE && leapdif) {
if (leapdif > 0) {
set_sys_leap(LEAP_ADDSECOND);
} else {
set_sys_leap(LEAP_DELSECOND);
}
} else {
set_sys_leap(LEAP_NOWARNING);
}
}
/* We guard against panic alarming during the red alert phase.
* Strange and evil things might happen if we go from stone cold
* to piping hot in one step. If things are already that wobbly,
* we let the normal clock correction take over, even if a jump
* is involved.
* Also make sure the alarming events are edge-triggered, that is,
* created only when the threshold is crossed.
*/
if ( (leapsec > 0 || lsprox < LSPROX_ALERT)
&& leapsec < lsprox) {
if ( leapsec < LSPROX_SCHEDULE
&& lsprox >= LSPROX_SCHEDULE) {
if (lsdata.dynamic)
report_event(PEVNT_ARMED, sys_peer, NULL);
else
report_event(EVNT_ARMED, NULL, NULL);
}
leapsec = lsprox;
}
if (leapsec > lsprox) {
if ( leapsec >= LSPROX_SCHEDULE
&& lsprox < LSPROX_SCHEDULE) {
report_event(EVNT_DISARMED, NULL, NULL);
}
leapsec = lsprox;
}