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