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