19c2daa00SOllivier Robert /* 29c2daa00SOllivier Robert * NTP simulator engine - Harish Nair 39c2daa00SOllivier Robert * University of Delaware, 2001 49c2daa00SOllivier Robert */ 59c2daa00SOllivier Robert #include "ntpd.h" 69c2daa00SOllivier Robert #include "ntpsim.h" 7ea906c41SOllivier Robert #include "ntpdsim-opts.h" 89c2daa00SOllivier Robert 99c2daa00SOllivier Robert /* 109c2daa00SOllivier Robert * Defines... 119c2daa00SOllivier Robert */ 129c2daa00SOllivier Robert #define SIM_TIME 86400 /* end simulation time */ 139c2daa00SOllivier Robert #define NET_DLY .001 /* network delay */ 149c2daa00SOllivier Robert #define PROC_DLY .001 /* processing delay */ 159c2daa00SOllivier Robert #define BEEP_DLY 3600 /* beep interval (s) */ 169c2daa00SOllivier Robert #define SLEW 500e-6 /* correction rate (PPM) */ 179c2daa00SOllivier Robert 189c2daa00SOllivier Robert /* 199c2daa00SOllivier Robert * Function pointers 209c2daa00SOllivier Robert */ 219c2daa00SOllivier Robert void (*funcPtr[]) (Node *, Event) = { 229c2daa00SOllivier Robert &ndbeep, &ndeclk, &ntptmr, &netpkt 239c2daa00SOllivier Robert }; 249c2daa00SOllivier Robert 259c2daa00SOllivier Robert 269c2daa00SOllivier Robert /* 279c2daa00SOllivier Robert * ntpsim - initialize global variables and event queue and start 289c2daa00SOllivier Robert */ 299c2daa00SOllivier Robert int 309c2daa00SOllivier Robert ntpsim( 319c2daa00SOllivier Robert int argc, 329c2daa00SOllivier Robert char *argv[] 339c2daa00SOllivier Robert ) 349c2daa00SOllivier Robert { 359c2daa00SOllivier Robert Event e; 369c2daa00SOllivier Robert double maxtime; 379c2daa00SOllivier Robert struct timeval seed; 389c2daa00SOllivier Robert 399c2daa00SOllivier Robert /* 409c2daa00SOllivier Robert * Initialize the global node 419c2daa00SOllivier Robert */ 429c2daa00SOllivier Robert ntp_node.time = 0; /* simulation time */ 439c2daa00SOllivier Robert ntp_node.sim_time = SIM_TIME; /* end simulation time (-S) */ 449c2daa00SOllivier Robert ntp_node.ntp_time = 0; /* client disciplined time */ 459c2daa00SOllivier Robert ntp_node.adj = 0; /* remaining time correction */ 469c2daa00SOllivier Robert ntp_node.slew = SLEW; /* correction rate (-H) */ 479c2daa00SOllivier Robert 489c2daa00SOllivier Robert ntp_node.clk_time = 0; /* server time (-O) */ 499c2daa00SOllivier Robert ntp_node.ferr = 0; /* frequency error (-T) */ 509c2daa00SOllivier Robert ntp_node.fnse = 0; /* random walk noise (-W) */ 519c2daa00SOllivier Robert ntp_node.ndly = NET_DLY; /* network delay (-Y) */ 529c2daa00SOllivier Robert ntp_node.snse = 0; /* phase noise (-C) */ 539c2daa00SOllivier Robert ntp_node.pdly = PROC_DLY; /* processing delay (-Z) */ 549c2daa00SOllivier Robert ntp_node.bdly = BEEP_DLY; /* beep interval (-B) */ 559c2daa00SOllivier Robert 569c2daa00SOllivier Robert ntp_node.events = NULL; 579c2daa00SOllivier Robert ntp_node.rbuflist = NULL; 589c2daa00SOllivier Robert 599c2daa00SOllivier Robert /* 609c2daa00SOllivier Robert * Initialize ntp variables 619c2daa00SOllivier Robert */ 629c2daa00SOllivier Robert initializing = 1; 639c2daa00SOllivier Robert init_auth(); 649c2daa00SOllivier Robert init_util(); 659c2daa00SOllivier Robert init_restrict(); 669c2daa00SOllivier Robert init_mon(); 679c2daa00SOllivier Robert init_timer(); 689c2daa00SOllivier Robert init_lib(); 699c2daa00SOllivier Robert init_request(); 709c2daa00SOllivier Robert init_control(); 719c2daa00SOllivier Robert init_peer(); 729c2daa00SOllivier Robert init_proto(); 739c2daa00SOllivier Robert init_io(); 749c2daa00SOllivier Robert init_loopfilter(); 759c2daa00SOllivier Robert mon_start(MON_OFF); 76ea906c41SOllivier Robert 77ea906c41SOllivier Robert { 78ea906c41SOllivier Robert int optct = optionProcess(&ntpdsimOptions, argc, argv); 79ea906c41SOllivier Robert argc -= optct; 80ea906c41SOllivier Robert argv += optct; 81ea906c41SOllivier Robert } 82ea906c41SOllivier Robert 839c2daa00SOllivier Robert getconfig(argc, argv); 84ea906c41SOllivier Robert 859c2daa00SOllivier Robert initializing = 0; 86ea906c41SOllivier Robert loop_config(LOOP_DRIFTCOMP, old_drift / 1e6); 879c2daa00SOllivier Robert 889c2daa00SOllivier Robert /* 899c2daa00SOllivier Robert * Watch out here, we want the real time, not the silly stuff. 909c2daa00SOllivier Robert */ 919c2daa00SOllivier Robert gettimeofday(&seed, NULL); 92ea906c41SOllivier Robert ntp_srandom(seed.tv_usec); 939c2daa00SOllivier Robert 949c2daa00SOllivier Robert /* 959c2daa00SOllivier Robert * Push a beep and timer interrupt on the queue 969c2daa00SOllivier Robert */ 979c2daa00SOllivier Robert push(event(0, BEEP), &ntp_node.events); 989c2daa00SOllivier Robert push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events); 999c2daa00SOllivier Robert 1009c2daa00SOllivier Robert /* 1019c2daa00SOllivier Robert * Pop the queue until nothing is left or time is exceeded 1029c2daa00SOllivier Robert */ 1039c2daa00SOllivier Robert maxtime = ntp_node.time + ntp_node.sim_time; 1049c2daa00SOllivier Robert while (ntp_node.time <= maxtime && ntp_node.events != NULL ) { 1059c2daa00SOllivier Robert e = pop(&ntp_node.events); 1069c2daa00SOllivier Robert ndeclk(&ntp_node, e); 1079c2daa00SOllivier Robert funcPtr[e.function](&ntp_node, e); 1089c2daa00SOllivier Robert } 1099c2daa00SOllivier Robert return (0); 1109c2daa00SOllivier Robert } 1119c2daa00SOllivier Robert 1129c2daa00SOllivier Robert 1139c2daa00SOllivier Robert /* 1149c2daa00SOllivier Robert * Return an event 1159c2daa00SOllivier Robert */ 1169c2daa00SOllivier Robert Event 1179c2daa00SOllivier Robert event( 1189c2daa00SOllivier Robert double t, 1199c2daa00SOllivier Robert funcTkn f 1209c2daa00SOllivier Robert ) 1219c2daa00SOllivier Robert { 1229c2daa00SOllivier Robert Event e; 1239c2daa00SOllivier Robert 1249c2daa00SOllivier Robert e.time = t; 1259c2daa00SOllivier Robert e.function = f; 1269c2daa00SOllivier Robert return (e); 1279c2daa00SOllivier Robert } 1289c2daa00SOllivier Robert 1299c2daa00SOllivier Robert /* 1309c2daa00SOllivier Robert * Create an event queue 1319c2daa00SOllivier Robert */ 1329c2daa00SOllivier Robert Queue 1339c2daa00SOllivier Robert queue( 1349c2daa00SOllivier Robert Event e, 1359c2daa00SOllivier Robert Queue q 1369c2daa00SOllivier Robert ) 1379c2daa00SOllivier Robert { 1389c2daa00SOllivier Robert Queue ret; 1399c2daa00SOllivier Robert 1409c2daa00SOllivier Robert if ((ret = (Queue)malloc(sizeof(struct List))) == NULL) 1419c2daa00SOllivier Robert abortsim("queue-malloc"); 1429c2daa00SOllivier Robert ret->event = e; 1439c2daa00SOllivier Robert ret->next = q; 1449c2daa00SOllivier Robert return (ret); 1459c2daa00SOllivier Robert } 1469c2daa00SOllivier Robert 1479c2daa00SOllivier Robert 1489c2daa00SOllivier Robert /* 1499c2daa00SOllivier Robert * Push an event into the event queue 1509c2daa00SOllivier Robert */ 1519c2daa00SOllivier Robert void push( 1529c2daa00SOllivier Robert Event e, 1539c2daa00SOllivier Robert Queue *qp 1549c2daa00SOllivier Robert ) 1559c2daa00SOllivier Robert { 1569c2daa00SOllivier Robert Queue *tmp = qp; 1579c2daa00SOllivier Robert 1589c2daa00SOllivier Robert while (*tmp != NULL && ((*tmp)->event.time < e.time)) 1599c2daa00SOllivier Robert tmp = &((*tmp)->next); 1609c2daa00SOllivier Robert *tmp = queue(e, (*tmp)); 1619c2daa00SOllivier Robert } 1629c2daa00SOllivier Robert 1639c2daa00SOllivier Robert 1649c2daa00SOllivier Robert /* 1659c2daa00SOllivier Robert * Pop the first event from the event queue 1669c2daa00SOllivier Robert */ 1679c2daa00SOllivier Robert Event 1689c2daa00SOllivier Robert pop( 1699c2daa00SOllivier Robert Queue *qp 1709c2daa00SOllivier Robert ) 1719c2daa00SOllivier Robert { 1729c2daa00SOllivier Robert Event ret; 1739c2daa00SOllivier Robert Queue tmp; 1749c2daa00SOllivier Robert 1759c2daa00SOllivier Robert tmp = *qp; 1769c2daa00SOllivier Robert if (tmp == NULL) 1779c2daa00SOllivier Robert abortsim("pop - empty queue"); 1789c2daa00SOllivier Robert ret = tmp->event; 1799c2daa00SOllivier Robert *qp = tmp->next; 1809c2daa00SOllivier Robert free(tmp); 1819c2daa00SOllivier Robert return (ret); 1829c2daa00SOllivier Robert } 1839c2daa00SOllivier Robert 1849c2daa00SOllivier Robert 1859c2daa00SOllivier Robert /* 1869c2daa00SOllivier Robert * Update clocks 1879c2daa00SOllivier Robert */ 1889c2daa00SOllivier Robert void 1899c2daa00SOllivier Robert ndeclk( 1909c2daa00SOllivier Robert Node *n, 1919c2daa00SOllivier Robert Event e 1929c2daa00SOllivier Robert ) 1939c2daa00SOllivier Robert { 1949c2daa00SOllivier Robert node_clock(n, e.time); 1959c2daa00SOllivier Robert } 1969c2daa00SOllivier Robert 1979c2daa00SOllivier Robert 1989c2daa00SOllivier Robert /* 1999c2daa00SOllivier Robert * Timer interrupt. Eventually, this results in calling the 2009c2daa00SOllivier Robert * srvr_rplyi() routine below. 2019c2daa00SOllivier Robert */ 2029c2daa00SOllivier Robert void 2039c2daa00SOllivier Robert ntptmr( 2049c2daa00SOllivier Robert Node *n, 2059c2daa00SOllivier Robert Event e 2069c2daa00SOllivier Robert ) 2079c2daa00SOllivier Robert { 2089c2daa00SOllivier Robert struct recvbuf *rbuf; 2099c2daa00SOllivier Robert 2109c2daa00SOllivier Robert timer(); 2119c2daa00SOllivier Robert 2129c2daa00SOllivier Robert /* 2139c2daa00SOllivier Robert * Process buffers received. They had better be in order by 214ea906c41SOllivier Robert * receive timestamp. Note that there are no additional buffers 215ea906c41SOllivier Robert * in the current implementation of ntpsim. 2169c2daa00SOllivier Robert */ 2179c2daa00SOllivier Robert while (n->rbuflist != NULL) { 2189c2daa00SOllivier Robert rbuf = n->rbuflist; 219ea906c41SOllivier Robert n->rbuflist = NULL; 2209c2daa00SOllivier Robert (rbuf->receiver)(rbuf); 2219c2daa00SOllivier Robert free(rbuf); 2229c2daa00SOllivier Robert } 2239c2daa00SOllivier Robert 2249c2daa00SOllivier Robert /* 2259c2daa00SOllivier Robert * Arm the next timer interrupt. 2269c2daa00SOllivier Robert */ 2279c2daa00SOllivier Robert push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events); 2289c2daa00SOllivier Robert } 2299c2daa00SOllivier Robert 2309c2daa00SOllivier Robert 2319c2daa00SOllivier Robert /* 2329c2daa00SOllivier Robert * srvr_rply() - send packet 2339c2daa00SOllivier Robert */ 2349c2daa00SOllivier Robert int srvr_rply( 2359c2daa00SOllivier Robert Node *n, 2369c2daa00SOllivier Robert struct sockaddr_storage *dest, 2379c2daa00SOllivier Robert struct interface *inter, struct pkt *rpkt 2389c2daa00SOllivier Robert ) 2399c2daa00SOllivier Robert { 2409c2daa00SOllivier Robert struct pkt xpkt; 2419c2daa00SOllivier Robert struct recvbuf rbuf; 2429c2daa00SOllivier Robert Event xvnt; 2439c2daa00SOllivier Robert double dtemp, etemp; 2449c2daa00SOllivier Robert 2459c2daa00SOllivier Robert /* 2469c2daa00SOllivier Robert * Insert packet header values. We make this look like a 2479c2daa00SOllivier Robert * stratum-1 server with a GPS clock, but nobody will ever 2489c2daa00SOllivier Robert * notice that. 2499c2daa00SOllivier Robert */ 2509c2daa00SOllivier Robert xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, 2519c2daa00SOllivier Robert MODE_SERVER); 2529c2daa00SOllivier Robert xpkt.stratum = STRATUM_TO_PKT(((u_char)1)); 2539c2daa00SOllivier Robert memcpy(&xpkt.refid, "GPS", 4); 2549c2daa00SOllivier Robert xpkt.ppoll = rpkt->ppoll; 2559c2daa00SOllivier Robert xpkt.precision = rpkt->precision; 2569c2daa00SOllivier Robert xpkt.rootdelay = 0; 2579c2daa00SOllivier Robert xpkt.rootdispersion = 0; 2589c2daa00SOllivier Robert 2599c2daa00SOllivier Robert /* 2609c2daa00SOllivier Robert * Insert the timestamps. 2619c2daa00SOllivier Robert */ 2629c2daa00SOllivier Robert xpkt.org = rpkt->xmt; 2639c2daa00SOllivier Robert dtemp = poisson(n->ndly, n->snse); /* client->server delay */ 2649c2daa00SOllivier Robert DTOLFP(dtemp + n->clk_time, &xpkt.rec); 2659c2daa00SOllivier Robert dtemp += poisson(n->pdly, 0); /* server delay */ 2669c2daa00SOllivier Robert DTOLFP(dtemp + n->clk_time, &xpkt.xmt); 2679c2daa00SOllivier Robert xpkt.reftime = xpkt.xmt; 2689c2daa00SOllivier Robert dtemp += poisson(n->ndly, n->snse); /* server->client delay */ 2699c2daa00SOllivier Robert 2709c2daa00SOllivier Robert /* 2719c2daa00SOllivier Robert * Insert the I/O stuff. 2729c2daa00SOllivier Robert */ 2739c2daa00SOllivier Robert rbuf.receiver = receive; 2749c2daa00SOllivier Robert get_systime(&rbuf.recv_time); 2759c2daa00SOllivier Robert rbuf.recv_length = LEN_PKT_NOMAC; 2769c2daa00SOllivier Robert rbuf.recv_pkt = xpkt; 2779c2daa00SOllivier Robert memcpy(&rbuf.srcadr, dest, sizeof(struct sockaddr_storage)); 2789c2daa00SOllivier Robert memcpy(&rbuf.recv_srcadr, dest, 2799c2daa00SOllivier Robert sizeof(struct sockaddr_storage)); 2809c2daa00SOllivier Robert if ((rbuf.dstadr = malloc(sizeof(struct interface))) == NULL) 2819c2daa00SOllivier Robert abortsim("server-malloc"); 2829c2daa00SOllivier Robert memcpy(rbuf.dstadr, inter, sizeof(struct interface)); 2839c2daa00SOllivier Robert 2849c2daa00SOllivier Robert /* 2859c2daa00SOllivier Robert * Very carefully predict the time of arrival for the received 2869c2daa00SOllivier Robert * packet. 2879c2daa00SOllivier Robert */ 2889c2daa00SOllivier Robert LFPTOD(&xpkt.org, etemp); 2899c2daa00SOllivier Robert etemp += dtemp; 2909c2daa00SOllivier Robert xvnt = event(etemp, PACKET); 2919c2daa00SOllivier Robert xvnt.rcv_buf = rbuf; 2929c2daa00SOllivier Robert push(xvnt, &n->events); 2939c2daa00SOllivier Robert return (0); 2949c2daa00SOllivier Robert } 2959c2daa00SOllivier Robert 2969c2daa00SOllivier Robert 2979c2daa00SOllivier Robert /* 2989c2daa00SOllivier Robert * netpkt() - receive packet 2999c2daa00SOllivier Robert */ 3009c2daa00SOllivier Robert void 3019c2daa00SOllivier Robert netpkt( 3029c2daa00SOllivier Robert Node *n, 3039c2daa00SOllivier Robert Event e 3049c2daa00SOllivier Robert ) 3059c2daa00SOllivier Robert { 3069c2daa00SOllivier Robert struct recvbuf *rbuf; 3079c2daa00SOllivier Robert struct recvbuf *obuf; 3089c2daa00SOllivier Robert 3099c2daa00SOllivier Robert /* 3109c2daa00SOllivier Robert * Insert the packet on the receive queue and record the arrival 3119c2daa00SOllivier Robert * time. 3129c2daa00SOllivier Robert */ 3139c2daa00SOllivier Robert if ((rbuf = malloc(sizeof(struct recvbuf))) == NULL) 3149c2daa00SOllivier Robert abortsim("ntprcv-malloc"); 3159c2daa00SOllivier Robert memcpy(rbuf, &e.rcv_buf, sizeof(struct recvbuf)); 3169c2daa00SOllivier Robert rbuf->receiver = receive; 3179c2daa00SOllivier Robert DTOLFP(n->ntp_time, &rbuf->recv_time); 3189c2daa00SOllivier Robert obuf = n->rbuflist; 3199c2daa00SOllivier Robert 3209c2daa00SOllivier Robert /* 3219c2daa00SOllivier Robert * In the present incarnation, no more than one buffer can be on 322ea906c41SOllivier Robert * the queue; 3239c2daa00SOllivier Robert */ 3249c2daa00SOllivier Robert if (obuf == NULL) { 3259c2daa00SOllivier Robert n->rbuflist = rbuf; 3269c2daa00SOllivier Robert } 3279c2daa00SOllivier Robert } 3289c2daa00SOllivier Robert 3299c2daa00SOllivier Robert 3309c2daa00SOllivier Robert /* 3319c2daa00SOllivier Robert * ndbeep() - progress indicator 3329c2daa00SOllivier Robert */ 3339c2daa00SOllivier Robert void 3349c2daa00SOllivier Robert ndbeep( 3359c2daa00SOllivier Robert Node *n, 3369c2daa00SOllivier Robert Event e 3379c2daa00SOllivier Robert ) 3389c2daa00SOllivier Robert { 3399c2daa00SOllivier Robert static int first_time = 1; 3409c2daa00SOllivier Robert char *dash = "-----------------"; 3419c2daa00SOllivier Robert 3429c2daa00SOllivier Robert if(n->bdly > 0) { 3439c2daa00SOllivier Robert if (first_time) { 3449c2daa00SOllivier Robert printf( 3459c2daa00SOllivier Robert "\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' '); 3469c2daa00SOllivier Robert printf("\t%s\t%s\t%s\n", dash, dash, dash); 3479c2daa00SOllivier Robert first_time = 0; 3489c2daa00SOllivier Robert push(event(n->bdly, BEEP), &n->events); 3499c2daa00SOllivier Robert push(event(n->sim_time, BEEP), &n->events); 3509c2daa00SOllivier Robert printf("\t%16.6f\t%16.6f\t%16.6f\n", 3519c2daa00SOllivier Robert n->time, n->clk_time, n->ntp_time); 3529c2daa00SOllivier Robert return; 3539c2daa00SOllivier Robert } 3549c2daa00SOllivier Robert printf("\t%16.6f\t%16.6f\t%16.6f\n", 3559c2daa00SOllivier Robert n->time, n->clk_time, n->ntp_time); 3569c2daa00SOllivier Robert push(event(e.time + n->bdly, BEEP), &n->events); 3579c2daa00SOllivier Robert } 3589c2daa00SOllivier Robert } 3599c2daa00SOllivier Robert 3609c2daa00SOllivier Robert 3619c2daa00SOllivier Robert /* 3629c2daa00SOllivier Robert * Abort simulation 3639c2daa00SOllivier Robert */ 3649c2daa00SOllivier Robert void 3659c2daa00SOllivier Robert abortsim( 3669c2daa00SOllivier Robert char *errmsg 3679c2daa00SOllivier Robert ) 3689c2daa00SOllivier Robert { 3699c2daa00SOllivier Robert perror(errmsg); 3709c2daa00SOllivier Robert exit(1); 3719c2daa00SOllivier Robert } 372