1/* $NetBSD: correct.c,v 1.13 2007/01/26 16:12:41 christos Exp $ */ 2 3/*- 4 * Copyright (c) 1985, 1993 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34#if 0 35static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93"; 36#else 37__RCSID("$NetBSD: correct.c,v 1.13 2007/01/26 16:12:41 christos Exp $"); 38#endif 39#endif /* not lint */ 40 41#include "globals.h" 42#include <math.h> 43#include <sys/types.h> 44#include <sys/times.h> 45 46static void adjclock(struct timeval*); 47 48/* 49 * sends to the slaves the corrections for their clocks after fixing our 50 * own 51 */ 52void 53correct(long avdelta) 54{ 55 struct hosttbl *htp; 56 long corr; 57 struct timeval adjlocal, tmptv; 58 struct tsp to; 59 struct tsp *answer; 60 61 mstotvround(&adjlocal, avdelta); 62 63 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 64 if (htp->delta != HOSTDOWN) { 65 corr = avdelta - htp->delta; 66/* If the other machine is off in the weeds, set its time directly. 67 * If a slave gets the wrong day, the original code would simply 68 * fix the minutes. If you fix a network partition, you can get 69 * into such situations. 70 */ 71 if (htp->need_set 72 || corr >= MAXADJ*1000 73 || corr <= -MAXADJ*1000) { 74 htp->need_set = 0; 75 (void)gettimeofday(&tmptv,0); 76 timeradd(&tmptv, &adjlocal, &tmptv); 77 to.tsp_time.tv_sec = tmptv.tv_sec; 78 to.tsp_time.tv_usec = tmptv.tv_usec; 79 to.tsp_type = TSP_SETTIME; 80 } else { 81 tmptv.tv_sec = to.tsp_time.tv_sec ; 82 tmptv.tv_usec = to.tsp_time.tv_usec ; 83 mstotvround(&tmptv, corr); 84 to.tsp_time.tv_sec = tmptv.tv_sec; 85 to.tsp_time.tv_usec = tmptv.tv_usec; 86 to.tsp_type = TSP_ADJTIME; 87 } 88 set_tsp_name(&to, hostname); 89 answer = acksend(&to, &htp->addr, htp->name, 90 TSP_ACK, 0, 0); 91 if (!answer) { 92 htp->delta = HOSTDOWN; 93 syslog(LOG_WARNING, 94 "no reply to time correction from %s", 95 htp->name); 96 if (++htp->noanswer >= LOSTHOST) { 97 if (trace) { 98 fprintf(fd, 99 "purging %s for not answering\n", 100 htp->name); 101 (void)fflush(fd); 102 } 103 htp = remmach(htp); 104 } 105 } 106 } 107 } 108 109 /* 110 * adjust our own clock now that we are not sending it out 111 */ 112 adjclock(&adjlocal); 113} 114 115 116static void 117adjclock(struct timeval *corr) 118{ 119 static int passes = 0; 120 static int smoother = 0; 121 long delta; /* adjustment in usec */ 122 long ndelta; 123 struct timeval now; 124 struct timeval adj; 125 126 if (!timerisset(corr)) 127 return; 128 129 adj = *corr; 130 if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) { 131 delta = adj.tv_sec*1000000 + adj.tv_usec; 132 /* If the correction is less than the minimum round 133 * trip time for an ICMP packet, and thus 134 * less than the likely error in the measurement, 135 * do not do the entire correction. Do half 136 * or a quarter of it. 137 */ 138 139 if (delta > -MIN_ROUND*1000 140 && delta < MIN_ROUND*1000) { 141 if (smoother <= 4) 142 smoother++; 143 ndelta = (unsigned long)delta >> smoother; 144 if (delta < 0) { 145 long mask = (long)~0 & 146 ~((1 << ((sizeof(long) * NBBY) - smoother)) 147 - 1); 148 ndelta |= mask; 149 } 150 if (trace) 151 fprintf(fd, 152 "trimming delta %ld usec to %ld\n", 153 delta, ndelta); 154 adj.tv_usec = ndelta; 155 adj.tv_sec = 0; 156 } else if (smoother > 0) { 157 smoother--; 158 } 159 if (0 > adjtime(corr, 0)) { 160 syslog(LOG_ERR, "adjtime: %m"); 161 } 162 if (passes > 1 163 && (delta < -BIG_ADJ || delta > BIG_ADJ)) { 164 smoother = 0; 165 passes = 0; 166 syslog(LOG_WARNING, 167 "large time adjustment of %+.3f sec", 168 delta/1000000.0); 169 } 170 } else { 171 syslog(LOG_WARNING, 172 "clock correction %ld sec too large to adjust", 173 (long)adj.tv_sec); 174 (void) gettimeofday(&now, 0); 175 timeradd(&now, corr, &now); 176 if (settimeofday(&now, 0) < 0) 177 syslog(LOG_ERR, "settimeofday: %m"); 178 } 179} 180 181 182/* adjust the time in a message by the time it 183 * spent in the queue 184 */ 185void 186adj_msg_time(struct tsp *msg, struct timeval *now) 187{ 188 struct timeval diff; 189 190 timersub(now, &from_when, &diff); 191 timeradd(&msg->tsp_time, &diff, &msg->tsp_time); 192} 193