include-afsconfig-before-param-h-20010712
[openafs.git] / src / ntp / ntp_adjust.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID("$Header$");
14
15 #include <stdio.h>
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/socket.h>
19 #include <sys/time.h>
20 #include <sys/ioctl.h>
21 #include <sys/resource.h>
22
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <netinet/udp.h>
27 #include <arpa/inet.h>
28 #include <netdb.h>
29 #include <strings.h>
30 #include <errno.h>
31 #if defined(AIX)
32 #include <sys/syslog.h>
33 #else
34 #include <syslog.h>
35 #endif /* defined(AIX) */
36
37 #include "ntp.h"
38
39 #ifdef  DEBUG
40 extern int debug;
41 #endif
42
43 extern int doset;
44 extern int debuglevel;
45 extern int kern_tickadj;
46 extern char *ntoa();
47 extern struct sysdata sys;
48
49 double  drift_comp = 0.0,
50         compliance,
51         clock_adjust;
52 afs_int32       update_timer = 0;
53
54 int     adj_precision;
55 double  adj_residual;
56 int     firstpass = 1;
57
58 #define MICROSECONDS 1000000
59
60 #define abs(x)  ((x) < 0 ? -(x) : (x))
61
62 void
63 init_logical_clock()
64 {
65         if (kern_tickadj)
66                 adj_precision = kern_tickadj;
67         else
68                 adj_precision = 1;
69         /*
70          *  If you have the "fix" for adjtime() installed in you kernel, you'll
71          *  have to make sure that adj_precision is set to 1 here.
72          */
73 }
74
75
76 /*
77  *  5.0 Logical clock procedure
78  *
79  *  Only paramter is an offset to vary the clock by, in seconds.  We'll either
80  *  arrange for the clock to slew to accomodate the adjustment, or just preform
81  *  a step adjustment if the offset is too large.
82  *
83  *  The update which is to be performed is left in the external
84  *  clock_adjust. 
85  *
86  *  Returns non-zero if clock was reset rather than slewed.
87  *
88  *  Many thanks for Dennis Ferguson <dennis@gw.ccie.utoronto.ca> for his
89  *  corrections to my code.
90  */
91
92 int
93 adj_logical(offset)
94         double offset;
95 {
96         struct timeval tv1, tv2;
97 #ifdef  XADJTIME2
98         struct timeval delta, olddelta;
99 #endif
100         
101         /*
102          *  Now adjust the logical clock
103          */
104         if (!doset)
105                 return 0;
106
107         adj_residual = 0.0;
108         if (offset > CLOCK_MAX || offset < -CLOCK_MAX) {
109                 double steptime = offset;
110
111                 (void) gettimeofday(&tv2, (struct timezone *) 0);
112                 steptime += tv2.tv_sec;
113                 steptime += tv2.tv_usec / 1000000.0;
114                 tv1.tv_sec = steptime;
115                 tv1.tv_usec = (steptime - tv1.tv_sec) * 1000000;
116 #ifdef  DEBUG
117                 if (debug > 2) {
118                         steptime = (tv1.tv_sec + tv1.tv_usec/1000000.0) -
119                                 (tv2.tv_sec + tv2.tv_usec/1000000.0);
120                         printf("adj_logical: %f %f\n", offset, steptime);
121                 }
122 #endif
123                 if (settimeofday(&tv1, (struct timezone *) 0) < 0)
124                     {
125                         syslog(LOG_ERR, "Can't set time: %m");
126                         return(-1);
127                     }
128                 firstpass = 1;
129                 update_timer = 0;
130                 clock_adjust = 0.0;
131                 return (1);       /* indicate that step adjustment was done */
132         } else  {
133                 double ai;
134
135                 /*
136                  * If this is our very first adjustment, don't touch
137                  * the drift compensation (this is f in the spec
138                  * equations), else update using the *old* value
139                  * of the compliance.
140                  */
141                 clock_adjust = offset;
142                 if (firstpass)
143                         firstpass = 0;
144                 else if (update_timer > 0) {
145                         ai = abs(compliance);
146                         ai = (double)(1<<CLOCK_COMP) - 
147                                 (double)(1<<CLOCK_FACTOR) * ai;
148                         if (ai < 1.0)           /* max(... , 1.0) */
149                                 ai = 1.0;
150                         drift_comp += offset / (ai * (double)update_timer);
151                 }
152
153                 /*
154                  * Set the timer to zero.  adj_host_clock() increments it
155                  * so we can tell the period between updates.
156                  */
157                 update_timer = 0;
158
159                 /*
160                  * Now update the compliance.  The compliance is h in the
161                  * equations.
162                  */
163                 compliance += (offset - compliance)/(double)(1<<CLOCK_TRACK);
164
165 #ifdef XADJTIME2
166                 delta.tv_sec = offset;
167                 delta.tv_usec = (offset - delta.tv_sec) * 1000;
168                 (void) adjtime2(&delta, &olddelta);
169 #endif
170                 return(0);
171         }
172 }
173
174 #ifndef XADJTIME2
175 extern int adjtime();
176
177 /*
178  *  This is that routine that performs the periodic clock adjustment.
179  *  The procedure is best described in the the NTP document.  In a
180  *  nutshell, we prefer to do lots of small evenly spaced adjustments.
181  *  The alternative, one large adjustment, creates two much of a
182  *  clock disruption and as a result oscillation.
183  *
184  *  This function is called every 2**CLOCK_ADJ seconds.
185  *
186  */
187
188 /*
189  * global for debugging?
190  */
191 double adjustment;
192
193 void
194 adj_host_clock()
195 {
196
197         struct timeval delta, olddelta;
198
199         if (!doset)
200                 return;
201
202         /*
203          * Add update period into timer so we know how long it
204          * took between the last update and the next one.
205          */
206         update_timer += 1<<CLOCK_ADJ;
207         /*
208          * Should check to see if update_timer > 1 day here?
209          */
210
211         /*
212          * Compute phase part of adjustment here and update clock_adjust.
213          * Note that the equations used here are implicit in the last
214          * two equations in the spec (in particular, look at the equation
215          * for g and figure out how to  find the k==1 term given the k==0 term.)
216          */
217         adjustment = clock_adjust / (double)(1<<CLOCK_PHASE);
218         clock_adjust -= adjustment;
219
220         /*
221          * Now add in the frequency component.  Be careful to note that
222          * the ni occurs in the last equation since those equations take
223          * you from 64 second update to 64 second update (ei is the total
224          * adjustment done over 64 seconds) and we're only deal in the
225          * little 4 second adjustment interval here.
226          */
227         adjustment += drift_comp / (double)(1<<CLOCK_FREQ);
228
229         /*
230          * Add in old adjustment residual
231          */
232         adjustment += adj_residual;
233
234         /*
235          * Simplify.  Adjustment shouldn't be bigger than 2 ms.  Hope
236          * writer of spec was truth telling.
237          */
238 #ifdef  DEBUG
239         delta.tv_sec = adjustment;
240         if (debug && delta.tv_sec) abort();
241 #else
242         delta.tv_sec = 0;
243 #endif
244 #if defined(AFS_AIX32_ENV)
245         /* aix 3.1 ajdtime has unsigned bug. */
246         if (adjustment < 0.0) adj_precision = 5000;
247         else if (adjustment < 1000000.0) adj_precision = 1000;
248         else adj_precision = 5000;
249 #endif
250         delta.tv_usec = ((afs_int32)(adjustment * 1000000.0) / adj_precision)
251                    * adj_precision;
252
253         adj_residual = adjustment - (double) delta.tv_usec / 1000000.0;
254
255         if (delta.tv_usec == 0)
256                 return;
257
258         if (adjtime(&delta, &olddelta) < 0)
259                 syslog(LOG_ERR, "Can't adjust time: %m");
260
261 #ifdef  DEBUG
262         if(debug > 2)
263                 printf("adj: %ld us  %f %f\n",
264                        delta.tv_usec, drift_comp, clock_adjust);
265 #endif
266 }
267 #endif
268
269 #if defined(AFS_HPUX_ENV) && !defined(AFS_HPUX102_ENV)
270 /*
271  * adjtime for HPUX.  Basically a poor man's version of the BSD adjtime call.
272  * It accumulates adjustments until such time as there are enough to use the
273  * stime primitive.  This code is ugly.  It also does no range checking,
274  * since the assumption is that the adjustments will be (fairly) small.
275  *
276  * The basic mechanism is simple: we only have a coarse granularity (1
277  * second)  so we accumulate changes until they exceed 1 second.  When
278  * that is the case, an adjustment is made which will always be less
279  * than 1 second.  If it is a negative adjustment, we won't allow it
280  * to timewarp more frequently than once every ten seconds.
281  * 
282  */
283 static struct timeval cum = {0,0};      /* use to accumulate unadjusted time */
284
285 ZeroAIXcum()
286 {
287     if (debug > 6)
288         printf ("Zeroing aix_adjtime accumulation: %d %d\n",
289                 cum.tv_sec, cum.tv_usec);
290     bzero (&cum, sizeof(cum));
291 }
292
293 int adjtime(newdelta, olddelta)
294    struct timeval *newdelta;
295    struct timeval *olddelta;
296 {
297     static struct timeval lastbackadj; /* last time adjusted backwards */
298     struct timeval now, new;
299
300 #if 0
301     {   /* punt accumulated change if sign of correction changes */
302         int dNeg = ((newdelta->tv_sec < 0 || newdelta->tv_usec < 0) ? 1 : 0);
303         int cNeg = ((cum.tv_sec < 0 || cum.tv_usec < 0) ? 1 : 0);
304         if (dNeg != cNeg) ZeroAIXcum();
305     }
306 #endif /* 0 */
307
308     *olddelta = cum;
309     cum.tv_usec += newdelta->tv_usec;
310     cum.tv_sec += newdelta->tv_sec + cum.tv_usec / MICROSECONDS;
311     cum.tv_usec = (cum.tv_usec < 0) ? -((-cum.tv_usec) % MICROSECONDS) :
312         cum.tv_usec % MICROSECONDS;
313
314     gettimeofday (&now, (struct timezone *)0);
315     new = now;
316     new.tv_sec += cum.tv_sec;
317     new.tv_usec += cum.tv_usec;
318     if (new.tv_usec >= MICROSECONDS) new.tv_sec++, new.tv_usec -= MICROSECONDS;
319     else if (new.tv_usec < 0) new.tv_sec--, new.tv_usec += MICROSECONDS;
320     if (debug > 6) {
321         printf ("cum is %d %d, new is %d %d, now is %d %d\n",
322                 cum.tv_sec, cum.tv_usec,
323                 new.tv_sec, new.tv_usec, now.tv_sec, now.tv_usec);
324     }
325
326     if (cum.tv_sec || abs(cum.tv_usec) > 2000) {
327         /* wait till accumulated update is at least 2msec since this call
328          * seems to add some jitter. */
329         settimeofday (&new, (struct timezone *)0);
330         if (debug > 4)                  /* do set before doing I/O */
331             printf ("hp_adjtime: pushing clock by %d usec w/ settimeofday \n",
332                     cum.tv_sec*1000000 + cum.tv_usec);
333         cum.tv_sec = 0;
334         cum.tv_usec = 0;
335     }
336     return 0;
337 }
338 #endif /* defined(AFS_HPUX_ENV) */