#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
#ifdef KERNEL_PLL
#include "ntp_syscall.h"
#endif
#ifdef OPENSSL
#include <openssl/rand.h>
#endif
#include <notify.h>
#include <sys/sysctl.h>
int use_pacemaker = 0;
int mode_wakeup;
#define TV_SLEEP 0
#define TV_WAKE 1
static struct timeval tvals[2];
volatile int interface_interval = 300;
volatile int alarm_flag;
static u_long nap_time;
static u_long interface_timer;
static u_long adjust_timer;
static u_long stats_timer;
static u_long huffpuff_timer;
u_long dns_timer;
static u_long sleep_timer;
u_long wake_timer;
static int sleep_token;
u_long leapsec;
l_fp sys_time;
#ifdef OPENSSL
static u_long revoke_timer;
static u_long keys_timer;
u_long sys_revoke = KEY_REVOKE;
u_long sys_automax = NTP_AUTOMAX;
#endif
volatile u_long alarm_overflow;
#define MINUTE 60
#define HOUR (60 * MINUTE)
#define DAY (24 * HOUR)
u_long current_time;
u_long timer_timereset;
u_long timer_overflows;
u_long timer_xmtcalls;
#if defined(VMS)
static int vmstimer[2];
static int vmsinc[2];
#endif
#if defined SYS_WINNT
static HANDLE WaitableTimerHandle = NULL;
#else
static RETSIGTYPE alarming (int);
#endif
#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
# endif
#endif
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 , &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
}
void
trigger_timer(void)
{
struct itimerval itimerval;
if (nap_time == 1) {
return;
}
getitimer(ITIMER_REAL, &itimerval);
current_time += nap_time - itimerval.it_value.tv_sec;
nap_time = 1;
itimerval.it_interval.tv_sec = itimerval.it_value.tv_sec = nap_time;
itimerval.it_interval.tv_usec = itimerval.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itimerval, NULL);
}
static int
check_sleep_wake_tv(int which)
{
int rc = 0;
struct timeval tv;
size_t tv_size = sizeof(tv);
if (0 == sysctlbyname(which ? "kern.sleeptime" : "kern.waketime", &tv, &tv_size, NULL, 0)) {
if (tv.tv_sec != tvals[which].tv_sec) {
tvals[which] = tv;
rc = 1;
}
}
return rc;
}
static RETSIGTYPE sigsleep(int sig) {
if (check_sleep_wake_tv(1)) {
wake_timer = current_time;
} else {
sleep_timer = current_time;
mode_wakeup = FALSE; }
trigger_timer();
}
void
init_timer(void)
{
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)
# 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 , &itimer, NULL);
# else
(void) signal_no_reset(SIGALRM, alarming);
nap_time = 1;
itimer.it_interval.tv_sec = itimer.it_value.tv_sec = nap_time;
itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
# endif
# else
vmsinc[0] = 10000000;
vmsinc[1] = 0;
lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
sys$gettim(&vmstimer);
lib$addx(&vmsinc, &vmstimer, &vmstimer);
sys$setimr(0, &vmstimer, alarming, alarming, 0);
# endif
#else
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
signal_no_reset(SIGINFO, sigsleep);
check_sleep_wake_tv(TV_SLEEP);
check_sleep_wake_tv(TV_WAKE);
notify_register_signal("com.apple.powermanagement.systempowerstate", SIGINFO, &sleep_token);
}
#if defined(SYS_WINNT)
extern HANDLE
get_timer_handle(void)
{
return WaitableTimerHandle;
}
#endif
static u_long update_dns_peers(void)
{
u_int n;
u_long next_update = ~0UL, curr_update;
struct peer *peer;
for (n = 0; n < NTP_HASH_SIZE; n++) {
for (peer = peer_hash[n]; peer != 0; peer = peer->next) {
if (peer->dns_update && peer->dns_update <= current_time) {
curr_update = get_dns_flags(peer->dns_name, peer);
if (curr_update < next_update)
next_update = curr_update;
}
}
}
return next_update;
}
void
timer(void)
{
register struct peer *peer, *next_peer;
u_int n;
long delta;
current_time += nap_time;
get_systime(&sys_time);
nap_time = (u_long)-1;
if (!use_pacemaker) {
if (adjust_timer <= current_time) {
adjust_timer += 1;
adj_host_clock();
#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
}
nap_time = 1;
}
if (wake_timer) {
if (wake_timer <= current_time) {
mode_wakeup = TRUE;
allow_panic = TRUE;
peer = sys_peer;
if (peer) {
transmit(peer);
} else {
for (n = 0; n < NTP_HASH_SIZE; n++) {
for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
next_peer = peer->next;
transmit(peer);
}
}
}
msyslog(LOG_DEBUG, "wake transmit");
} else {
delta = wake_timer - current_time;
if (delta < nap_time) {
nap_time = delta;
}
}
}
if (sleep_timer) {
if (sleep_timer <= current_time) {
if (check_sleep_wake_tv(TV_WAKE)) {
sleep_timer = 0;
wake_timer = current_time;
} else {
msyslog(LOG_DEBUG, "sleep noticed");
if (sleep_timer < current_time + 10) { sleep_timer = 0;
}
wake_timer = 0;
}
} else {
delta = sleep_timer - current_time;
if (delta < nap_time) {
nap_time = delta;
}
}
}
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->throttle > 0)
peer->throttle--;
if (peer->nextdate <= current_time) {
#ifdef REFCLOCK
if (peer->flags & FLAG_REFCLOCK)
refclock_transmit(peer);
else
transmit(peer);
#else
transmit(peer);
#endif
}
if (peer->action && peer->nextaction >= current_time) {
delta = peer->nextaction - current_time;
if (delta < nap_time) {
nap_time = delta;
}
} else if (peer->nextdate >= current_time) {
delta = peer->nextdate - current_time;
if (delta < nap_time) {
nap_time = delta;
}
}
}
}
if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL) {
if (sys_leap == LEAP_NOTINSYNC) {
sys_leap = LEAP_NOWARNING;
#ifdef OPENSSL
if (crypto_flags)
crypto_update();
#endif
}
sys_stratum = (u_char)sys_orphan;
if (sys_stratum > 1)
sys_refid = htonl(LOOPBACKADR);
else
memcpy(&sys_refid, "LOOP", 4);
sys_offset = 0;
sys_rootdelay = 0;
sys_rootdisp = 0;
}
if (leapsec > 0) {
leapsec--;
if (leapsec == 0) {
sys_leap = LEAP_NOWARNING;
sys_tai = leap_tai;
#ifdef KERNEL_PLL
if (!(pll_control && kern_enable))
step_systime(-1.0);
#else
#ifndef SYS_WINNT
step_systime(-1.0);
#endif
#endif
report_event(EVNT_LEAP, NULL, NULL);
} else {
if (leapsec < DAY)
sys_leap = LEAP_ADDSECOND;
if (leap_tai > 0)
sys_tai = leap_tai - 1;
}
}
if (huffpuff_timer <= current_time) {
huffpuff_timer += HUFFPUFF;
huffpuff();
}
if (huffpuff_timer >= current_time) {
delta = huffpuff_timer - current_time;
if (delta < nap_time) {
nap_time = delta;
}
}
#ifdef OPENSSL
if (keys_timer <= current_time) {
keys_timer += 1 << sys_automax;
auth_agekeys();
}
if (keys_timer >= current_time) {
delta = keys_timer - current_time;
if (delta < nap_time) {
nap_time = delta;
}
}
if (revoke_timer <= current_time && sys_leap !=
LEAP_NOTINSYNC) {
revoke_timer += 1 << sys_revoke;
RAND_bytes((u_char *)&sys_private, 4);
}
if (revoke_timer >= current_time) {
delta = revoke_timer - current_time;
if (delta < nap_time) {
nap_time = delta;
}
}
#endif
if (interface_interval && interface_timer <= current_time) {
timer_interfacetimeout(current_time +
interface_interval);
DPRINTF(2, ("timer: interface update\n"));
interface_update(NULL, NULL);
}
if (interface_interval && interface_timer >= current_time) {
delta = interface_timer - current_time;
if (delta < nap_time) {
nap_time = delta;
}
}
if (dns_timer && (dns_timer <= current_time)) {
dns_timer = update_dns_peers();
}
if (dns_timer >= current_time) {
delta = dns_timer - current_time;
if (delta < nap_time) {
nap_time = delta;
}
}
if (stats_timer <= current_time) {
stats_timer += HOUR;
write_stats();
if (sys_tai != 0 && sys_time.l_ui > leap_expire)
report_event(EVNT_LEAPVAL, NULL, NULL);
} else if (use_pacemaker && drift_file_sw) {
write_stats();
}
if (stats_timer >= current_time) {
delta = stats_timer - current_time;
if (delta < nap_time) {
nap_time = delta;
}
}
if (nap_time == 0) {
nap_time = 1;
}
if (debug) {
msyslog(LOG_INFO, "%s: current_time: %ld, nap_time: %ld", __FUNCTION__,
current_time, nap_time);
}
itimer.it_interval.tv_sec = itimer.it_value.tv_sec = nap_time;
setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
}
#ifndef SYS_WINNT
static RETSIGTYPE
alarming(
int sig
)
{
#if !defined(VMS)
if (initializing)
return;
if (alarm_flag)
alarm_overflow++;
else
alarm_flag++;
#else
if (!initializing) {
if (alarm_flag) alarm_overflow++;
else alarm_flag = 1;
}
lib$addx(&vmsinc,&vmstimer,&vmstimer);
sys$setimr(0,&vmstimer,alarming,alarming,0);
#endif
}
#endif
void
timer_interfacetimeout(u_long timeout)
{
interface_timer = timeout;
}
void
timer_clr_stats(void)
{
timer_overflows = 0;
timer_xmtcalls = 0;
timer_timereset = current_time;
}