xref: /netbsd-src/usr.sbin/timed/timed/correct.c (revision 7ac2181da6b3b8088eeb5744c5fef2c0377740e6)
1 /*	$NetBSD: correct.c,v 1.14 2007/05/17 00:36:12 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
35 static char sccsid[] = "@(#)correct.c	8.1 (Berkeley) 6/6/93";
36 #else
37 __RCSID("$NetBSD: correct.c,v 1.14 2007/05/17 00:36:12 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 
46 static void adjclock(struct timeval*);
47 
48 /*
49  * sends to the slaves the corrections for their clocks after fixing our
50  * own
51  */
52 void
correct(long avdelta)53 correct(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 
116 static void
adjclock(struct timeval * corr)117 adjclock(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  */
185 void
adj_msg_time(struct tsp * msg,struct timeval * now)186 adj_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