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