correct.c revision 30642
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$";
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)strncpy(to.tsp_name, hostname,
88					sizeof to.tsp_name-1);
89			to.tsp_name[sizeof to.tsp_name-1] = '\0';
90			answer = acksend(&to, &htp->addr, htp->name,
91					 TSP_ACK, 0, 0);
92			if (!answer) {
93				htp->delta = HOSTDOWN;
94				syslog(LOG_WARNING,
95				       "no reply to time correction from %s",
96				       htp->name);
97				if (++htp->noanswer >= LOSTHOST) {
98					if (trace) {
99						fprintf(fd,
100					     "purging %s for not answering\n",
101							htp->name);
102						(void)fflush(fd);
103					}
104					htp = remmach(htp);
105				}
106			}
107		}
108	}
109
110	/*
111	 * adjust our own clock now that we are not sending it out
112	 */
113	adjclock(&adjlocal);
114}
115
116
117static void
118adjclock(corr)
119	struct timeval *corr;
120{
121	static int passes = 0;
122	static int smoother = 0;
123	long delta;			/* adjustment in usec */
124	long ndelta;
125	struct timeval now;
126	struct timeval adj;
127
128	if (!timerisset(corr))
129		return;
130
131	adj = *corr;
132	if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
133		delta = adj.tv_sec*1000000 + adj.tv_usec;
134		/* If the correction is less than the minimum round
135		 *	trip time for an ICMP packet, and thus
136		 *	less than the likely error in the measurement,
137		 *	do not do the entire correction.  Do half
138		 *	or a quarter of it.
139		 */
140
141		if (delta > -MIN_ROUND*1000
142		    && delta < MIN_ROUND*1000) {
143			if (smoother <= 4)
144				smoother++;
145			ndelta = delta >> smoother;
146			if (trace)
147				fprintf(fd,
148					"trimming delta %ld usec to %ld\n",
149					delta, ndelta);
150			adj.tv_usec = ndelta;
151			adj.tv_sec = 0;
152		} else if (smoother > 0) {
153			smoother--;
154		}
155		if (0 > adjtime(corr, 0)) {
156			syslog(LOG_ERR, "adjtime: %m");
157		}
158		if (passes > 1
159		    && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
160			smoother = 0;
161			passes = 0;
162			syslog(LOG_WARNING,
163			       "large time adjustment of %+.3f sec",
164			       delta/1000000.0);
165		}
166	} else {
167		syslog(LOG_WARNING,
168		       "clock correction %d sec too large to adjust",
169		       adj.tv_sec);
170		(void) gettimeofday(&now, 0);
171		timevaladd(&now, corr);
172		if (settimeofday(&now, 0) < 0)
173			syslog(LOG_ERR, "settimeofday: %m");
174	}
175
176#ifdef sgi
177	/* Accumulate the total change, and use it to adjust the basic
178	 * clock rate.
179	 */
180	if (++passes > 2) {
181#define F_USEC_PER_SEC	(1000000*1.0)	/* reduce typos */
182#define F_NSEC_PER_SEC	(F_USEC_PER_SEC*1000.0)
183
184		extern char *timetrim_fn;
185		extern char *timetrim_wpat;
186		extern long timetrim;
187		extern double tot_adj, hr_adj;	/* totals in nsec */
188		extern double tot_ticks, hr_ticks;
189
190		static double nag_tick;
191		double cur_ticks, hr_delta_ticks, tot_delta_ticks;
192		double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */
193		double tot_trim, hr_trim;   /* nsec/sec */
194		struct tms tm;
195		FILE *timetrim_st;
196
197		cur_ticks = times(&tm);
198		tot_adj += delta*1000.0;
199		hr_adj += delta*1000.0;
200
201		tot_delta_ticks = cur_ticks-tot_ticks;
202		if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) {
203			tot_adj -= rint(tot_adj/16);
204			tot_ticks += rint(tot_delta_ticks/16);
205			tot_delta_ticks = cur_ticks-tot_ticks;
206		}
207		hr_delta_ticks = cur_ticks-hr_ticks;
208
209		tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK);
210		tru_tot_adj = (tot_adj
211			       + timetrim*rint(tot_delta_ticks/CLK_TCK));
212
213		if (hr_delta_ticks >= SECDAY*CLK_TCK
214		    || (tot_delta_ticks < 4*SECDAY*CLK_TCK
215			&& hr_delta_ticks >= SECHR*CLK_TCK)
216		    || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) {
217
218			tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks);
219			hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks);
220
221			if (trace
222			    || (abs(timetrim - hr_trim) > 100000.0
223				&& 0 == timetrim_fn
224				&& ((cur_ticks - nag_tick)
225				    >= 24*SECDAY*CLK_TCK))) {
226				nag_tick = cur_ticks;
227				syslog(LOG_NOTICE,
228		   "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f",
229				       tru_tot_adj/F_NSEC_PER_SEC,
230				       tot_delta_ticks/(SECHR*CLK_TCK*1.0),
231				       tru_hr_adj/F_NSEC_PER_SEC,
232				       hr_delta_ticks/(SECHR*CLK_TCK*1.0),
233				       tot_trim,
234				       hr_trim);
235			}
236
237			if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) {
238				tot_ticks = hr_ticks;
239				tot_adj = hr_adj;
240			} else if (0 > syssgi(SGI_SETTIMETRIM,
241					      (long)tot_trim)) {
242				syslog(LOG_ERR, "SETTIMETRIM(%d): %m",
243				       (long)tot_trim);
244			} else {
245				if (0 != timetrim_fn) {
246				    timetrim_st = fopen(timetrim_fn, "w");
247				    if (0 == timetrim_st) {
248					syslog(LOG_ERR, "fopen(%s): %m",
249					       timetrim_fn);
250				    } else {
251					if (0 > fprintf(timetrim_st,
252							timetrim_wpat,
253							(long)tot_trim,
254							tru_tot_adj,
255							tot_delta_ticks)) {
256						syslog(LOG_ERR,
257						       "fprintf(%s): %m",
258						       timetrim_fn);
259					}
260					(void)fclose(timetrim_st);
261				    }
262				}
263
264				tot_adj -= ((tot_trim - timetrim)
265					    * rint(tot_delta_ticks/CLK_TCK));
266				timetrim = tot_trim;
267			}
268
269			hr_ticks = cur_ticks;
270			hr_adj = 0;
271		}
272	}
273#endif /* sgi */
274}
275
276
277/* adjust the time in a message by the time it
278 *	spent in the queue
279 */
280void
281adj_msg_time(msg, now)
282	struct tsp *msg;
283	struct timeval *now;
284{
285	msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec);
286	msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec);
287
288	while (msg->tsp_time.tv_usec < 0) {
289		msg->tsp_time.tv_sec--;
290		msg->tsp_time.tv_usec += 1000000;
291	}
292	while (msg->tsp_time.tv_usec >= 1000000) {
293		msg->tsp_time.tv_sec++;
294		msg->tsp_time.tv_usec -= 1000000;
295	}
296}
297