11553Srgrimes/*-
21553Srgrimes * Copyright (c) 1985, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 4. Neither the name of the University nor the names of its contributors
141553Srgrimes *    may be used to endorse or promote products derived from this software
151553Srgrimes *    without specific prior written permission.
161553Srgrimes *
171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271553Srgrimes * SUCH DAMAGE.
281553Srgrimes */
291553Srgrimes
301553Srgrimes#ifndef lint
3130642Scharnier#if 0
321553Srgrimesstatic char sccsid[] = "@(#)correct.c	8.1 (Berkeley) 6/6/93";
3330642Scharnier#endif
3430642Scharnierstatic const char rcsid[] =
3550479Speter  "$FreeBSD$";
361553Srgrimes#endif /* not lint */
371553Srgrimes
381553Srgrimes#include "globals.h"
391553Srgrimes#include <math.h>
401553Srgrimes#include <sys/types.h>
411553Srgrimes#include <sys/times.h>
421553Srgrimes
43173412Skevlostatic void adjclock(struct timeval *);
441553Srgrimes
451553Srgrimes/*
461553Srgrimes * sends to the slaves the corrections for their clocks after fixing our
471553Srgrimes * own
481553Srgrimes */
491553Srgrimesvoid
50246209Scharniercorrect(long avdelta)
511553Srgrimes{
521553Srgrimes	struct hosttbl *htp;
531553Srgrimes	int corr;
5486644Sjhb	struct timeval adjlocal, tmptv;
551553Srgrimes	struct tsp to;
561553Srgrimes	struct tsp *answer;
571553Srgrimes
581553Srgrimes	mstotvround(&adjlocal, avdelta);
591553Srgrimes
601553Srgrimes	for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
611553Srgrimes		if (htp->delta != HOSTDOWN)  {
621553Srgrimes			corr = avdelta - htp->delta;
631553Srgrimes/* If the other machine is off in the weeds, set its time directly.
641553Srgrimes *	If a slave gets the wrong day, the original code would simply
651553Srgrimes *	fix the minutes.  If you fix a network partition, you can get
661553Srgrimes *	into such situations.
671553Srgrimes */
681553Srgrimes			if (htp->need_set
691553Srgrimes			    || corr >= MAXADJ*1000
701553Srgrimes			    || corr <= -MAXADJ*1000) {
711553Srgrimes				htp->need_set = 0;
7286644Sjhb				(void)gettimeofday(&tmptv,0);
7386644Sjhb				timevaladd(&tmptv, &adjlocal);
7486644Sjhb				to.tsp_time.tv_sec = tmptv.tv_sec;
7586644Sjhb				to.tsp_time.tv_usec = tmptv.tv_usec;
761553Srgrimes				to.tsp_type = TSP_SETTIME;
771553Srgrimes			} else {
7886644Sjhb				tmptv.tv_sec = to.tsp_time.tv_sec;
7986644Sjhb				tmptv.tv_usec = to.tsp_time.tv_usec;
8086644Sjhb				mstotvround(&tmptv, corr);
8186644Sjhb				to.tsp_time.tv_sec = tmptv.tv_sec;
8286644Sjhb				to.tsp_time.tv_usec = tmptv.tv_usec;
831553Srgrimes				to.tsp_type = TSP_ADJTIME;
841553Srgrimes			}
8530830Scharnier			(void)strcpy(to.tsp_name, hostname);
861553Srgrimes			answer = acksend(&to, &htp->addr, htp->name,
871553Srgrimes					 TSP_ACK, 0, 0);
881553Srgrimes			if (!answer) {
891553Srgrimes				htp->delta = HOSTDOWN;
901553Srgrimes				syslog(LOG_WARNING,
911553Srgrimes				       "no reply to time correction from %s",
921553Srgrimes				       htp->name);
931553Srgrimes				if (++htp->noanswer >= LOSTHOST) {
941553Srgrimes					if (trace) {
951553Srgrimes						fprintf(fd,
961553Srgrimes					     "purging %s for not answering\n",
971553Srgrimes							htp->name);
981553Srgrimes						(void)fflush(fd);
991553Srgrimes					}
1001553Srgrimes					htp = remmach(htp);
1011553Srgrimes				}
1021553Srgrimes			}
1031553Srgrimes		}
1041553Srgrimes	}
1051553Srgrimes
1061553Srgrimes	/*
1071553Srgrimes	 * adjust our own clock now that we are not sending it out
1081553Srgrimes	 */
1091553Srgrimes	adjclock(&adjlocal);
1101553Srgrimes}
1111553Srgrimes
1121553Srgrimes
1131553Srgrimesstatic void
114246209Scharnieradjclock(struct timeval *corr)
1151553Srgrimes{
1161553Srgrimes	static int passes = 0;
1171553Srgrimes	static int smoother = 0;
1181553Srgrimes	long delta;			/* adjustment in usec */
1191553Srgrimes	long ndelta;
1201553Srgrimes	struct timeval now;
1211553Srgrimes	struct timeval adj;
1221553Srgrimes
1231553Srgrimes	if (!timerisset(corr))
1241553Srgrimes		return;
1251553Srgrimes
1261553Srgrimes	adj = *corr;
1271553Srgrimes	if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
1281553Srgrimes		delta = adj.tv_sec*1000000 + adj.tv_usec;
1291553Srgrimes		/* If the correction is less than the minimum round
1301553Srgrimes		 *	trip time for an ICMP packet, and thus
1311553Srgrimes		 *	less than the likely error in the measurement,
1321553Srgrimes		 *	do not do the entire correction.  Do half
1331553Srgrimes		 *	or a quarter of it.
1341553Srgrimes		 */
1351553Srgrimes
1361553Srgrimes		if (delta > -MIN_ROUND*1000
1371553Srgrimes		    && delta < MIN_ROUND*1000) {
1381553Srgrimes			if (smoother <= 4)
1391553Srgrimes				smoother++;
1401553Srgrimes			ndelta = delta >> smoother;
1411553Srgrimes			if (trace)
1421553Srgrimes				fprintf(fd,
1431553Srgrimes					"trimming delta %ld usec to %ld\n",
1441553Srgrimes					delta, ndelta);
1451553Srgrimes			adj.tv_usec = ndelta;
1461553Srgrimes			adj.tv_sec = 0;
1471553Srgrimes		} else if (smoother > 0) {
1481553Srgrimes			smoother--;
1491553Srgrimes		}
1501553Srgrimes		if (0 > adjtime(corr, 0)) {
1511553Srgrimes			syslog(LOG_ERR, "adjtime: %m");
1521553Srgrimes		}
1531553Srgrimes		if (passes > 1
1541553Srgrimes		    && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
1551553Srgrimes			smoother = 0;
1561553Srgrimes			passes = 0;
1571553Srgrimes			syslog(LOG_WARNING,
1581553Srgrimes			       "large time adjustment of %+.3f sec",
1591553Srgrimes			       delta/1000000.0);
1601553Srgrimes		}
1611553Srgrimes	} else {
1621553Srgrimes		syslog(LOG_WARNING,
163228719Sdim		       "clock correction %jd sec too large to adjust",
164228719Sdim		       (intmax_t)adj.tv_sec);
1651553Srgrimes		(void) gettimeofday(&now, 0);
1661553Srgrimes		timevaladd(&now, corr);
1671553Srgrimes		if (settimeofday(&now, 0) < 0)
1681553Srgrimes			syslog(LOG_ERR, "settimeofday: %m");
1691553Srgrimes	}
1701553Srgrimes}
1711553Srgrimes
1721553Srgrimes
1731553Srgrimes/* adjust the time in a message by the time it
1741553Srgrimes *	spent in the queue
1751553Srgrimes */
1761553Srgrimesvoid
177246209Scharnieradj_msg_time(struct tsp *msg, struct timeval *now)
1781553Srgrimes{
1791553Srgrimes	msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec);
1801553Srgrimes	msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec);
1811553Srgrimes
1821553Srgrimes	while (msg->tsp_time.tv_usec < 0) {
1831553Srgrimes		msg->tsp_time.tv_sec--;
1841553Srgrimes		msg->tsp_time.tv_usec += 1000000;
1851553Srgrimes	}
1861553Srgrimes	while (msg->tsp_time.tv_usec >= 1000000) {
1871553Srgrimes		msg->tsp_time.tv_sec++;
1881553Srgrimes		msg->tsp_time.tv_usec -= 1000000;
1891553Srgrimes	}
1901553Srgrimes}
191