systime.c revision 182007
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 43double sys_tick = 10e-3; /* 10 ms tickadj() */ 44#else 45double sys_tick = 1e-6; /* 1 us tickadj() */ 46#endif 47double sys_residual = 0; /* adjustment residue (s) */ 48 49#ifndef SIM 50 51/* 52 * get_systime - return system time in NTP timestamp format. 53 */ 54void 55get_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 119int /* 0 okay, 1 error */ 120adj_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 */ 172int 173step_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 */ 369void 370get_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 */ 392int /* always succeeds */ 393adj_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 */ 438int /* always succeeds */ 439step_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 */ 455int /* always succeeds */ 456node_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 */ 500double /* Gaussian sample */ 501gauss( 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 */ 524double /* delay sample (s) */ 525poisson( 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 */ 543