Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / timed / timed / correct.c
CommitLineData
984263bc
MD
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 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35#if 0
36static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93";
37#endif
38static const char rcsid[] =
39 "$FreeBSD: src/usr.sbin/timed/timed/correct.c,v 1.4 1999/08/28 01:20:17 peter Exp $";
40#endif /* not lint */
41
42#include "globals.h"
43#include <math.h>
44#include <sys/types.h>
45#include <sys/times.h>
46#ifdef sgi
47#include <sys/syssgi.h>
48#endif /* sgi */
49
50static void adjclock __P((struct timeval *));
51
52/*
53 * sends to the slaves the corrections for their clocks after fixing our
54 * own
55 */
56void
57correct(avdelta)
58 long avdelta;
59{
60 struct hosttbl *htp;
61 int corr;
62 struct timeval adjlocal;
63 struct tsp to;
64 struct tsp *answer;
65
66 mstotvround(&adjlocal, avdelta);
67
68 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
69 if (htp->delta != HOSTDOWN) {
70 corr = avdelta - htp->delta;
71/* If the other machine is off in the weeds, set its time directly.
72 * If a slave gets the wrong day, the original code would simply
73 * fix the minutes. If you fix a network partition, you can get
74 * into such situations.
75 */
76 if (htp->need_set
77 || corr >= MAXADJ*1000
78 || corr <= -MAXADJ*1000) {
79 htp->need_set = 0;
80 (void)gettimeofday(&to.tsp_time,0);
81 timevaladd(&to.tsp_time, &adjlocal);
82 to.tsp_type = TSP_SETTIME;
83 } else {
84 mstotvround(&to.tsp_time, corr);
85 to.tsp_type = TSP_ADJTIME;
86 }
87 (void)strcpy(to.tsp_name, hostname);
88 answer = acksend(&to, &htp->addr, htp->name,
89 TSP_ACK, 0, 0);
90 if (!answer) {
91 htp->delta = HOSTDOWN;
92 syslog(LOG_WARNING,
93 "no reply to time correction from %s",
94 htp->name);
95 if (++htp->noanswer >= LOSTHOST) {
96 if (trace) {
97 fprintf(fd,
98 "purging %s for not answering\n",
99 htp->name);
100 (void)fflush(fd);
101 }
102 htp = remmach(htp);
103 }
104 }
105 }
106 }
107
108 /*
109 * adjust our own clock now that we are not sending it out
110 */
111 adjclock(&adjlocal);
112}
113
114
115static void
116adjclock(corr)
117 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 = delta >> smoother;
144 if (trace)
145 fprintf(fd,
146 "trimming delta %ld usec to %ld\n",
147 delta, ndelta);
148 adj.tv_usec = ndelta;
149 adj.tv_sec = 0;
150 } else if (smoother > 0) {
151 smoother--;
152 }
153 if (0 > adjtime(corr, 0)) {
154 syslog(LOG_ERR, "adjtime: %m");
155 }
156 if (passes > 1
157 && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
158 smoother = 0;
159 passes = 0;
160 syslog(LOG_WARNING,
161 "large time adjustment of %+.3f sec",
162 delta/1000000.0);
163 }
164 } else {
165 syslog(LOG_WARNING,
166 "clock correction %d sec too large to adjust",
167 adj.tv_sec);
168 (void) gettimeofday(&now, 0);
169 timevaladd(&now, corr);
170 if (settimeofday(&now, 0) < 0)
171 syslog(LOG_ERR, "settimeofday: %m");
172 }
173
174#ifdef sgi
175 /* Accumulate the total change, and use it to adjust the basic
176 * clock rate.
177 */
178 if (++passes > 2) {
179#define F_USEC_PER_SEC (1000000*1.0) /* reduce typos */
180#define F_NSEC_PER_SEC (F_USEC_PER_SEC*1000.0)
181
182 extern char *timetrim_fn;
183 extern char *timetrim_wpat;
184 extern long timetrim;
185 extern double tot_adj, hr_adj; /* totals in nsec */
186 extern double tot_ticks, hr_ticks;
187
188 static double nag_tick;
189 double cur_ticks, hr_delta_ticks, tot_delta_ticks;
190 double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */
191 double tot_trim, hr_trim; /* nsec/sec */
192 struct tms tm;
193 FILE *timetrim_st;
194
195 cur_ticks = times(&tm);
196 tot_adj += delta*1000.0;
197 hr_adj += delta*1000.0;
198
199 tot_delta_ticks = cur_ticks-tot_ticks;
200 if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) {
201 tot_adj -= rint(tot_adj/16);
202 tot_ticks += rint(tot_delta_ticks/16);
203 tot_delta_ticks = cur_ticks-tot_ticks;
204 }
205 hr_delta_ticks = cur_ticks-hr_ticks;
206
207 tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK);
208 tru_tot_adj = (tot_adj
209 + timetrim*rint(tot_delta_ticks/CLK_TCK));
210
211 if (hr_delta_ticks >= SECDAY*CLK_TCK
212 || (tot_delta_ticks < 4*SECDAY*CLK_TCK
213 && hr_delta_ticks >= SECHR*CLK_TCK)
214 || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) {
215
216 tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks);
217 hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks);
218
219 if (trace
220 || (abs(timetrim - hr_trim) > 100000.0
221 && 0 == timetrim_fn
222 && ((cur_ticks - nag_tick)
223 >= 24*SECDAY*CLK_TCK))) {
224 nag_tick = cur_ticks;
225 syslog(LOG_NOTICE,
226 "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f",
227 tru_tot_adj/F_NSEC_PER_SEC,
228 tot_delta_ticks/(SECHR*CLK_TCK*1.0),
229 tru_hr_adj/F_NSEC_PER_SEC,
230 hr_delta_ticks/(SECHR*CLK_TCK*1.0),
231 tot_trim,
232 hr_trim);
233 }
234
235 if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) {
236 tot_ticks = hr_ticks;
237 tot_adj = hr_adj;
238 } else if (0 > syssgi(SGI_SETTIMETRIM,
239 (long)tot_trim)) {
240 syslog(LOG_ERR, "SETTIMETRIM(%d): %m",
241 (long)tot_trim);
242 } else {
243 if (0 != timetrim_fn) {
244 timetrim_st = fopen(timetrim_fn, "w");
245 if (0 == timetrim_st) {
246 syslog(LOG_ERR, "fopen(%s): %m",
247 timetrim_fn);
248 } else {
249 if (0 > fprintf(timetrim_st,
250 timetrim_wpat,
251 (long)tot_trim,
252 tru_tot_adj,
253 tot_delta_ticks)) {
254 syslog(LOG_ERR,
255 "fprintf(%s): %m",
256 timetrim_fn);
257 }
258 (void)fclose(timetrim_st);
259 }
260 }
261
262 tot_adj -= ((tot_trim - timetrim)
263 * rint(tot_delta_ticks/CLK_TCK));
264 timetrim = tot_trim;
265 }
266
267 hr_ticks = cur_ticks;
268 hr_adj = 0;
269 }
270 }
271#endif /* sgi */
272}
273
274
275/* adjust the time in a message by the time it
276 * spent in the queue
277 */
278void
279adj_msg_time(msg, now)
280 struct tsp *msg;
281 struct timeval *now;
282{
283 msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec);
284 msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec);
285
286 while (msg->tsp_time.tv_usec < 0) {
287 msg->tsp_time.tv_sec--;
288 msg->tsp_time.tv_usec += 1000000;
289 }
290 while (msg->tsp_time.tv_usec >= 1000000) {
291 msg->tsp_time.tv_sec++;
292 msg->tsp_time.tv_usec -= 1000000;
293 }
294}