correct.c revision 30830
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	"$Id: correct.c,v 1.2 1997/10/22 06:19:48 charnier 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}
295