1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert * systime -- routines to fiddle a UNIX clock. 39c2daa00SOllivier Robert * 49c2daa00SOllivier Robert * ATTENTION: Get approval from Dave Mills on all changes to this file! 59c2daa00SOllivier Robert * 6c0b746e5SOllivier Robert */ 7224ba2bdSOllivier Robert #include "ntp_machine.h" 8224ba2bdSOllivier Robert #include "ntp_fp.h" 9224ba2bdSOllivier Robert #include "ntp_syslog.h" 10224ba2bdSOllivier Robert #include "ntp_unixtime.h" 11224ba2bdSOllivier Robert #include "ntp_stdlib.h" 12c0b746e5SOllivier Robert 139c2daa00SOllivier Robert #ifdef SIM 149c2daa00SOllivier Robert #include "ntpsim.h" 159c2daa00SOllivier Robert #endif /*SIM */ 169c2daa00SOllivier Robert 17c0b746e5SOllivier Robert #ifdef HAVE_SYS_PARAM_H 18c0b746e5SOllivier Robert # include <sys/param.h> 19c0b746e5SOllivier Robert #endif 20c0b746e5SOllivier Robert #ifdef HAVE_UTMP_H 21c0b746e5SOllivier Robert # include <utmp.h> 22c0b746e5SOllivier Robert #endif /* HAVE_UTMP_H */ 23c0b746e5SOllivier Robert #ifdef HAVE_UTMPX_H 24c0b746e5SOllivier Robert # include <utmpx.h> 25c0b746e5SOllivier Robert #endif /* HAVE_UTMPX_H */ 26c0b746e5SOllivier Robert 27c0b746e5SOllivier Robert /* 289c2daa00SOllivier Robert * These routines (get_systime, step_systime, adj_systime) implement an 299c2daa00SOllivier Robert * interface between the system independent NTP clock and the Unix 309c2daa00SOllivier Robert * system clock in various architectures and operating systems. 319c2daa00SOllivier Robert * 329c2daa00SOllivier Robert * Time is a precious quantity in these routines and every effort is 339c2daa00SOllivier Robert * made to minimize errors by always rounding toward zero and amortizing 349c2daa00SOllivier Robert * adjustment residues. By default the adjustment quantum is 1 us for 359c2daa00SOllivier Robert * the usual Unix tickadj() system call, but this can be increased if 369c2daa00SOllivier Robert * necessary by a configuration command. For instance, when the 379c2daa00SOllivier Robert * adjtime() quantum is a clock tick for a 100-Hz clock, the quantum 389c2daa00SOllivier Robert * should be 10 ms. 39c0b746e5SOllivier Robert */ 409c2daa00SOllivier Robert double sys_tick = 1e-6; /* tickadj() quantum (s) */ 419c2daa00SOllivier Robert double sys_residual = 0; /* adjustment residue (s) */ 42c0b746e5SOllivier Robert 439c2daa00SOllivier Robert #ifndef SIM 44c0b746e5SOllivier Robert 45c0b746e5SOllivier Robert /* 469c2daa00SOllivier Robert * get_systime - return system time in NTP timestamp format. 47c0b746e5SOllivier Robert */ 48c0b746e5SOllivier Robert void 49c0b746e5SOllivier Robert get_systime( 509c2daa00SOllivier Robert l_fp *now /* system time */ 51c0b746e5SOllivier Robert ) 52c0b746e5SOllivier Robert { 53c0b746e5SOllivier Robert double dtemp; 54c0b746e5SOllivier Robert 55c0b746e5SOllivier Robert #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 569c2daa00SOllivier Robert struct timespec ts; /* seconds and nanoseconds */ 579c2daa00SOllivier Robert 589c2daa00SOllivier Robert /* 599c2daa00SOllivier Robert * Convert Unix clock from seconds and nanoseconds to seconds. 609c2daa00SOllivier Robert */ 61c0b746e5SOllivier Robert # ifdef HAVE_CLOCK_GETTIME 629c2daa00SOllivier Robert clock_gettime(CLOCK_REALTIME, &ts); 63c0b746e5SOllivier Robert # else 649c2daa00SOllivier Robert getclock(TIMEOFDAY, &ts); 65c0b746e5SOllivier Robert # endif 66c0b746e5SOllivier Robert now->l_i = ts.tv_sec + JAN_1970; 679c2daa00SOllivier Robert dtemp = ts.tv_nsec / 1e9; 68c0b746e5SOllivier Robert 699c2daa00SOllivier Robert #else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 709c2daa00SOllivier Robert struct timeval tv; /* seconds and microseconds */ 719c2daa00SOllivier Robert 729c2daa00SOllivier Robert /* 739c2daa00SOllivier Robert * Convert Unix clock from seconds and microseconds to seconds. 749c2daa00SOllivier Robert */ 759c2daa00SOllivier Robert GETTIMEOFDAY(&tv, NULL); 769c2daa00SOllivier Robert now->l_i = tv.tv_sec + JAN_1970; 77c0b746e5SOllivier Robert dtemp = tv.tv_usec / 1e6; 789c2daa00SOllivier Robert 799c2daa00SOllivier Robert #endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ 809c2daa00SOllivier Robert 819c2daa00SOllivier Robert /* 829c2daa00SOllivier Robert * Renormalize to seconds past 1900 and fraction. 839c2daa00SOllivier Robert */ 84c0b746e5SOllivier Robert dtemp += sys_residual; 859c2daa00SOllivier Robert if (dtemp >= 1) { 869c2daa00SOllivier Robert dtemp -= 1; 879c2daa00SOllivier Robert now->l_i++; 889c2daa00SOllivier Robert } else if (dtemp < -1) { 899c2daa00SOllivier Robert dtemp += 1; 90c0b746e5SOllivier Robert now->l_i--; 91c0b746e5SOllivier Robert } 92c0b746e5SOllivier Robert dtemp *= FRAC; 93c0b746e5SOllivier Robert now->l_uf = (u_int32)dtemp; 94c0b746e5SOllivier Robert } 95c0b746e5SOllivier Robert 96c0b746e5SOllivier Robert 97c0b746e5SOllivier Robert /* 989c2daa00SOllivier Robert * adj_systime - adjust system time by the argument. 99c0b746e5SOllivier Robert */ 100a151a66cSOllivier Robert #if !defined SYS_WINNT 1019c2daa00SOllivier Robert int /* 0 okay, 1 error */ 102c0b746e5SOllivier Robert adj_systime( 1039c2daa00SOllivier Robert double now /* adjustment (s) */ 104c0b746e5SOllivier Robert ) 105c0b746e5SOllivier Robert { 1069c2daa00SOllivier Robert struct timeval adjtv; /* new adjustment */ 1079c2daa00SOllivier Robert struct timeval oadjtv; /* residual adjustment */ 108c0b746e5SOllivier Robert double dtemp; 1099c2daa00SOllivier Robert long ticks; 1109c2daa00SOllivier Robert int isneg = 0; 111c0b746e5SOllivier Robert 112c0b746e5SOllivier Robert /* 1139c2daa00SOllivier Robert * Most Unix adjtime() implementations adjust the system clock 1149c2daa00SOllivier Robert * in microsecond quanta, but some adjust in 10-ms quanta. We 1159c2daa00SOllivier Robert * carefully round the adjustment to the nearest quantum, then 1169c2daa00SOllivier Robert * adjust in quanta and keep the residue for later. 117c0b746e5SOllivier Robert */ 1189c2daa00SOllivier Robert dtemp = now + sys_residual; 119c0b746e5SOllivier Robert if (dtemp < 0) { 120c0b746e5SOllivier Robert isneg = 1; 121c0b746e5SOllivier Robert dtemp = -dtemp; 122c0b746e5SOllivier Robert } 1239c2daa00SOllivier Robert adjtv.tv_sec = (long)dtemp; 1249c2daa00SOllivier Robert dtemp -= adjtv.tv_sec; 1259c2daa00SOllivier Robert ticks = (long)(dtemp / sys_tick + .5); 1269c2daa00SOllivier Robert adjtv.tv_usec = (long)(ticks * sys_tick * 1e6); 1279c2daa00SOllivier Robert dtemp -= adjtv.tv_usec / 1e6; 1289c2daa00SOllivier Robert sys_residual = dtemp; 129c0b746e5SOllivier Robert 130c0b746e5SOllivier Robert /* 1319c2daa00SOllivier Robert * Convert to signed seconds and microseconds for the Unix 1329c2daa00SOllivier Robert * adjtime() system call. Note we purposely lose the adjtime() 1339c2daa00SOllivier Robert * leftover. 134c0b746e5SOllivier Robert */ 1359c2daa00SOllivier Robert if (isneg) { 1369c2daa00SOllivier Robert adjtv.tv_sec = -adjtv.tv_sec; 1379c2daa00SOllivier Robert adjtv.tv_usec = -adjtv.tv_usec; 138c0b746e5SOllivier Robert } 1399c2daa00SOllivier Robert if (adjtime(&adjtv, &oadjtv) < 0) { 1409c2daa00SOllivier Robert msyslog(LOG_ERR, "adj_systime: %m"); 1419c2daa00SOllivier Robert return (0); 142c0b746e5SOllivier Robert } 1439c2daa00SOllivier Robert return (1); 144c0b746e5SOllivier Robert } 145a151a66cSOllivier Robert #endif 146c0b746e5SOllivier Robert 147c0b746e5SOllivier Robert 148c0b746e5SOllivier Robert /* 149c0b746e5SOllivier Robert * step_systime - step the system clock. 150c0b746e5SOllivier Robert */ 151c0b746e5SOllivier Robert int 152c0b746e5SOllivier Robert step_systime( 153c0b746e5SOllivier Robert double now 154c0b746e5SOllivier Robert ) 155c0b746e5SOllivier Robert { 156c0b746e5SOllivier Robert struct timeval timetv, adjtv, oldtimetv; 157c0b746e5SOllivier Robert int isneg = 0; 158c0b746e5SOllivier Robert double dtemp; 159c0b746e5SOllivier Robert #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 160c0b746e5SOllivier Robert struct timespec ts; 161c0b746e5SOllivier Robert #endif 162c0b746e5SOllivier Robert 163c0b746e5SOllivier Robert dtemp = sys_residual + now; 164c0b746e5SOllivier Robert if (dtemp < 0) { 165c0b746e5SOllivier Robert isneg = 1; 166c0b746e5SOllivier Robert dtemp = - dtemp; 167c0b746e5SOllivier Robert adjtv.tv_sec = (int32)dtemp; 1689c2daa00SOllivier Robert adjtv.tv_usec = (u_int32)((dtemp - 1699c2daa00SOllivier Robert (double)adjtv.tv_sec) * 1e6 + .5); 170c0b746e5SOllivier Robert } else { 171c0b746e5SOllivier Robert adjtv.tv_sec = (int32)dtemp; 1729c2daa00SOllivier Robert adjtv.tv_usec = (u_int32)((dtemp - 1739c2daa00SOllivier Robert (double)adjtv.tv_sec) * 1e6 + .5); 174c0b746e5SOllivier Robert } 175c0b746e5SOllivier Robert #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 176c0b746e5SOllivier Robert #ifdef HAVE_CLOCK_GETTIME 177c0b746e5SOllivier Robert (void) clock_gettime(CLOCK_REALTIME, &ts); 178c0b746e5SOllivier Robert #else 179c0b746e5SOllivier Robert (void) getclock(TIMEOFDAY, &ts); 180c0b746e5SOllivier Robert #endif 181c0b746e5SOllivier Robert timetv.tv_sec = ts.tv_sec; 182c0b746e5SOllivier Robert timetv.tv_usec = ts.tv_nsec / 1000; 183c0b746e5SOllivier Robert #else /* not HAVE_GETCLOCK */ 184c0b746e5SOllivier Robert (void) GETTIMEOFDAY(&timetv, (struct timezone *)0); 185c0b746e5SOllivier Robert #endif /* not HAVE_GETCLOCK */ 186c0b746e5SOllivier Robert 187c0b746e5SOllivier Robert oldtimetv = timetv; 188c0b746e5SOllivier Robert 189c0b746e5SOllivier Robert #ifdef DEBUG 190c0b746e5SOllivier Robert if (debug) 191c0b746e5SOllivier Robert printf("step_systime: step %.6f residual %.6f\n", now, sys_residual); 192c0b746e5SOllivier Robert #endif 193c0b746e5SOllivier Robert if (isneg) { 194c0b746e5SOllivier Robert timetv.tv_sec -= adjtv.tv_sec; 195c0b746e5SOllivier Robert timetv.tv_usec -= adjtv.tv_usec; 196c0b746e5SOllivier Robert if (timetv.tv_usec < 0) { 197c0b746e5SOllivier Robert timetv.tv_sec--; 198c0b746e5SOllivier Robert timetv.tv_usec += 1000000; 199c0b746e5SOllivier Robert } 200c0b746e5SOllivier Robert } else { 201c0b746e5SOllivier Robert timetv.tv_sec += adjtv.tv_sec; 202c0b746e5SOllivier Robert timetv.tv_usec += adjtv.tv_usec; 203c0b746e5SOllivier Robert if (timetv.tv_usec >= 1000000) { 204c0b746e5SOllivier Robert timetv.tv_sec++; 205c0b746e5SOllivier Robert timetv.tv_usec -= 1000000; 206c0b746e5SOllivier Robert } 207c0b746e5SOllivier Robert } 2089c2daa00SOllivier Robert if (ntp_set_tod(&timetv, NULL) != 0) { 2099c2daa00SOllivier Robert msyslog(LOG_ERR, "step-systime: %m"); 210c0b746e5SOllivier Robert return (0); 211c0b746e5SOllivier Robert } 212c0b746e5SOllivier Robert sys_residual = 0; 213c0b746e5SOllivier Robert 214c0b746e5SOllivier Robert #ifdef NEED_HPUX_ADJTIME 215c0b746e5SOllivier Robert /* 216c0b746e5SOllivier Robert * CHECKME: is this correct when called by ntpdate????? 217c0b746e5SOllivier Robert */ 218c0b746e5SOllivier Robert _clear_adjtime(); 219c0b746e5SOllivier Robert #endif 220c0b746e5SOllivier Robert 221c0b746e5SOllivier Robert /* 222c0b746e5SOllivier Robert * FreeBSD, for example, has: 223c0b746e5SOllivier Robert * struct utmp { 224c0b746e5SOllivier Robert * char ut_line[UT_LINESIZE]; 225c0b746e5SOllivier Robert * char ut_name[UT_NAMESIZE]; 226c0b746e5SOllivier Robert * char ut_host[UT_HOSTSIZE]; 227c0b746e5SOllivier Robert * long ut_time; 228c0b746e5SOllivier Robert * }; 229c0b746e5SOllivier Robert * and appends line="|", name="date", host="", time for the OLD 230c0b746e5SOllivier Robert * and appends line="{", name="date", host="", time for the NEW 231c0b746e5SOllivier Robert * to _PATH_WTMP . 232c0b746e5SOllivier Robert * 233c0b746e5SOllivier Robert * Some OSes have utmp, some have utmpx. 234c0b746e5SOllivier Robert */ 235c0b746e5SOllivier Robert 236c0b746e5SOllivier Robert /* 2379c2daa00SOllivier Robert * Write old and new time entries in utmp and wtmp if step 2389c2daa00SOllivier Robert * adjustment is greater than one second. 239c0b746e5SOllivier Robert * 240c0b746e5SOllivier Robert * This might become even Uglier... 241c0b746e5SOllivier Robert */ 242c0b746e5SOllivier Robert if (oldtimetv.tv_sec != timetv.tv_sec) 243c0b746e5SOllivier Robert { 244c0b746e5SOllivier Robert #ifdef HAVE_UTMP_H 245c0b746e5SOllivier Robert struct utmp ut; 246c0b746e5SOllivier Robert #endif 247c0b746e5SOllivier Robert #ifdef HAVE_UTMPX_H 248c0b746e5SOllivier Robert struct utmpx utx; 249c0b746e5SOllivier Robert #endif 250c0b746e5SOllivier Robert 251c0b746e5SOllivier Robert #ifdef HAVE_UTMP_H 252c0b746e5SOllivier Robert memset((char *)&ut, 0, sizeof(ut)); 253c0b746e5SOllivier Robert #endif 254c0b746e5SOllivier Robert #ifdef HAVE_UTMPX_H 255c0b746e5SOllivier Robert memset((char *)&utx, 0, sizeof(utx)); 256c0b746e5SOllivier Robert #endif 257c0b746e5SOllivier Robert 258c0b746e5SOllivier Robert /* UTMP */ 259c0b746e5SOllivier Robert 260c0b746e5SOllivier Robert #ifdef UPDATE_UTMP 261c0b746e5SOllivier Robert # ifdef HAVE_PUTUTLINE 262c0b746e5SOllivier Robert ut.ut_type = OLD_TIME; 263c0b746e5SOllivier Robert (void)strcpy(ut.ut_line, OTIME_MSG); 264c0b746e5SOllivier Robert ut.ut_time = oldtimetv.tv_sec; 265c0b746e5SOllivier Robert pututline(&ut); 266c0b746e5SOllivier Robert setutent(); 267c0b746e5SOllivier Robert ut.ut_type = NEW_TIME; 268c0b746e5SOllivier Robert (void)strcpy(ut.ut_line, NTIME_MSG); 269c0b746e5SOllivier Robert ut.ut_time = timetv.tv_sec; 270c0b746e5SOllivier Robert pututline(&ut); 271c0b746e5SOllivier Robert endutent(); 272c0b746e5SOllivier Robert # else /* not HAVE_PUTUTLINE */ 273c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTLINE */ 274c0b746e5SOllivier Robert #endif /* UPDATE_UTMP */ 275c0b746e5SOllivier Robert 276c0b746e5SOllivier Robert /* UTMPX */ 277c0b746e5SOllivier Robert 278c0b746e5SOllivier Robert #ifdef UPDATE_UTMPX 279c0b746e5SOllivier Robert # ifdef HAVE_PUTUTXLINE 280c0b746e5SOllivier Robert utx.ut_type = OLD_TIME; 281c0b746e5SOllivier Robert (void)strcpy(utx.ut_line, OTIME_MSG); 282c0b746e5SOllivier Robert utx.ut_tv = oldtimetv; 283c0b746e5SOllivier Robert pututxline(&utx); 284c0b746e5SOllivier Robert setutxent(); 285c0b746e5SOllivier Robert utx.ut_type = NEW_TIME; 286c0b746e5SOllivier Robert (void)strcpy(utx.ut_line, NTIME_MSG); 287c0b746e5SOllivier Robert utx.ut_tv = timetv; 288c0b746e5SOllivier Robert pututxline(&utx); 289c0b746e5SOllivier Robert endutxent(); 290c0b746e5SOllivier Robert # else /* not HAVE_PUTUTXLINE */ 291c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTXLINE */ 292c0b746e5SOllivier Robert #endif /* UPDATE_UTMPX */ 293c0b746e5SOllivier Robert 294c0b746e5SOllivier Robert /* WTMP */ 295c0b746e5SOllivier Robert 296c0b746e5SOllivier Robert #ifdef UPDATE_WTMP 297c0b746e5SOllivier Robert # ifdef HAVE_PUTUTLINE 298c0b746e5SOllivier Robert utmpname(WTMP_FILE); 299c0b746e5SOllivier Robert ut.ut_type = OLD_TIME; 300c0b746e5SOllivier Robert (void)strcpy(ut.ut_line, OTIME_MSG); 301c0b746e5SOllivier Robert ut.ut_time = oldtimetv.tv_sec; 302c0b746e5SOllivier Robert pututline(&ut); 303c0b746e5SOllivier Robert ut.ut_type = NEW_TIME; 304c0b746e5SOllivier Robert (void)strcpy(ut.ut_line, NTIME_MSG); 305c0b746e5SOllivier Robert ut.ut_time = timetv.tv_sec; 306c0b746e5SOllivier Robert pututline(&ut); 307c0b746e5SOllivier Robert endutent(); 308c0b746e5SOllivier Robert # else /* not HAVE_PUTUTLINE */ 309c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTLINE */ 310c0b746e5SOllivier Robert #endif /* UPDATE_WTMP */ 311c0b746e5SOllivier Robert 312c0b746e5SOllivier Robert /* WTMPX */ 313c0b746e5SOllivier Robert 314c0b746e5SOllivier Robert #ifdef UPDATE_WTMPX 315c0b746e5SOllivier Robert # ifdef HAVE_PUTUTXLINE 316c0b746e5SOllivier Robert utx.ut_type = OLD_TIME; 317c0b746e5SOllivier Robert utx.ut_tv = oldtimetv; 318c0b746e5SOllivier Robert (void)strcpy(utx.ut_line, OTIME_MSG); 319c0b746e5SOllivier Robert # ifdef HAVE_UPDWTMPX 320c0b746e5SOllivier Robert updwtmpx(WTMPX_FILE, &utx); 321c0b746e5SOllivier Robert # else /* not HAVE_UPDWTMPX */ 322c0b746e5SOllivier Robert # endif /* not HAVE_UPDWTMPX */ 323c0b746e5SOllivier Robert # else /* not HAVE_PUTUTXLINE */ 324c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTXLINE */ 325c0b746e5SOllivier Robert # ifdef HAVE_PUTUTXLINE 326c0b746e5SOllivier Robert utx.ut_type = NEW_TIME; 327c0b746e5SOllivier Robert utx.ut_tv = timetv; 328c0b746e5SOllivier Robert (void)strcpy(utx.ut_line, NTIME_MSG); 329c0b746e5SOllivier Robert # ifdef HAVE_UPDWTMPX 330c0b746e5SOllivier Robert updwtmpx(WTMPX_FILE, &utx); 331c0b746e5SOllivier Robert # else /* not HAVE_UPDWTMPX */ 332c0b746e5SOllivier Robert # endif /* not HAVE_UPDWTMPX */ 333c0b746e5SOllivier Robert # else /* not HAVE_PUTUTXLINE */ 334c0b746e5SOllivier Robert # endif /* not HAVE_PUTUTXLINE */ 335c0b746e5SOllivier Robert #endif /* UPDATE_WTMPX */ 336c0b746e5SOllivier Robert 337c0b746e5SOllivier Robert } 338c0b746e5SOllivier Robert return (1); 339c0b746e5SOllivier Robert } 3409c2daa00SOllivier Robert 3419c2daa00SOllivier Robert #else /* SIM */ 3429c2daa00SOllivier Robert /* 3439c2daa00SOllivier Robert * Clock routines for the simulator - Harish Nair, with help 3449c2daa00SOllivier Robert */ 3459c2daa00SOllivier Robert /* 3469c2daa00SOllivier Robert * get_systime - return the system time in NTP timestamp format 3479c2daa00SOllivier Robert */ 3489c2daa00SOllivier Robert void 3499c2daa00SOllivier Robert get_systime( 3509c2daa00SOllivier Robert l_fp *now /* current system time in l_fp */ ) 3519c2daa00SOllivier Robert { 3529c2daa00SOllivier Robert /* 3539c2daa00SOllivier Robert * To fool the code that determines the local clock precision, 3549c2daa00SOllivier Robert * we advance the clock a minimum of 200 nanoseconds on every 3559c2daa00SOllivier Robert * clock read. This is appropriate for a typical modern machine 3569c2daa00SOllivier Robert * with nanosecond clocks. Note we make no attempt here to 3579c2daa00SOllivier Robert * simulate reading error, since the error is so small. This may 3589c2daa00SOllivier Robert * change when the need comes to implement picosecond clocks. 3599c2daa00SOllivier Robert */ 3609c2daa00SOllivier Robert if (ntp_node.ntp_time == ntp_node.last_time) 3619c2daa00SOllivier Robert ntp_node.ntp_time += 200e-9; 3629c2daa00SOllivier Robert ntp_node.last_time = ntp_node.ntp_time; 3639c2daa00SOllivier Robert DTOLFP(ntp_node.ntp_time, now); 3649c2daa00SOllivier Robert } 3659c2daa00SOllivier Robert 3669c2daa00SOllivier Robert 3679c2daa00SOllivier Robert /* 3689c2daa00SOllivier Robert * adj_systime - advance or retard the system clock exactly like the 3699c2daa00SOllivier Robert * real thng. 3709c2daa00SOllivier Robert */ 3719c2daa00SOllivier Robert int /* always succeeds */ 3729c2daa00SOllivier Robert adj_systime( 3739c2daa00SOllivier Robert double now /* time adjustment (s) */ 3749c2daa00SOllivier Robert ) 3759c2daa00SOllivier Robert { 3769c2daa00SOllivier Robert struct timeval adjtv; /* new adjustment */ 3779c2daa00SOllivier Robert double dtemp; 3789c2daa00SOllivier Robert long ticks; 3799c2daa00SOllivier Robert int isneg = 0; 3809c2daa00SOllivier Robert 3819c2daa00SOllivier Robert /* 3829c2daa00SOllivier Robert * Most Unix adjtime() implementations adjust the system clock 3839c2daa00SOllivier Robert * in microsecond quanta, but some adjust in 10-ms quanta. We 3849c2daa00SOllivier Robert * carefully round the adjustment to the nearest quantum, then 3859c2daa00SOllivier Robert * adjust in quanta and keep the residue for later. 3869c2daa00SOllivier Robert */ 3879c2daa00SOllivier Robert dtemp = now + sys_residual; 3889c2daa00SOllivier Robert if (dtemp < 0) { 3899c2daa00SOllivier Robert isneg = 1; 3909c2daa00SOllivier Robert dtemp = -dtemp; 3919c2daa00SOllivier Robert } 3929c2daa00SOllivier Robert adjtv.tv_sec = (long)dtemp; 3939c2daa00SOllivier Robert dtemp -= adjtv.tv_sec; 3949c2daa00SOllivier Robert ticks = (long)(dtemp / sys_tick + .5); 3959c2daa00SOllivier Robert adjtv.tv_usec = (long)(ticks * sys_tick * 1e6); 3969c2daa00SOllivier Robert dtemp -= adjtv.tv_usec / 1e6; 3979c2daa00SOllivier Robert sys_residual = dtemp; 3989c2daa00SOllivier Robert 3999c2daa00SOllivier Robert /* 4009c2daa00SOllivier Robert * Convert to signed seconds and microseconds for the Unix 4019c2daa00SOllivier Robert * adjtime() system call. Note we purposely lose the adjtime() 4029c2daa00SOllivier Robert * leftover. 4039c2daa00SOllivier Robert */ 4049c2daa00SOllivier Robert if (isneg) { 4059c2daa00SOllivier Robert adjtv.tv_sec = -adjtv.tv_sec; 4069c2daa00SOllivier Robert adjtv.tv_usec = -adjtv.tv_usec; 4079c2daa00SOllivier Robert sys_residual = -sys_residual; 4089c2daa00SOllivier Robert } 4099c2daa00SOllivier Robert 4109c2daa00SOllivier Robert /* 4119c2daa00SOllivier Robert * We went to all the trouble just to be sure the emulation is 4129c2daa00SOllivier Robert * precise. We now return to our regularly scheduled concert. 4139c2daa00SOllivier Robert */ 4149c2daa00SOllivier Robert ntp_node.clk_time -= adjtv.tv_sec + adjtv.tv_usec / 1e6; 4159c2daa00SOllivier Robert return (1); 4169c2daa00SOllivier Robert } 4179c2daa00SOllivier Robert 4189c2daa00SOllivier Robert 4199c2daa00SOllivier Robert /* 4209c2daa00SOllivier Robert * step_systime - step the system clock. We are religious here. 4219c2daa00SOllivier Robert */ 4229c2daa00SOllivier Robert int /* always succeeds */ 4239c2daa00SOllivier Robert step_systime( 4249c2daa00SOllivier Robert double now /* step adjustment (s) */ 4259c2daa00SOllivier Robert ) 4269c2daa00SOllivier Robert { 4279c2daa00SOllivier Robert ntp_node.adj = now; 4289c2daa00SOllivier Robert return (1); 4299c2daa00SOllivier Robert } 4309c2daa00SOllivier Robert 4319c2daa00SOllivier Robert /* 4329c2daa00SOllivier Robert * node_clock - update the clocks 4339c2daa00SOllivier Robert */ 4349c2daa00SOllivier Robert int /* always succeeds */ 4359c2daa00SOllivier Robert node_clock( 4369c2daa00SOllivier Robert Node *n, /* global node pointer */ 4379c2daa00SOllivier Robert double t /* node time */ 4389c2daa00SOllivier Robert ) 4399c2daa00SOllivier Robert { 4409c2daa00SOllivier Robert double dtemp; 4419c2daa00SOllivier Robert 4429c2daa00SOllivier Robert /* 4439c2daa00SOllivier Robert * Advance client clock (ntp_time). Advance server clock 4449c2daa00SOllivier Robert * (clk_time) adjusted for systematic and random frequency 4459c2daa00SOllivier Robert * errors. The random error is a random walk computed as the 4469c2daa00SOllivier Robert * integral of samples from a Gaussian distribution. 4479c2daa00SOllivier Robert */ 4489c2daa00SOllivier Robert dtemp = t - n->ntp_time; 4499c2daa00SOllivier Robert n->time = t; 4509c2daa00SOllivier Robert n->ntp_time += dtemp; 4519c2daa00SOllivier Robert n->ferr += gauss(0, dtemp * n->fnse); 4529c2daa00SOllivier Robert n->clk_time += dtemp * (1 + n->ferr); 4539c2daa00SOllivier Robert 4549c2daa00SOllivier Robert /* 4559c2daa00SOllivier Robert * Perform the adjtime() function. If the adjustment completed 4569c2daa00SOllivier Robert * in the previous interval, amortize the entire amount; if not, 4579c2daa00SOllivier Robert * carry the leftover to the next interval. 4589c2daa00SOllivier Robert */ 4599c2daa00SOllivier Robert dtemp *= n->slew; 4609c2daa00SOllivier Robert if (dtemp < fabs(n->adj)) { 4619c2daa00SOllivier Robert if (n->adj < 0) { 4629c2daa00SOllivier Robert n->adj += dtemp; 4639c2daa00SOllivier Robert n->ntp_time -= dtemp; 4649c2daa00SOllivier Robert } else { 4659c2daa00SOllivier Robert n->adj -= dtemp; 4669c2daa00SOllivier Robert n->ntp_time += dtemp; 4679c2daa00SOllivier Robert } 4689c2daa00SOllivier Robert } else { 4699c2daa00SOllivier Robert n->ntp_time += n->adj; 4709c2daa00SOllivier Robert n->adj = 0; 4719c2daa00SOllivier Robert } 4729c2daa00SOllivier Robert return (0); 4739c2daa00SOllivier Robert } 4749c2daa00SOllivier Robert 4759c2daa00SOllivier Robert 4769c2daa00SOllivier Robert /* 4779c2daa00SOllivier Robert * gauss() - returns samples from a gaussion distribution 4789c2daa00SOllivier Robert */ 4799c2daa00SOllivier Robert double /* Gaussian sample */ 4809c2daa00SOllivier Robert gauss( 4819c2daa00SOllivier Robert double m, /* sample mean */ 4829c2daa00SOllivier Robert double s /* sample standard deviation (sigma) */ 4839c2daa00SOllivier Robert ) 4849c2daa00SOllivier Robert { 4859c2daa00SOllivier Robert double q1, q2; 4869c2daa00SOllivier Robert 4879c2daa00SOllivier Robert /* 4889c2daa00SOllivier Robert * Roll a sample from a Gaussian distribution with mean m and 4899c2daa00SOllivier Robert * standard deviation s. For m = 0, s = 1, mean(y) = 0, 4909c2daa00SOllivier Robert * std(y) = 1. 4919c2daa00SOllivier Robert */ 4929c2daa00SOllivier Robert if (s == 0) 4939c2daa00SOllivier Robert return (m); 4949c2daa00SOllivier Robert while ((q1 = drand48()) == 0); 4959c2daa00SOllivier Robert q2 = drand48(); 4969c2daa00SOllivier Robert return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2)); 4979c2daa00SOllivier Robert } 4989c2daa00SOllivier Robert 4999c2daa00SOllivier Robert 5009c2daa00SOllivier Robert /* 5019c2daa00SOllivier Robert * poisson() - returns samples from a network delay distribution 5029c2daa00SOllivier Robert */ 5039c2daa00SOllivier Robert double /* delay sample (s) */ 5049c2daa00SOllivier Robert poisson( 5059c2daa00SOllivier Robert double m, /* fixed propagation delay (s) */ 5069c2daa00SOllivier Robert double s /* exponential parameter (mu) */ 5079c2daa00SOllivier Robert ) 5089c2daa00SOllivier Robert { 5099c2daa00SOllivier Robert double q1; 5109c2daa00SOllivier Robert 5119c2daa00SOllivier Robert /* 5129c2daa00SOllivier Robert * Roll a sample from a composite distribution with propagation 5139c2daa00SOllivier Robert * delay m and exponential distribution time with parameter s. 5149c2daa00SOllivier Robert * For m = 0, s = 1, mean(y) = std(y) = 1. 5159c2daa00SOllivier Robert */ 5169c2daa00SOllivier Robert if (s == 0) 5179c2daa00SOllivier Robert return (m); 5189c2daa00SOllivier Robert while ((q1 = drand48()) == 0); 5199c2daa00SOllivier Robert return (m - s * log(q1 * s)); 5209c2daa00SOllivier Robert } 5219c2daa00SOllivier Robert #endif /* SIM */ 522