Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.sbin / timed / timed / correct.c
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  * @(#)correct.c        8.1 (Berkeley) 6/6/93
34  * $FreeBSD: src/usr.sbin/timed/timed/correct.c,v 1.4 1999/08/28 01:20:17 peter Exp $
35  * $DragonFly: src/usr.sbin/timed/timed/correct.c,v 1.2 2003/06/17 04:30:03 dillon Exp $
36  */
37
38 #include "globals.h"
39 #include <math.h>
40 #include <sys/types.h>
41 #include <sys/times.h>
42 #ifdef sgi
43 #include <sys/syssgi.h>
44 #endif /* sgi */
45
46 static void adjclock __P((struct timeval *));
47
48 /*
49  * sends to the slaves the corrections for their clocks after fixing our
50  * own
51  */
52 void
53 correct(avdelta)
54         long avdelta;
55 {
56         struct hosttbl *htp;
57         int corr;
58         struct timeval adjlocal;
59         struct tsp to;
60         struct tsp *answer;
61
62         mstotvround(&adjlocal, avdelta);
63
64         for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
65                 if (htp->delta != HOSTDOWN)  {
66                         corr = avdelta - htp->delta;
67 /* If the other machine is off in the weeds, set its time directly.
68  *      If a slave gets the wrong day, the original code would simply
69  *      fix the minutes.  If you fix a network partition, you can get
70  *      into such situations.
71  */
72                         if (htp->need_set
73                             || corr >= MAXADJ*1000
74                             || corr <= -MAXADJ*1000) {
75                                 htp->need_set = 0;
76                                 (void)gettimeofday(&to.tsp_time,0);
77                                 timevaladd(&to.tsp_time, &adjlocal);
78                                 to.tsp_type = TSP_SETTIME;
79                         } else {
80                                 mstotvround(&to.tsp_time, corr);
81                                 to.tsp_type = TSP_ADJTIME;
82                         }
83                         (void)strcpy(to.tsp_name, hostname);
84                         answer = acksend(&to, &htp->addr, htp->name,
85                                          TSP_ACK, 0, 0);
86                         if (!answer) {
87                                 htp->delta = HOSTDOWN;
88                                 syslog(LOG_WARNING,
89                                        "no reply to time correction from %s",
90                                        htp->name);
91                                 if (++htp->noanswer >= LOSTHOST) {
92                                         if (trace) {
93                                                 fprintf(fd,
94                                              "purging %s for not answering\n",
95                                                         htp->name);
96                                                 (void)fflush(fd);
97                                         }
98                                         htp = remmach(htp);
99                                 }
100                         }
101                 }
102         }
103
104         /*
105          * adjust our own clock now that we are not sending it out
106          */
107         adjclock(&adjlocal);
108 }
109
110
111 static void
112 adjclock(corr)
113         struct timeval *corr;
114 {
115         static int passes = 0;
116         static int smoother = 0;
117         long delta;                     /* adjustment in usec */
118         long ndelta;
119         struct timeval now;
120         struct timeval adj;
121
122         if (!timerisset(corr))
123                 return;
124
125         adj = *corr;
126         if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
127                 delta = adj.tv_sec*1000000 + adj.tv_usec;
128                 /* If the correction is less than the minimum round
129                  *      trip time for an ICMP packet, and thus
130                  *      less than the likely error in the measurement,
131                  *      do not do the entire correction.  Do half
132                  *      or a quarter of it.
133                  */
134
135                 if (delta > -MIN_ROUND*1000
136                     && delta < MIN_ROUND*1000) {
137                         if (smoother <= 4)
138                                 smoother++;
139                         ndelta = delta >> smoother;
140                         if (trace)
141                                 fprintf(fd,
142                                         "trimming delta %ld usec to %ld\n",
143                                         delta, ndelta);
144                         adj.tv_usec = ndelta;
145                         adj.tv_sec = 0;
146                 } else if (smoother > 0) {
147                         smoother--;
148                 }
149                 if (0 > adjtime(corr, 0)) {
150                         syslog(LOG_ERR, "adjtime: %m");
151                 }
152                 if (passes > 1
153                     && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
154                         smoother = 0;
155                         passes = 0;
156                         syslog(LOG_WARNING,
157                                "large time adjustment of %+.3f sec",
158                                delta/1000000.0);
159                 }
160         } else {
161                 syslog(LOG_WARNING,
162                        "clock correction %d sec too large to adjust",
163                        adj.tv_sec);
164                 (void) gettimeofday(&now, 0);
165                 timevaladd(&now, corr);
166                 if (settimeofday(&now, 0) < 0)
167                         syslog(LOG_ERR, "settimeofday: %m");
168         }
169
170 #ifdef sgi
171         /* Accumulate the total change, and use it to adjust the basic
172          * clock rate.
173          */
174         if (++passes > 2) {
175 #define F_USEC_PER_SEC  (1000000*1.0)   /* reduce typos */
176 #define F_NSEC_PER_SEC  (F_USEC_PER_SEC*1000.0)
177
178                 extern char *timetrim_fn;
179                 extern char *timetrim_wpat;
180                 extern long timetrim;
181                 extern double tot_adj, hr_adj;  /* totals in nsec */
182                 extern double tot_ticks, hr_ticks;
183
184                 static double nag_tick;
185                 double cur_ticks, hr_delta_ticks, tot_delta_ticks;
186                 double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */
187                 double tot_trim, hr_trim;   /* nsec/sec */
188                 struct tms tm;
189                 FILE *timetrim_st;
190
191                 cur_ticks = times(&tm);
192                 tot_adj += delta*1000.0;
193                 hr_adj += delta*1000.0;
194
195                 tot_delta_ticks = cur_ticks-tot_ticks;
196                 if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) {
197                         tot_adj -= rint(tot_adj/16);
198                         tot_ticks += rint(tot_delta_ticks/16);
199                         tot_delta_ticks = cur_ticks-tot_ticks;
200                 }
201                 hr_delta_ticks = cur_ticks-hr_ticks;
202
203                 tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK);
204                 tru_tot_adj = (tot_adj
205                                + timetrim*rint(tot_delta_ticks/CLK_TCK));
206
207                 if (hr_delta_ticks >= SECDAY*CLK_TCK
208                     || (tot_delta_ticks < 4*SECDAY*CLK_TCK
209                         && hr_delta_ticks >= SECHR*CLK_TCK)
210                     || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) {
211
212                         tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks);
213                         hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks);
214
215                         if (trace
216                             || (abs(timetrim - hr_trim) > 100000.0
217                                 && 0 == timetrim_fn
218                                 && ((cur_ticks - nag_tick)
219                                     >= 24*SECDAY*CLK_TCK))) {
220                                 nag_tick = cur_ticks;
221                                 syslog(LOG_NOTICE,
222                    "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f",
223                                        tru_tot_adj/F_NSEC_PER_SEC,
224                                        tot_delta_ticks/(SECHR*CLK_TCK*1.0),
225                                        tru_hr_adj/F_NSEC_PER_SEC,
226                                        hr_delta_ticks/(SECHR*CLK_TCK*1.0),
227                                        tot_trim,
228                                        hr_trim);
229                         }
230
231                         if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) {
232                                 tot_ticks = hr_ticks;
233                                 tot_adj = hr_adj;
234                         } else if (0 > syssgi(SGI_SETTIMETRIM,
235                                               (long)tot_trim)) {
236                                 syslog(LOG_ERR, "SETTIMETRIM(%d): %m",
237                                        (long)tot_trim);
238                         } else {
239                                 if (0 != timetrim_fn) {
240                                     timetrim_st = fopen(timetrim_fn, "w");
241                                     if (0 == timetrim_st) {
242                                         syslog(LOG_ERR, "fopen(%s): %m",
243                                                timetrim_fn);
244                                     } else {
245                                         if (0 > fprintf(timetrim_st,
246                                                         timetrim_wpat,
247                                                         (long)tot_trim,
248                                                         tru_tot_adj,
249                                                         tot_delta_ticks)) {
250                                                 syslog(LOG_ERR,
251                                                        "fprintf(%s): %m",
252                                                        timetrim_fn);
253                                         }
254                                         (void)fclose(timetrim_st);
255                                     }
256                                 }
257
258                                 tot_adj -= ((tot_trim - timetrim)
259                                             * rint(tot_delta_ticks/CLK_TCK));
260                                 timetrim = tot_trim;
261                         }
262
263                         hr_ticks = cur_ticks;
264                         hr_adj = 0;
265                 }
266         }
267 #endif /* sgi */
268 }
269
270
271 /* adjust the time in a message by the time it
272  *      spent in the queue
273  */
274 void
275 adj_msg_time(msg, now)
276         struct tsp *msg;
277         struct timeval *now;
278 {
279         msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec);
280         msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec);
281
282         while (msg->tsp_time.tv_usec < 0) {
283                 msg->tsp_time.tv_sec--;
284                 msg->tsp_time.tv_usec += 1000000;
285         }
286         while (msg->tsp_time.tv_usec >= 1000000) {
287                 msg->tsp_time.tv_sec++;
288                 msg->tsp_time.tv_usec -= 1000000;
289         }
290 }