#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: correct.c,v 1.14 2007/05/17 00:36:12 christos Exp $");
#endif
#endif
#include "globals.h"
#include <math.h>
#include <sys/types.h>
#include <sys/times.h>
static void adjclock(struct timeval*);
void
correct(long avdelta)
{
struct hosttbl *htp;
long corr;
struct timeval adjlocal, tmptv;
struct tsp to;
struct tsp *answer;
mstotvround(&adjlocal, avdelta);
for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
if (htp->delta != HOSTDOWN) {
corr = avdelta - htp->delta;
if (htp->need_set
|| corr >= MAXADJ*1000
|| corr <= -MAXADJ*1000) {
htp->need_set = 0;
(void)gettimeofday(&tmptv,0);
timeradd(&tmptv, &adjlocal, &tmptv);
to.tsp_time.tv_sec = tmptv.tv_sec;
to.tsp_time.tv_usec = tmptv.tv_usec;
to.tsp_type = TSP_SETTIME;
} else {
tmptv.tv_sec = to.tsp_time.tv_sec ;
tmptv.tv_usec = to.tsp_time.tv_usec ;
mstotvround(&tmptv, corr);
to.tsp_time.tv_sec = tmptv.tv_sec;
to.tsp_time.tv_usec = tmptv.tv_usec;
to.tsp_type = TSP_ADJTIME;
}
set_tsp_name(&to, hostname);
answer = acksend(&to, &htp->addr, htp->name,
TSP_ACK, 0, 0);
if (!answer) {
htp->delta = HOSTDOWN;
syslog(LOG_WARNING,
"no reply to time correction from %s",
htp->name);
if (++htp->noanswer >= LOSTHOST) {
if (trace) {
fprintf(fd,
"purging %s for not answering\n",
htp->name);
(void)fflush(fd);
}
htp = remmach(htp);
}
}
}
}
adjclock(&adjlocal);
}
static void
adjclock(struct timeval *corr)
{
static int passes = 0;
static int smoother = 0;
long delta;
long ndelta;
struct timeval now;
struct timeval adj;
if (!timerisset(corr))
return;
adj = *corr;
if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
delta = adj.tv_sec*1000000 + adj.tv_usec;
if (delta > -MIN_ROUND*1000
&& delta < MIN_ROUND*1000) {
if (smoother <= 4)
smoother++;
ndelta = (unsigned long)delta >> smoother;
if (delta < 0) {
long mask = (long)~0 &
~((1 << ((sizeof(long) * NBBY) - smoother))
- 1);
ndelta |= mask;
}
if (trace)
fprintf(fd,
"trimming delta %ld usec to %ld\n",
delta, ndelta);
adj.tv_usec = ndelta;
adj.tv_sec = 0;
} else if (smoother > 0) {
smoother--;
}
if (0 > adjtime(corr, 0)) {
syslog(LOG_ERR, "adjtime: %m");
}
if (passes > 1
&& (delta < -BIG_ADJ || delta > BIG_ADJ)) {
smoother = 0;
passes = 0;
syslog(LOG_WARNING,
"large time adjustment of %+.3f sec",
delta/1000000.0);
}
} else {
syslog(LOG_WARNING,
"clock correction %ld sec too large to adjust",
(long)adj.tv_sec);
(void) gettimeofday(&now, 0);
timeradd(&now, corr, &now);
if (settimeofday(&now, 0) < 0)
syslog(LOG_ERR, "settimeofday: %m");
}
}
void
adj_msg_time(struct tsp *msg, struct timeval *now)
{
struct timeval diff;
timersub(now, &from_when, &diff);
timeradd(&msg->tsp_time, &diff, &msg->tsp_time);
}