1 /* $NetBSD: correct.c,v 1.14 2007/05/17 00:36:12 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
35 static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93";
36 #else
37 __RCSID("$NetBSD: correct.c,v 1.14 2007/05/17 00:36:12 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
46 static void adjclock(struct timeval*);
47
48 /*
49 * sends to the slaves the corrections for their clocks after fixing our
50 * own
51 */
52 void
correct(long avdelta)53 correct(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
116 static void
adjclock(struct timeval * corr)117 adjclock(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 */
185 void
adj_msg_time(struct tsp * msg,struct timeval * now)186 adj_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