xref: /netbsd/usr.sbin/timed/timed/correct.c (revision bf9ec67e)
1 /*	$NetBSD: correct.c,v 1.9 2001/09/02 00:13:06 reinoud 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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)correct.c	8.1 (Berkeley) 6/6/93";
40 #else
41 __RCSID("$NetBSD: correct.c,v 1.9 2001/09/02 00:13:06 reinoud Exp $");
42 #endif
43 #endif /* not lint */
44 
45 #include "globals.h"
46 #include <math.h>
47 #include <sys/types.h>
48 #include <sys/times.h>
49 
50 static void adjclock(struct timeval*);
51 
52 /*
53  * sends to the slaves the corrections for their clocks after fixing our
54  * own
55  */
56 void
57 correct(long avdelta)
58 {
59 	struct hosttbl *htp;
60 	int corr;
61 	struct timeval adjlocal, tmptv;
62 	struct tsp to;
63 	struct tsp *answer;
64 
65 	mstotvround(&adjlocal, avdelta);
66 
67 	for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
68 		if (htp->delta != HOSTDOWN)  {
69 			corr = avdelta - htp->delta;
70 /* If the other machine is off in the weeds, set its time directly.
71  *	If a slave gets the wrong day, the original code would simply
72  *	fix the minutes.  If you fix a network partition, you can get
73  *	into such situations.
74  */
75 			if (htp->need_set
76 			    || corr >= MAXADJ*1000
77 			    || corr <= -MAXADJ*1000) {
78 				htp->need_set = 0;
79 				(void)gettimeofday(&tmptv,0);
80 				timeradd(&tmptv, &adjlocal, &tmptv);
81 				to.tsp_time.tv_sec = tmptv.tv_sec;
82 				to.tsp_time.tv_usec = tmptv.tv_usec;
83 				to.tsp_type = TSP_SETTIME;
84 			} else {
85 				tmptv.tv_sec = to.tsp_time.tv_sec ;
86 				tmptv.tv_usec = to.tsp_time.tv_usec ;
87 				mstotvround(&tmptv, corr);
88 				to.tsp_time.tv_sec = tmptv.tv_sec;
89 				to.tsp_time.tv_usec = tmptv.tv_usec;
90 				to.tsp_type = TSP_ADJTIME;
91 			}
92 			(void)strcpy(to.tsp_name, hostname);
93 			answer = acksend(&to, &htp->addr, htp->name,
94 					 TSP_ACK, 0, 0);
95 			if (!answer) {
96 				htp->delta = HOSTDOWN;
97 				syslog(LOG_WARNING,
98 				       "no reply to time correction from %s",
99 				       htp->name);
100 				if (++htp->noanswer >= LOSTHOST) {
101 					if (trace) {
102 						fprintf(fd,
103 					     "purging %s for not answering\n",
104 							htp->name);
105 						(void)fflush(fd);
106 					}
107 					htp = remmach(htp);
108 				}
109 			}
110 		}
111 	}
112 
113 	/*
114 	 * adjust our own clock now that we are not sending it out
115 	 */
116 	adjclock(&adjlocal);
117 }
118 
119 
120 static void
121 adjclock(struct timeval *corr)
122 {
123 	static int passes = 0;
124 	static int smoother = 0;
125 	long delta;			/* adjustment in usec */
126 	long ndelta;
127 	struct timeval now;
128 	struct timeval adj;
129 
130 	if (!timerisset(corr))
131 		return;
132 
133 	adj = *corr;
134 	if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
135 		delta = adj.tv_sec*1000000 + adj.tv_usec;
136 		/* If the correction is less than the minimum round
137 		 *	trip time for an ICMP packet, and thus
138 		 *	less than the likely error in the measurement,
139 		 *	do not do the entire correction.  Do half
140 		 *	or a quarter of it.
141 		 */
142 
143 		if (delta > -MIN_ROUND*1000
144 		    && delta < MIN_ROUND*1000) {
145 			if (smoother <= 4)
146 				smoother++;
147 			ndelta = delta >> smoother;
148 			if (trace)
149 				fprintf(fd,
150 					"trimming delta %ld usec to %ld\n",
151 					delta, ndelta);
152 			adj.tv_usec = ndelta;
153 			adj.tv_sec = 0;
154 		} else if (smoother > 0) {
155 			smoother--;
156 		}
157 		if (0 > adjtime(corr, 0)) {
158 			syslog(LOG_ERR, "adjtime: %m");
159 		}
160 		if (passes > 1
161 		    && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
162 			smoother = 0;
163 			passes = 0;
164 			syslog(LOG_WARNING,
165 			       "large time adjustment of %+.3f sec",
166 			       delta/1000000.0);
167 		}
168 	} else {
169 		syslog(LOG_WARNING,
170 		       "clock correction %ld sec too large to adjust",
171 		       (long)adj.tv_sec);
172 		(void) gettimeofday(&now, 0);
173 		timeradd(&now, corr, &now);
174 		if (settimeofday(&now, 0) < 0)
175 			syslog(LOG_ERR, "settimeofday: %m");
176 	}
177 }
178 
179 
180 /* adjust the time in a message by the time it
181  *	spent in the queue
182  */
183 void
184 adj_msg_time(struct tsp *msg, struct timeval *now)
185 {
186 	struct timeval diff;
187 
188 	timersub(now, &from_when, &diff);
189 	timeradd(&msg->tsp_time, &diff, &msg->tsp_time);
190 }
191