correct.c revision 86644
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 * 3. All advertising materials mentioning features or use of this software
141553Srgrimes *    must display the following acknowledgement:
151553Srgrimes *	This product includes software developed by the University of
161553Srgrimes *	California, Berkeley and its contributors.
171553Srgrimes * 4. Neither the name of the University nor the names of its contributors
181553Srgrimes *    may be used to endorse or promote products derived from this software
191553Srgrimes *    without specific prior written permission.
201553Srgrimes *
211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311553Srgrimes * SUCH DAMAGE.
321553Srgrimes */
331553Srgrimes
341553Srgrimes#ifndef lint
3530642Scharnier#if 0
361553Srgrimesstatic char sccsid[] = "@(#)correct.c	8.1 (Berkeley) 6/6/93";
3730642Scharnier#endif
3830642Scharnierstatic const char rcsid[] =
3950479Speter  "$FreeBSD: head/usr.sbin/timed/timed/correct.c 86644 2001-11-20 06:36:09Z jhb $";
401553Srgrimes#endif /* not lint */
411553Srgrimes
421553Srgrimes#include "globals.h"
431553Srgrimes#include <math.h>
441553Srgrimes#include <sys/types.h>
451553Srgrimes#include <sys/times.h>
461553Srgrimes#ifdef sgi
471553Srgrimes#include <sys/syssgi.h>
481553Srgrimes#endif /* sgi */
491553Srgrimes
501553Srgrimesstatic void adjclock __P((struct timeval *));
511553Srgrimes
521553Srgrimes/*
531553Srgrimes * sends to the slaves the corrections for their clocks after fixing our
541553Srgrimes * own
551553Srgrimes */
561553Srgrimesvoid
571553Srgrimescorrect(avdelta)
581553Srgrimes	long avdelta;
591553Srgrimes{
601553Srgrimes	struct hosttbl *htp;
611553Srgrimes	int corr;
6286644Sjhb	struct timeval adjlocal, tmptv;
631553Srgrimes	struct tsp to;
641553Srgrimes	struct tsp *answer;
651553Srgrimes
661553Srgrimes	mstotvround(&adjlocal, avdelta);
671553Srgrimes
681553Srgrimes	for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
691553Srgrimes		if (htp->delta != HOSTDOWN)  {
701553Srgrimes			corr = avdelta - htp->delta;
711553Srgrimes/* If the other machine is off in the weeds, set its time directly.
721553Srgrimes *	If a slave gets the wrong day, the original code would simply
731553Srgrimes *	fix the minutes.  If you fix a network partition, you can get
741553Srgrimes *	into such situations.
751553Srgrimes */
761553Srgrimes			if (htp->need_set
771553Srgrimes			    || corr >= MAXADJ*1000
781553Srgrimes			    || corr <= -MAXADJ*1000) {
791553Srgrimes				htp->need_set = 0;
8086644Sjhb				(void)gettimeofday(&tmptv,0);
8186644Sjhb				timevaladd(&tmptv, &adjlocal);
8286644Sjhb				to.tsp_time.tv_sec = tmptv.tv_sec;
8386644Sjhb				to.tsp_time.tv_usec = tmptv.tv_usec;
841553Srgrimes				to.tsp_type = TSP_SETTIME;
851553Srgrimes			} else {
8686644Sjhb				tmptv.tv_sec = to.tsp_time.tv_sec;
8786644Sjhb				tmptv.tv_usec = to.tsp_time.tv_usec;
8886644Sjhb				mstotvround(&tmptv, corr);
8986644Sjhb				to.tsp_time.tv_sec = tmptv.tv_sec;
9086644Sjhb				to.tsp_time.tv_usec = tmptv.tv_usec;
911553Srgrimes				to.tsp_type = TSP_ADJTIME;
921553Srgrimes			}
9330830Scharnier			(void)strcpy(to.tsp_name, hostname);
941553Srgrimes			answer = acksend(&to, &htp->addr, htp->name,
951553Srgrimes					 TSP_ACK, 0, 0);
961553Srgrimes			if (!answer) {
971553Srgrimes				htp->delta = HOSTDOWN;
981553Srgrimes				syslog(LOG_WARNING,
991553Srgrimes				       "no reply to time correction from %s",
1001553Srgrimes				       htp->name);
1011553Srgrimes				if (++htp->noanswer >= LOSTHOST) {
1021553Srgrimes					if (trace) {
1031553Srgrimes						fprintf(fd,
1041553Srgrimes					     "purging %s for not answering\n",
1051553Srgrimes							htp->name);
1061553Srgrimes						(void)fflush(fd);
1071553Srgrimes					}
1081553Srgrimes					htp = remmach(htp);
1091553Srgrimes				}
1101553Srgrimes			}
1111553Srgrimes		}
1121553Srgrimes	}
1131553Srgrimes
1141553Srgrimes	/*
1151553Srgrimes	 * adjust our own clock now that we are not sending it out
1161553Srgrimes	 */
1171553Srgrimes	adjclock(&adjlocal);
1181553Srgrimes}
1191553Srgrimes
1201553Srgrimes
1211553Srgrimesstatic void
1221553Srgrimesadjclock(corr)
1231553Srgrimes	struct timeval *corr;
1241553Srgrimes{
1251553Srgrimes	static int passes = 0;
1261553Srgrimes	static int smoother = 0;
1271553Srgrimes	long delta;			/* adjustment in usec */
1281553Srgrimes	long ndelta;
1291553Srgrimes	struct timeval now;
1301553Srgrimes	struct timeval adj;
1311553Srgrimes
1321553Srgrimes	if (!timerisset(corr))
1331553Srgrimes		return;
1341553Srgrimes
1351553Srgrimes	adj = *corr;
1361553Srgrimes	if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
1371553Srgrimes		delta = adj.tv_sec*1000000 + adj.tv_usec;
1381553Srgrimes		/* If the correction is less than the minimum round
1391553Srgrimes		 *	trip time for an ICMP packet, and thus
1401553Srgrimes		 *	less than the likely error in the measurement,
1411553Srgrimes		 *	do not do the entire correction.  Do half
1421553Srgrimes		 *	or a quarter of it.
1431553Srgrimes		 */
1441553Srgrimes
1451553Srgrimes		if (delta > -MIN_ROUND*1000
1461553Srgrimes		    && delta < MIN_ROUND*1000) {
1471553Srgrimes			if (smoother <= 4)
1481553Srgrimes				smoother++;
1491553Srgrimes			ndelta = delta >> smoother;
1501553Srgrimes			if (trace)
1511553Srgrimes				fprintf(fd,
1521553Srgrimes					"trimming delta %ld usec to %ld\n",
1531553Srgrimes					delta, ndelta);
1541553Srgrimes			adj.tv_usec = ndelta;
1551553Srgrimes			adj.tv_sec = 0;
1561553Srgrimes		} else if (smoother > 0) {
1571553Srgrimes			smoother--;
1581553Srgrimes		}
1591553Srgrimes		if (0 > adjtime(corr, 0)) {
1601553Srgrimes			syslog(LOG_ERR, "adjtime: %m");
1611553Srgrimes		}
1621553Srgrimes		if (passes > 1
1631553Srgrimes		    && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
1641553Srgrimes			smoother = 0;
1651553Srgrimes			passes = 0;
1661553Srgrimes			syslog(LOG_WARNING,
1671553Srgrimes			       "large time adjustment of %+.3f sec",
1681553Srgrimes			       delta/1000000.0);
1691553Srgrimes		}
1701553Srgrimes	} else {
1711553Srgrimes		syslog(LOG_WARNING,
1721553Srgrimes		       "clock correction %d sec too large to adjust",
1731553Srgrimes		       adj.tv_sec);
1741553Srgrimes		(void) gettimeofday(&now, 0);
1751553Srgrimes		timevaladd(&now, corr);
1761553Srgrimes		if (settimeofday(&now, 0) < 0)
1771553Srgrimes			syslog(LOG_ERR, "settimeofday: %m");
1781553Srgrimes	}
1791553Srgrimes
1801553Srgrimes#ifdef sgi
1811553Srgrimes	/* Accumulate the total change, and use it to adjust the basic
1821553Srgrimes	 * clock rate.
1831553Srgrimes	 */
1841553Srgrimes	if (++passes > 2) {
1851553Srgrimes#define F_USEC_PER_SEC	(1000000*1.0)	/* reduce typos */
1861553Srgrimes#define F_NSEC_PER_SEC	(F_USEC_PER_SEC*1000.0)
1871553Srgrimes
1881553Srgrimes		extern char *timetrim_fn;
1891553Srgrimes		extern char *timetrim_wpat;
1901553Srgrimes		extern long timetrim;
1911553Srgrimes		extern double tot_adj, hr_adj;	/* totals in nsec */
1921553Srgrimes		extern double tot_ticks, hr_ticks;
1931553Srgrimes
1941553Srgrimes		static double nag_tick;
1951553Srgrimes		double cur_ticks, hr_delta_ticks, tot_delta_ticks;
1961553Srgrimes		double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */
1971553Srgrimes		double tot_trim, hr_trim;   /* nsec/sec */
1981553Srgrimes		struct tms tm;
1991553Srgrimes		FILE *timetrim_st;
2001553Srgrimes
2011553Srgrimes		cur_ticks = times(&tm);
2021553Srgrimes		tot_adj += delta*1000.0;
2031553Srgrimes		hr_adj += delta*1000.0;
2041553Srgrimes
2051553Srgrimes		tot_delta_ticks = cur_ticks-tot_ticks;
2061553Srgrimes		if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) {
2071553Srgrimes			tot_adj -= rint(tot_adj/16);
2081553Srgrimes			tot_ticks += rint(tot_delta_ticks/16);
2091553Srgrimes			tot_delta_ticks = cur_ticks-tot_ticks;
2101553Srgrimes		}
2111553Srgrimes		hr_delta_ticks = cur_ticks-hr_ticks;
2121553Srgrimes
2131553Srgrimes		tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK);
2141553Srgrimes		tru_tot_adj = (tot_adj
2151553Srgrimes			       + timetrim*rint(tot_delta_ticks/CLK_TCK));
2161553Srgrimes
2171553Srgrimes		if (hr_delta_ticks >= SECDAY*CLK_TCK
2181553Srgrimes		    || (tot_delta_ticks < 4*SECDAY*CLK_TCK
2191553Srgrimes			&& hr_delta_ticks >= SECHR*CLK_TCK)
2201553Srgrimes		    || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) {
2211553Srgrimes
2221553Srgrimes			tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks);
2231553Srgrimes			hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks);
2241553Srgrimes
2251553Srgrimes			if (trace
2261553Srgrimes			    || (abs(timetrim - hr_trim) > 100000.0
2271553Srgrimes				&& 0 == timetrim_fn
2281553Srgrimes				&& ((cur_ticks - nag_tick)
2291553Srgrimes				    >= 24*SECDAY*CLK_TCK))) {
2301553Srgrimes				nag_tick = cur_ticks;
2311553Srgrimes				syslog(LOG_NOTICE,
2321553Srgrimes		   "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f",
2331553Srgrimes				       tru_tot_adj/F_NSEC_PER_SEC,
2341553Srgrimes				       tot_delta_ticks/(SECHR*CLK_TCK*1.0),
2351553Srgrimes				       tru_hr_adj/F_NSEC_PER_SEC,
2361553Srgrimes				       hr_delta_ticks/(SECHR*CLK_TCK*1.0),
2371553Srgrimes				       tot_trim,
2381553Srgrimes				       hr_trim);
2391553Srgrimes			}
2401553Srgrimes
2411553Srgrimes			if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) {
2421553Srgrimes				tot_ticks = hr_ticks;
2431553Srgrimes				tot_adj = hr_adj;
2441553Srgrimes			} else if (0 > syssgi(SGI_SETTIMETRIM,
2451553Srgrimes					      (long)tot_trim)) {
2461553Srgrimes				syslog(LOG_ERR, "SETTIMETRIM(%d): %m",
2471553Srgrimes				       (long)tot_trim);
2481553Srgrimes			} else {
2491553Srgrimes				if (0 != timetrim_fn) {
2501553Srgrimes				    timetrim_st = fopen(timetrim_fn, "w");
2511553Srgrimes				    if (0 == timetrim_st) {
2521553Srgrimes					syslog(LOG_ERR, "fopen(%s): %m",
2531553Srgrimes					       timetrim_fn);
2541553Srgrimes				    } else {
2551553Srgrimes					if (0 > fprintf(timetrim_st,
2561553Srgrimes							timetrim_wpat,
2571553Srgrimes							(long)tot_trim,
2581553Srgrimes							tru_tot_adj,
2591553Srgrimes							tot_delta_ticks)) {
2601553Srgrimes						syslog(LOG_ERR,
2611553Srgrimes						       "fprintf(%s): %m",
2621553Srgrimes						       timetrim_fn);
2631553Srgrimes					}
2641553Srgrimes					(void)fclose(timetrim_st);
2651553Srgrimes				    }
2661553Srgrimes				}
2671553Srgrimes
2681553Srgrimes				tot_adj -= ((tot_trim - timetrim)
2691553Srgrimes					    * rint(tot_delta_ticks/CLK_TCK));
2701553Srgrimes				timetrim = tot_trim;
2711553Srgrimes			}
2721553Srgrimes
2731553Srgrimes			hr_ticks = cur_ticks;
2741553Srgrimes			hr_adj = 0;
2751553Srgrimes		}
2761553Srgrimes	}
2771553Srgrimes#endif /* sgi */
2781553Srgrimes}
2791553Srgrimes
2801553Srgrimes
2811553Srgrimes/* adjust the time in a message by the time it
2821553Srgrimes *	spent in the queue
2831553Srgrimes */
2841553Srgrimesvoid
2851553Srgrimesadj_msg_time(msg, now)
2861553Srgrimes	struct tsp *msg;
2871553Srgrimes	struct timeval *now;
2881553Srgrimes{
2891553Srgrimes	msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec);
2901553Srgrimes	msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec);
2911553Srgrimes
2921553Srgrimes	while (msg->tsp_time.tv_usec < 0) {
2931553Srgrimes		msg->tsp_time.tv_sec--;
2941553Srgrimes		msg->tsp_time.tv_usec += 1000000;
2951553Srgrimes	}
2961553Srgrimes	while (msg->tsp_time.tv_usec >= 1000000) {
2971553Srgrimes		msg->tsp_time.tv_sec++;
2981553Srgrimes		msg->tsp_time.tv_usec -= 1000000;
2991553Srgrimes	}
3001553Srgrimes}
301