]> git.saurik.com Git - apple/network_cmds.git/blob - timed.tproj/timed.tproj/correct.c
be9867705d858280b82cb5b2f9dd60b569547c9f
[apple/network_cmds.git] / timed.tproj / timed.tproj / correct.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*-
25 * Copyright (c) 1985, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57 #ifndef lint
58 static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93";
59 #endif /* not lint */
60
61 #ifdef sgi
62 #ident "$Revision: 1.1 $"
63 #endif
64
65 #include "globals.h"
66 #include <math.h>
67 #include <sys/types.h>
68 #include <sys/times.h>
69 #ifdef sgi
70 #include <sys/syssgi.h>
71 #endif /* sgi */
72
73 static void adjclock __P((struct timeval *));
74
75 /*
76 * sends to the slaves the corrections for their clocks after fixing our
77 * own
78 */
79 void
80 correct(avdelta)
81 long avdelta;
82 {
83 struct hosttbl *htp;
84 int corr;
85 struct timeval adjlocal;
86 struct tsp to;
87 struct tsp *answer;
88
89 mstotvround(&adjlocal, avdelta);
90
91 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
92 if (htp->delta != HOSTDOWN) {
93 corr = avdelta - htp->delta;
94 /* If the other machine is off in the weeds, set its time directly.
95 * If a slave gets the wrong day, the original code would simply
96 * fix the minutes. If you fix a network partition, you can get
97 * into such situations.
98 */
99 if (htp->need_set
100 || corr >= MAXADJ*1000
101 || corr <= -MAXADJ*1000) {
102 htp->need_set = 0;
103 (void)gettimeofday(&to.tsp_time,0);
104 timevaladd(&to.tsp_time, &adjlocal);
105 to.tsp_type = TSP_SETTIME;
106 } else {
107 mstotvround(&to.tsp_time, corr);
108 to.tsp_type = TSP_ADJTIME;
109 }
110 (void)strcpy(to.tsp_name, hostname);
111 answer = acksend(&to, &htp->addr, htp->name,
112 TSP_ACK, 0, 0);
113 if (!answer) {
114 htp->delta = HOSTDOWN;
115 syslog(LOG_WARNING,
116 "no reply to time correction from %s",
117 htp->name);
118 if (++htp->noanswer >= LOSTHOST) {
119 if (trace) {
120 fprintf(fd,
121 "purging %s for not answering\n",
122 htp->name);
123 (void)fflush(fd);
124 }
125 htp = remmach(htp);
126 }
127 }
128 }
129 }
130
131 /*
132 * adjust our own clock now that we are not sending it out
133 */
134 adjclock(&adjlocal);
135 }
136
137
138 static void
139 adjclock(corr)
140 struct timeval *corr;
141 {
142 static int passes = 0;
143 static int smoother = 0;
144 long delta; /* adjustment in usec */
145 long ndelta;
146 struct timeval now;
147 struct timeval adj;
148
149 if (!timerisset(corr))
150 return;
151
152 adj = *corr;
153 if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
154 delta = adj.tv_sec*1000000 + adj.tv_usec;
155 /* If the correction is less than the minimum round
156 * trip time for an ICMP packet, and thus
157 * less than the likely error in the measurement,
158 * do not do the entire correction. Do half
159 * or a quarter of it.
160 */
161
162 if (delta > -MIN_ROUND*1000
163 && delta < MIN_ROUND*1000) {
164 if (smoother <= 4)
165 smoother++;
166 ndelta = delta >> smoother;
167 if (trace)
168 fprintf(fd,
169 "trimming delta %ld usec to %ld\n",
170 delta, ndelta);
171 adj.tv_usec = ndelta;
172 adj.tv_sec = 0;
173 } else if (smoother > 0) {
174 smoother--;
175 }
176 if (0 > adjtime(corr, 0)) {
177 syslog(LOG_ERR, "adjtime: %m");
178 }
179 if (passes > 1
180 && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
181 smoother = 0;
182 passes = 0;
183 syslog(LOG_WARNING,
184 "large time adjustment of %+.3f sec",
185 delta/1000000.0);
186 }
187 } else {
188 syslog(LOG_WARNING,
189 "clock correction %d sec too large to adjust",
190 adj.tv_sec);
191 (void) gettimeofday(&now, 0);
192 timevaladd(&now, corr);
193 if (settimeofday(&now, 0) < 0)
194 syslog(LOG_ERR, "settimeofday: %m");
195 }
196
197 #ifdef sgi
198 /* Accumulate the total change, and use it to adjust the basic
199 * clock rate.
200 */
201 if (++passes > 2) {
202 #define F_USEC_PER_SEC (1000000*1.0) /* reduce typos */
203 #define F_NSEC_PER_SEC (F_USEC_PER_SEC*1000.0)
204
205 extern char *timetrim_fn;
206 extern char *timetrim_wpat;
207 extern long timetrim;
208 extern double tot_adj, hr_adj; /* totals in nsec */
209 extern double tot_ticks, hr_ticks;
210
211 static double nag_tick;
212 double cur_ticks, hr_delta_ticks, tot_delta_ticks;
213 double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */
214 double tot_trim, hr_trim; /* nsec/sec */
215 struct tms tm;
216 FILE *timetrim_st;
217
218 cur_ticks = times(&tm);
219 tot_adj += delta*1000.0;
220 hr_adj += delta*1000.0;
221
222 tot_delta_ticks = cur_ticks-tot_ticks;
223 if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) {
224 tot_adj -= rint(tot_adj/16);
225 tot_ticks += rint(tot_delta_ticks/16);
226 tot_delta_ticks = cur_ticks-tot_ticks;
227 }
228 hr_delta_ticks = cur_ticks-hr_ticks;
229
230 tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK);
231 tru_tot_adj = (tot_adj
232 + timetrim*rint(tot_delta_ticks/CLK_TCK));
233
234 if (hr_delta_ticks >= SECDAY*CLK_TCK
235 || (tot_delta_ticks < 4*SECDAY*CLK_TCK
236 && hr_delta_ticks >= SECHR*CLK_TCK)
237 || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) {
238
239 tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks);
240 hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks);
241
242 if (trace
243 || (abs(timetrim - hr_trim) > 100000.0
244 && 0 == timetrim_fn
245 && ((cur_ticks - nag_tick)
246 >= 24*SECDAY*CLK_TCK))) {
247 nag_tick = cur_ticks;
248 syslog(LOG_NOTICE,
249 "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f",
250 tru_tot_adj/F_NSEC_PER_SEC,
251 tot_delta_ticks/(SECHR*CLK_TCK*1.0),
252 tru_hr_adj/F_NSEC_PER_SEC,
253 hr_delta_ticks/(SECHR*CLK_TCK*1.0),
254 tot_trim,
255 hr_trim);
256 }
257
258 if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) {
259 tot_ticks = hr_ticks;
260 tot_adj = hr_adj;
261 } else if (0 > syssgi(SGI_SETTIMETRIM,
262 (long)tot_trim)) {
263 syslog(LOG_ERR, "SETTIMETRIM(%d): %m",
264 (long)tot_trim);
265 } else {
266 if (0 != timetrim_fn) {
267 timetrim_st = fopen(timetrim_fn, "w");
268 if (0 == timetrim_st) {
269 syslog(LOG_ERR, "fopen(%s): %m",
270 timetrim_fn);
271 } else {
272 if (0 > fprintf(timetrim_st,
273 timetrim_wpat,
274 (long)tot_trim,
275 tru_tot_adj,
276 tot_delta_ticks)) {
277 syslog(LOG_ERR,
278 "fprintf(%s): %m",
279 timetrim_fn);
280 }
281 (void)fclose(timetrim_st);
282 }
283 }
284
285 tot_adj -= ((tot_trim - timetrim)
286 * rint(tot_delta_ticks/CLK_TCK));
287 timetrim = tot_trim;
288 }
289
290 hr_ticks = cur_ticks;
291 hr_adj = 0;
292 }
293 }
294 #endif /* sgi */
295 }
296
297
298 /* adjust the time in a message by the time it
299 * spent in the queue
300 */
301 void
302 adj_msg_time(msg, now)
303 struct tsp *msg;
304 struct timeval *now;
305 {
306 msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec);
307 msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec);
308
309 while (msg->tsp_time.tv_usec < 0) {
310 msg->tsp_time.tv_sec--;
311 msg->tsp_time.tv_usec += 1000000;
312 }
313 while (msg->tsp_time.tv_usec >= 1000000) {
314 msg->tsp_time.tv_sec++;
315 msg->tsp_time.tv_usec -= 1000000;
316 }
317 }