]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/libntp/systime.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ntp / libntp / systime.c
1 /*
2  * systime -- routines to fiddle a UNIX clock.
3  *
4  * ATTENTION: Get approval from Dave Mills on all changes to this file!
5  *
6  */
7 #include "ntp_machine.h"
8 #include "ntp_fp.h"
9 #include "ntp_syslog.h"
10 #include "ntp_unixtime.h"
11 #include "ntp_stdlib.h"
12 #include "ntp_random.h"
13 #include "ntpd.h"               /* for sys_precision */
14
15 #ifdef SIM
16 # include "ntpsim.h"
17 #endif /*SIM */
18
19 #ifdef HAVE_SYS_PARAM_H
20 # include <sys/param.h>
21 #endif
22 #ifdef HAVE_UTMP_H
23 # include <utmp.h>
24 #endif /* HAVE_UTMP_H */
25 #ifdef HAVE_UTMPX_H
26 # include <utmpx.h>
27 #endif /* HAVE_UTMPX_H */
28
29 /*
30  * These routines (get_systime, step_systime, adj_systime) implement an
31  * interface between the system independent NTP clock and the Unix
32  * system clock in various architectures and operating systems.
33  *
34  * Time is a precious quantity in these routines and every effort is
35  * made to minimize errors by always rounding toward zero and amortizing
36  * adjustment residues. By default the adjustment quantum is 1 us for
37  * the usual Unix tickadj() system call, but this can be increased if
38  * necessary by the tick configuration command. For instance, when the
39  * adjtime() quantum is a clock tick for a 100-Hz clock, the quantum
40  * should be 10 ms.
41  */
42 #if defined RELIANTUNIX_CLOCK || defined SCO5_CLOCK
43 double  sys_tick = 10e-3;       /* 10 ms tickadj() */
44 #else
45 double  sys_tick = 1e-6;        /* 1 us tickadj() */
46 #endif
47 double  sys_residual = 0;       /* adjustment residue (s) */
48
49 #ifndef SIM
50
51 /*
52  * get_systime - return system time in NTP timestamp format.
53  */
54 void
55 get_systime(
56         l_fp *now               /* system time */
57         )
58 {
59         double dtemp;
60
61 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
62         struct timespec ts;     /* seconds and nanoseconds */
63
64         /*
65          * Convert Unix clock from seconds and nanoseconds to seconds.
66          * The bottom is only two bits down, so no need for fuzz.
67          * Some systems don't have that level of precision, however...
68          */
69 # ifdef HAVE_CLOCK_GETTIME
70         clock_gettime(CLOCK_REALTIME, &ts);
71 # else
72         getclock(TIMEOFDAY, &ts);
73 # endif
74         now->l_i = ts.tv_sec + JAN_1970;
75         dtemp = ts.tv_nsec / 1e9;
76
77 #else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
78         struct timeval tv;      /* seconds and microseconds */
79
80         /*
81          * Convert Unix clock from seconds and microseconds to seconds.
82          * Add in unbiased random fuzz beneath the microsecond.
83          */
84         GETTIMEOFDAY(&tv, NULL);
85         now->l_i = tv.tv_sec + JAN_1970;
86         dtemp = tv.tv_usec / 1e6;
87
88 #endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
89
90         /*
91          * ntp_random() produces 31 bits (always nonnegative).
92          * This bit is done only after the precision has been
93          * determined.
94          */
95         if (sys_precision != 0)
96                 dtemp += (ntp_random() / FRAC - .5) / (1 <<
97                     -sys_precision);
98
99         /*
100          * Renormalize to seconds past 1900 and fraction.
101          */
102         dtemp += sys_residual;
103         if (dtemp >= 1) {
104                 dtemp -= 1;
105                 now->l_i++;
106         } else if (dtemp < 0) {
107                 dtemp += 1;
108                 now->l_i--;
109         }
110         dtemp *= FRAC;
111         now->l_uf = (u_int32)dtemp;
112 }
113
114
115 /*
116  * adj_systime - adjust system time by the argument.
117  */
118 #if !defined SYS_WINNT
119 int                             /* 0 okay, 1 error */
120 adj_systime(
121         double now              /* adjustment (s) */
122         )
123 {
124         struct timeval adjtv;   /* new adjustment */
125         struct timeval oadjtv;  /* residual adjustment */
126         double  dtemp;
127         long    ticks;
128         int     isneg = 0;
129
130         /*
131          * Most Unix adjtime() implementations adjust the system clock
132          * in microsecond quanta, but some adjust in 10-ms quanta. We
133          * carefully round the adjustment to the nearest quantum, then
134          * adjust in quanta and keep the residue for later.
135          */
136         dtemp = now + sys_residual;
137         if (dtemp < 0) {
138                 isneg = 1;
139                 dtemp = -dtemp;
140         }
141         adjtv.tv_sec = (long)dtemp;
142         dtemp -= adjtv.tv_sec;
143         ticks = (long)(dtemp / sys_tick + .5);
144         adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
145         dtemp -= adjtv.tv_usec / 1e6;
146         sys_residual = dtemp;
147
148         /*
149          * Convert to signed seconds and microseconds for the Unix
150          * adjtime() system call. Note we purposely lose the adjtime()
151          * leftover.
152          */
153         if (isneg) {
154                 adjtv.tv_sec = -adjtv.tv_sec;
155                 adjtv.tv_usec = -adjtv.tv_usec;
156                 sys_residual = -sys_residual;
157         }
158         if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {
159                 if (adjtime(&adjtv, &oadjtv) < 0) {
160                         msyslog(LOG_ERR, "adj_systime: %m");
161                         return (0);
162                 }
163         }
164         return (1);
165 }
166 #endif
167
168
169 /*
170  * step_systime - step the system clock.
171  */
172 int
173 step_systime(
174         double now
175         )
176 {
177         struct timeval timetv, adjtv, oldtimetv;
178         int isneg = 0;
179         double dtemp;
180 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
181         struct timespec ts;
182 #endif
183
184         dtemp = sys_residual + now;
185         if (dtemp < 0) {
186                 isneg = 1;
187                 dtemp = - dtemp;
188                 adjtv.tv_sec = (int32)dtemp;
189                 adjtv.tv_usec = (u_int32)((dtemp -
190                     (double)adjtv.tv_sec) * 1e6 + .5);
191         } else {
192                 adjtv.tv_sec = (int32)dtemp;
193                 adjtv.tv_usec = (u_int32)((dtemp -
194                     (double)adjtv.tv_sec) * 1e6 + .5);
195         }
196 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
197 # ifdef HAVE_CLOCK_GETTIME
198         (void) clock_gettime(CLOCK_REALTIME, &ts);
199 # else
200         (void) getclock(TIMEOFDAY, &ts);
201 # endif
202         timetv.tv_sec = ts.tv_sec;
203         timetv.tv_usec = ts.tv_nsec / 1000;
204 #else /*  not HAVE_GETCLOCK */
205         (void) GETTIMEOFDAY(&timetv, (struct timezone *)0);
206 #endif /* not HAVE_GETCLOCK */
207
208         oldtimetv = timetv;
209
210 #ifdef DEBUG
211         if (debug)
212                 printf("step_systime: step %.6f residual %.6f\n", now, sys_residual);
213 #endif
214         if (isneg) {
215                 timetv.tv_sec -= adjtv.tv_sec;
216                 timetv.tv_usec -= adjtv.tv_usec;
217                 if (timetv.tv_usec < 0) {
218                         timetv.tv_sec--;
219                         timetv.tv_usec += 1000000;
220                 }
221         } else {
222                 timetv.tv_sec += adjtv.tv_sec;
223                 timetv.tv_usec += adjtv.tv_usec;
224                 if (timetv.tv_usec >= 1000000) {
225                         timetv.tv_sec++;
226                         timetv.tv_usec -= 1000000;
227                 }
228         }
229         if (ntp_set_tod(&timetv, NULL) != 0) {
230                 msyslog(LOG_ERR, "step-systime: %m");
231                 return (0);
232         }
233         sys_residual = 0;
234
235 #ifdef NEED_HPUX_ADJTIME
236         /*
237          * CHECKME: is this correct when called by ntpdate?????
238          */
239         _clear_adjtime();
240 #endif
241
242         /*
243          * FreeBSD, for example, has:
244          * struct utmp {
245          *         char    ut_line[UT_LINESIZE];
246          *         char    ut_name[UT_NAMESIZE];
247          *         char    ut_host[UT_HOSTSIZE];
248          *         long    ut_time;
249          * };
250          * and appends line="|", name="date", host="", time for the OLD
251          * and appends line="{", name="date", host="", time for the NEW
252          * to _PATH_WTMP .
253          *
254          * Some OSes have utmp, some have utmpx.
255          */
256
257         /*
258          * Write old and new time entries in utmp and wtmp if step
259          * adjustment is greater than one second.
260          *
261          * This might become even Uglier...
262          */
263         if (oldtimetv.tv_sec != timetv.tv_sec)
264         {
265 #ifdef HAVE_UTMP_H
266                 struct utmp ut;
267 #endif
268 #ifdef HAVE_UTMPX_H
269                 struct utmpx utx;
270 #endif
271
272 #ifdef HAVE_UTMP_H
273                 memset((char *)&ut, 0, sizeof(ut));
274 #endif
275 #ifdef HAVE_UTMPX_H
276                 memset((char *)&utx, 0, sizeof(utx));
277 #endif
278
279                 /* UTMP */
280
281 #ifdef UPDATE_UTMP
282 # ifdef HAVE_PUTUTLINE
283                 ut.ut_type = OLD_TIME;
284                 (void)strcpy(ut.ut_line, OTIME_MSG);
285                 ut.ut_time = oldtimetv.tv_sec;
286                 pututline(&ut);
287                 setutent();
288                 ut.ut_type = NEW_TIME;
289                 (void)strcpy(ut.ut_line, NTIME_MSG);
290                 ut.ut_time = timetv.tv_sec;
291                 pututline(&ut);
292                 endutent();
293 # else /* not HAVE_PUTUTLINE */
294 # endif /* not HAVE_PUTUTLINE */
295 #endif /* UPDATE_UTMP */
296
297                 /* UTMPX */
298
299 #ifdef UPDATE_UTMPX
300 # ifdef HAVE_PUTUTXLINE
301                 utx.ut_type = OLD_TIME;
302                 (void)strcpy(utx.ut_line, OTIME_MSG);
303                 utx.ut_tv = oldtimetv;
304                 pututxline(&utx);
305                 setutxent();
306                 utx.ut_type = NEW_TIME;
307                 (void)strcpy(utx.ut_line, NTIME_MSG);
308                 utx.ut_tv = timetv;
309                 pututxline(&utx);
310                 endutxent();
311 # else /* not HAVE_PUTUTXLINE */
312 # endif /* not HAVE_PUTUTXLINE */
313 #endif /* UPDATE_UTMPX */
314
315                 /* WTMP */
316
317 #ifdef UPDATE_WTMP
318 # ifdef HAVE_PUTUTLINE
319                 utmpname(WTMP_FILE);
320                 ut.ut_type = OLD_TIME;
321                 (void)strcpy(ut.ut_line, OTIME_MSG);
322                 ut.ut_time = oldtimetv.tv_sec;
323                 pututline(&ut);
324                 ut.ut_type = NEW_TIME;
325                 (void)strcpy(ut.ut_line, NTIME_MSG);
326                 ut.ut_time = timetv.tv_sec;
327                 pututline(&ut);
328                 endutent();
329 # else /* not HAVE_PUTUTLINE */
330 # endif /* not HAVE_PUTUTLINE */
331 #endif /* UPDATE_WTMP */
332
333                 /* WTMPX */
334
335 #ifdef UPDATE_WTMPX
336 # ifdef HAVE_PUTUTXLINE
337                 utx.ut_type = OLD_TIME;
338                 utx.ut_tv = oldtimetv;
339                 (void)strcpy(utx.ut_line, OTIME_MSG);
340 #  ifdef HAVE_UPDWTMPX
341                 updwtmpx(WTMPX_FILE, &utx);
342 #  else /* not HAVE_UPDWTMPX */
343 #  endif /* not HAVE_UPDWTMPX */
344 # else /* not HAVE_PUTUTXLINE */
345 # endif /* not HAVE_PUTUTXLINE */
346 # ifdef HAVE_PUTUTXLINE
347                 utx.ut_type = NEW_TIME;
348                 utx.ut_tv = timetv;
349                 (void)strcpy(utx.ut_line, NTIME_MSG);
350 #  ifdef HAVE_UPDWTMPX
351                 updwtmpx(WTMPX_FILE, &utx);
352 #  else /* not HAVE_UPDWTMPX */
353 #  endif /* not HAVE_UPDWTMPX */
354 # else /* not HAVE_PUTUTXLINE */
355 # endif /* not HAVE_PUTUTXLINE */
356 #endif /* UPDATE_WTMPX */
357
358         }
359         return (1);
360 }
361
362 #else /* SIM */
363 /*
364  * Clock routines for the simulator - Harish Nair, with help
365  */
366 /*
367  * get_systime - return the system time in NTP timestamp format 
368  */
369 void
370 get_systime(
371         l_fp *now               /* current system time in l_fp */        )
372 {
373         /*
374          * To fool the code that determines the local clock precision,
375          * we advance the clock a minimum of 200 nanoseconds on every
376          * clock read. This is appropriate for a typical modern machine
377          * with nanosecond clocks. Note we make no attempt here to
378          * simulate reading error, since the error is so small. This may
379          * change when the need comes to implement picosecond clocks.
380          */
381         if (ntp_node.ntp_time == ntp_node.last_time)
382                 ntp_node.ntp_time += 200e-9;
383         ntp_node.last_time = ntp_node.ntp_time;
384         DTOLFP(ntp_node.ntp_time, now);
385 }
386  
387  
388 /*
389  * adj_systime - advance or retard the system clock exactly like the
390  * real thng.
391  */
392 int                             /* always succeeds */
393 adj_systime(
394         double now              /* time adjustment (s) */
395         )
396 {
397         struct timeval adjtv;   /* new adjustment */
398         double  dtemp;
399         long    ticks;
400         int     isneg = 0;
401
402         /*
403          * Most Unix adjtime() implementations adjust the system clock
404          * in microsecond quanta, but some adjust in 10-ms quanta. We
405          * carefully round the adjustment to the nearest quantum, then
406          * adjust in quanta and keep the residue for later.
407          */
408         dtemp = now + sys_residual;
409         if (dtemp < 0) {
410                 isneg = 1;
411                 dtemp = -dtemp;
412         }
413         adjtv.tv_sec = (long)dtemp;
414         dtemp -= adjtv.tv_sec;
415         ticks = (long)(dtemp / sys_tick + .5);
416         adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
417         dtemp -= adjtv.tv_usec / 1e6;
418         sys_residual = dtemp;
419
420         /*
421          * Convert to signed seconds and microseconds for the Unix
422          * adjtime() system call. Note we purposely lose the adjtime()
423          * leftover.
424          */
425         if (isneg) {
426                 adjtv.tv_sec = -adjtv.tv_sec;
427                 adjtv.tv_usec = -adjtv.tv_usec;
428                 sys_residual = -sys_residual;
429         }
430         ntp_node.adj = now;
431         return (1);
432 }
433  
434  
435 /*
436  * step_systime - step the system clock. We are religious here.
437  */
438 int                             /* always succeeds */
439 step_systime(
440         double now              /* step adjustment (s) */
441         )
442 {
443 #ifdef DEBUG
444         if (debug)
445                 printf("step_systime: time %.6f adj %.6f\n",
446                    ntp_node.ntp_time, now);
447 #endif
448         ntp_node.ntp_time += now;
449         return (1);
450 }
451
452 /*
453  * node_clock - update the clocks
454  */
455 int                             /* always succeeds */
456 node_clock(
457         Node *n,                /* global node pointer */
458         double t                /* node time */
459         )
460 {
461         double  dtemp;
462
463         /*
464          * Advance client clock (ntp_time). Advance server clock
465          * (clk_time) adjusted for systematic and random frequency
466          * errors. The random error is a random walk computed as the
467          * integral of samples from a Gaussian distribution.
468          */
469         dtemp = t - n->ntp_time;
470         n->time = t;
471         n->ntp_time += dtemp;
472         n->ferr += gauss(0, dtemp * n->fnse);
473         n->clk_time += dtemp * (1 + n->ferr);
474
475         /*
476          * Perform the adjtime() function. If the adjustment completed
477          * in the previous interval, amortize the entire amount; if not,
478          * carry the leftover to the next interval.
479          */
480         dtemp *= n->slew;
481         if (dtemp < fabs(n->adj)) {
482                 if (n->adj < 0) {
483                         n->adj += dtemp;
484                         n->ntp_time -= dtemp;
485                 } else {
486                         n->adj -= dtemp;
487                         n->ntp_time += dtemp;
488                 }
489         } else {
490                 n->ntp_time += n->adj;
491                 n->adj = 0;
492         }
493         return (0);
494 }
495
496  
497 /*
498  * gauss() - returns samples from a gaussion distribution
499  */
500 double                          /* Gaussian sample */
501 gauss(
502         double m,               /* sample mean */
503         double s                /* sample standard deviation (sigma) */
504         )
505 {
506         double q1, q2;
507
508         /*
509          * Roll a sample from a Gaussian distribution with mean m and
510          * standard deviation s. For m = 0, s = 1, mean(y) = 0,
511          * std(y) = 1.
512          */
513         if (s == 0)
514                 return (m);
515         while ((q1 = drand48()) == 0);
516         q2 = drand48();
517         return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2));
518 }
519
520  
521 /*
522  * poisson() - returns samples from a network delay distribution
523  */
524 double                          /* delay sample (s) */
525 poisson(
526         double m,               /* fixed propagation delay (s) */
527         double s                /* exponential parameter (mu) */
528         )
529 {
530         double q1;
531
532         /*
533          * Roll a sample from a composite distribution with propagation
534          * delay m and exponential distribution time with parameter s.
535          * For m = 0, s = 1, mean(y) = std(y) = 1.
536          */
537         if (s == 0)
538                 return (m);
539         while ((q1 = drand48()) == 0);
540         return (m - s * log(q1 * s));
541 }
542 #endif /* SIM */