]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/timed/timed/correct.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)correct.c   8.1 (Berkeley) 6/6/93";
37 #endif
38 static const char rcsid[] =
39   "$FreeBSD$";
40 #endif /* not lint */
41
42 #include "globals.h"
43 #include <math.h>
44 #include <sys/types.h>
45 #include <sys/times.h>
46
47 static void adjclock(struct timeval *);
48
49 /*
50  * sends to the slaves the corrections for their clocks after fixing our
51  * own
52  */
53 void
54 correct(avdelta)
55         long avdelta;
56 {
57         struct hosttbl *htp;
58         int corr;
59         struct timeval adjlocal, tmptv;
60         struct tsp to;
61         struct tsp *answer;
62
63         mstotvround(&adjlocal, avdelta);
64
65         for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
66                 if (htp->delta != HOSTDOWN)  {
67                         corr = avdelta - htp->delta;
68 /* If the other machine is off in the weeds, set its time directly.
69  *      If a slave gets the wrong day, the original code would simply
70  *      fix the minutes.  If you fix a network partition, you can get
71  *      into such situations.
72  */
73                         if (htp->need_set
74                             || corr >= MAXADJ*1000
75                             || corr <= -MAXADJ*1000) {
76                                 htp->need_set = 0;
77                                 (void)gettimeofday(&tmptv,0);
78                                 timevaladd(&tmptv, &adjlocal);
79                                 to.tsp_time.tv_sec = tmptv.tv_sec;
80                                 to.tsp_time.tv_usec = tmptv.tv_usec;
81                                 to.tsp_type = TSP_SETTIME;
82                         } else {
83                                 tmptv.tv_sec = to.tsp_time.tv_sec;
84                                 tmptv.tv_usec = to.tsp_time.tv_usec;
85                                 mstotvround(&tmptv, corr);
86                                 to.tsp_time.tv_sec = tmptv.tv_sec;
87                                 to.tsp_time.tv_usec = tmptv.tv_usec;
88                                 to.tsp_type = TSP_ADJTIME;
89                         }
90                         (void)strcpy(to.tsp_name, hostname);
91                         answer = acksend(&to, &htp->addr, htp->name,
92                                          TSP_ACK, 0, 0);
93                         if (!answer) {
94                                 htp->delta = HOSTDOWN;
95                                 syslog(LOG_WARNING,
96                                        "no reply to time correction from %s",
97                                        htp->name);
98                                 if (++htp->noanswer >= LOSTHOST) {
99                                         if (trace) {
100                                                 fprintf(fd,
101                                              "purging %s for not answering\n",
102                                                         htp->name);
103                                                 (void)fflush(fd);
104                                         }
105                                         htp = remmach(htp);
106                                 }
107                         }
108                 }
109         }
110
111         /*
112          * adjust our own clock now that we are not sending it out
113          */
114         adjclock(&adjlocal);
115 }
116
117
118 static void
119 adjclock(corr)
120         struct timeval *corr;
121 {
122         static int passes = 0;
123         static int smoother = 0;
124         long delta;                     /* adjustment in usec */
125         long ndelta;
126         struct timeval now;
127         struct timeval adj;
128
129         if (!timerisset(corr))
130                 return;
131
132         adj = *corr;
133         if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
134                 delta = adj.tv_sec*1000000 + adj.tv_usec;
135                 /* If the correction is less than the minimum round
136                  *      trip time for an ICMP packet, and thus
137                  *      less than the likely error in the measurement,
138                  *      do not do the entire correction.  Do half
139                  *      or a quarter of it.
140                  */
141
142                 if (delta > -MIN_ROUND*1000
143                     && delta < MIN_ROUND*1000) {
144                         if (smoother <= 4)
145                                 smoother++;
146                         ndelta = delta >> smoother;
147                         if (trace)
148                                 fprintf(fd,
149                                         "trimming delta %ld usec to %ld\n",
150                                         delta, ndelta);
151                         adj.tv_usec = ndelta;
152                         adj.tv_sec = 0;
153                 } else if (smoother > 0) {
154                         smoother--;
155                 }
156                 if (0 > adjtime(corr, 0)) {
157                         syslog(LOG_ERR, "adjtime: %m");
158                 }
159                 if (passes > 1
160                     && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
161                         smoother = 0;
162                         passes = 0;
163                         syslog(LOG_WARNING,
164                                "large time adjustment of %+.3f sec",
165                                delta/1000000.0);
166                 }
167         } else {
168                 syslog(LOG_WARNING,
169                        "clock correction %ld sec too large to adjust",
170                        adj.tv_sec);
171                 (void) gettimeofday(&now, 0);
172                 timevaladd(&now, corr);
173                 if (settimeofday(&now, 0) < 0)
174                         syslog(LOG_ERR, "settimeofday: %m");
175         }
176 }
177
178
179 /* adjust the time in a message by the time it
180  *      spent in the queue
181  */
182 void
183 adj_msg_time(msg, now)
184         struct tsp *msg;
185         struct timeval *now;
186 {
187         msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec);
188         msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec);
189
190         while (msg->tsp_time.tv_usec < 0) {
191                 msg->tsp_time.tv_sec--;
192                 msg->tsp_time.tv_usec += 1000000;
193         }
194         while (msg->tsp_time.tv_usec >= 1000000) {
195                 msg->tsp_time.tv_sec++;
196                 msg->tsp_time.tv_usec -= 1000000;
197         }
198 }