1132451Sroberto/* 2132451Sroberto * NTP simulator engine - Harish Nair 3132451Sroberto * University of Delaware, 2001 4132451Sroberto */ 5132451Sroberto#include "ntpd.h" 6132451Sroberto#include "ntpsim.h" 7182007Sroberto#include "ntpdsim-opts.h" 8132451Sroberto 9132451Sroberto/* 10132451Sroberto * Defines... 11132451Sroberto */ 12132451Sroberto#define SIM_TIME 86400 /* end simulation time */ 13132451Sroberto#define NET_DLY .001 /* network delay */ 14132451Sroberto#define PROC_DLY .001 /* processing delay */ 15132451Sroberto#define BEEP_DLY 3600 /* beep interval (s) */ 16132451Sroberto#define SLEW 500e-6 /* correction rate (PPM) */ 17132451Sroberto 18132451Sroberto/* 19132451Sroberto * Function pointers 20132451Sroberto */ 21132451Srobertovoid (*funcPtr[]) (Node *, Event) = { 22132451Sroberto &ndbeep, &ndeclk, &ntptmr, &netpkt 23132451Sroberto}; 24132451Sroberto 25132451Sroberto 26132451Sroberto/* 27132451Sroberto * ntpsim - initialize global variables and event queue and start 28132451Sroberto */ 29132451Srobertoint 30132451Srobertontpsim( 31132451Sroberto int argc, 32132451Sroberto char *argv[] 33132451Sroberto ) 34132451Sroberto{ 35132451Sroberto Event e; 36132451Sroberto double maxtime; 37132451Sroberto struct timeval seed; 38132451Sroberto 39132451Sroberto /* 40132451Sroberto * Initialize the global node 41132451Sroberto */ 42132451Sroberto ntp_node.time = 0; /* simulation time */ 43132451Sroberto ntp_node.sim_time = SIM_TIME; /* end simulation time (-S) */ 44132451Sroberto ntp_node.ntp_time = 0; /* client disciplined time */ 45132451Sroberto ntp_node.adj = 0; /* remaining time correction */ 46132451Sroberto ntp_node.slew = SLEW; /* correction rate (-H) */ 47132451Sroberto 48132451Sroberto ntp_node.clk_time = 0; /* server time (-O) */ 49132451Sroberto ntp_node.ferr = 0; /* frequency error (-T) */ 50132451Sroberto ntp_node.fnse = 0; /* random walk noise (-W) */ 51132451Sroberto ntp_node.ndly = NET_DLY; /* network delay (-Y) */ 52132451Sroberto ntp_node.snse = 0; /* phase noise (-C) */ 53132451Sroberto ntp_node.pdly = PROC_DLY; /* processing delay (-Z) */ 54132451Sroberto ntp_node.bdly = BEEP_DLY; /* beep interval (-B) */ 55132451Sroberto 56132451Sroberto ntp_node.events = NULL; 57132451Sroberto ntp_node.rbuflist = NULL; 58132451Sroberto 59132451Sroberto /* 60132451Sroberto * Initialize ntp variables 61132451Sroberto */ 62132451Sroberto initializing = 1; 63132451Sroberto init_auth(); 64132451Sroberto init_util(); 65132451Sroberto init_restrict(); 66132451Sroberto init_mon(); 67132451Sroberto init_timer(); 68132451Sroberto init_lib(); 69132451Sroberto init_request(); 70132451Sroberto init_control(); 71132451Sroberto init_peer(); 72132451Sroberto init_proto(); 73132451Sroberto init_io(); 74132451Sroberto init_loopfilter(); 75132451Sroberto mon_start(MON_OFF); 76182007Sroberto 77182007Sroberto { 78182007Sroberto int optct = optionProcess(&ntpdsimOptions, argc, argv); 79182007Sroberto argc -= optct; 80182007Sroberto argv += optct; 81182007Sroberto } 82182007Sroberto 83132451Sroberto getconfig(argc, argv); 84182007Sroberto 85132451Sroberto initializing = 0; 86182007Sroberto loop_config(LOOP_DRIFTCOMP, old_drift / 1e6); 87132451Sroberto 88132451Sroberto /* 89132451Sroberto * Watch out here, we want the real time, not the silly stuff. 90132451Sroberto */ 91132451Sroberto gettimeofday(&seed, NULL); 92182007Sroberto ntp_srandom(seed.tv_usec); 93132451Sroberto 94132451Sroberto /* 95132451Sroberto * Push a beep and timer interrupt on the queue 96132451Sroberto */ 97132451Sroberto push(event(0, BEEP), &ntp_node.events); 98132451Sroberto push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events); 99132451Sroberto 100132451Sroberto /* 101132451Sroberto * Pop the queue until nothing is left or time is exceeded 102132451Sroberto */ 103132451Sroberto maxtime = ntp_node.time + ntp_node.sim_time; 104132451Sroberto while (ntp_node.time <= maxtime && ntp_node.events != NULL ) { 105132451Sroberto e = pop(&ntp_node.events); 106132451Sroberto ndeclk(&ntp_node, e); 107132451Sroberto funcPtr[e.function](&ntp_node, e); 108132451Sroberto } 109132451Sroberto return (0); 110132451Sroberto} 111132451Sroberto 112132451Sroberto 113132451Sroberto/* 114132451Sroberto * Return an event 115132451Sroberto */ 116132451SrobertoEvent 117132451Srobertoevent( 118132451Sroberto double t, 119132451Sroberto funcTkn f 120132451Sroberto ) 121132451Sroberto{ 122132451Sroberto Event e; 123132451Sroberto 124132451Sroberto e.time = t; 125132451Sroberto e.function = f; 126132451Sroberto return (e); 127132451Sroberto} 128132451Sroberto 129132451Sroberto/* 130132451Sroberto * Create an event queue 131132451Sroberto */ 132132451SrobertoQueue 133132451Srobertoqueue( 134132451Sroberto Event e, 135132451Sroberto Queue q 136132451Sroberto ) 137132451Sroberto{ 138132451Sroberto Queue ret; 139132451Sroberto 140132451Sroberto if ((ret = (Queue)malloc(sizeof(struct List))) == NULL) 141132451Sroberto abortsim("queue-malloc"); 142132451Sroberto ret->event = e; 143132451Sroberto ret->next = q; 144132451Sroberto return (ret); 145132451Sroberto} 146132451Sroberto 147132451Sroberto 148132451Sroberto/* 149132451Sroberto * Push an event into the event queue 150132451Sroberto */ 151132451Srobertovoid push( 152132451Sroberto Event e, 153132451Sroberto Queue *qp 154132451Sroberto ) 155132451Sroberto{ 156132451Sroberto Queue *tmp = qp; 157132451Sroberto 158132451Sroberto while (*tmp != NULL && ((*tmp)->event.time < e.time)) 159132451Sroberto tmp = &((*tmp)->next); 160132451Sroberto *tmp = queue(e, (*tmp)); 161132451Sroberto} 162132451Sroberto 163132451Sroberto 164132451Sroberto/* 165132451Sroberto * Pop the first event from the event queue 166132451Sroberto */ 167132451SrobertoEvent 168132451Srobertopop( 169132451Sroberto Queue *qp 170132451Sroberto ) 171132451Sroberto{ 172132451Sroberto Event ret; 173132451Sroberto Queue tmp; 174132451Sroberto 175132451Sroberto tmp = *qp; 176132451Sroberto if (tmp == NULL) 177132451Sroberto abortsim("pop - empty queue"); 178132451Sroberto ret = tmp->event; 179132451Sroberto *qp = tmp->next; 180132451Sroberto free(tmp); 181132451Sroberto return (ret); 182132451Sroberto} 183132451Sroberto 184132451Sroberto 185132451Sroberto/* 186132451Sroberto * Update clocks 187132451Sroberto */ 188132451Srobertovoid 189132451Srobertondeclk( 190132451Sroberto Node *n, 191132451Sroberto Event e 192132451Sroberto ) 193132451Sroberto{ 194132451Sroberto node_clock(n, e.time); 195132451Sroberto} 196132451Sroberto 197132451Sroberto 198132451Sroberto/* 199132451Sroberto * Timer interrupt. Eventually, this results in calling the 200132451Sroberto * srvr_rplyi() routine below. 201132451Sroberto */ 202132451Srobertovoid 203132451Srobertontptmr( 204132451Sroberto Node *n, 205132451Sroberto Event e 206132451Sroberto ) 207132451Sroberto{ 208132451Sroberto struct recvbuf *rbuf; 209132451Sroberto 210132451Sroberto timer(); 211132451Sroberto 212132451Sroberto /* 213132451Sroberto * Process buffers received. They had better be in order by 214182007Sroberto * receive timestamp. Note that there are no additional buffers 215182007Sroberto * in the current implementation of ntpsim. 216132451Sroberto */ 217132451Sroberto while (n->rbuflist != NULL) { 218132451Sroberto rbuf = n->rbuflist; 219182007Sroberto n->rbuflist = NULL; 220132451Sroberto (rbuf->receiver)(rbuf); 221132451Sroberto free(rbuf); 222132451Sroberto } 223132451Sroberto 224132451Sroberto /* 225132451Sroberto * Arm the next timer interrupt. 226132451Sroberto */ 227132451Sroberto push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events); 228132451Sroberto} 229132451Sroberto 230132451Sroberto 231132451Sroberto/* 232132451Sroberto * srvr_rply() - send packet 233132451Sroberto */ 234132451Srobertoint srvr_rply( 235132451Sroberto Node *n, 236132451Sroberto struct sockaddr_storage *dest, 237132451Sroberto struct interface *inter, struct pkt *rpkt 238132451Sroberto ) 239132451Sroberto{ 240132451Sroberto struct pkt xpkt; 241132451Sroberto struct recvbuf rbuf; 242132451Sroberto Event xvnt; 243132451Sroberto double dtemp, etemp; 244132451Sroberto 245132451Sroberto /* 246132451Sroberto * Insert packet header values. We make this look like a 247132451Sroberto * stratum-1 server with a GPS clock, but nobody will ever 248132451Sroberto * notice that. 249132451Sroberto */ 250132451Sroberto xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, 251132451Sroberto MODE_SERVER); 252132451Sroberto xpkt.stratum = STRATUM_TO_PKT(((u_char)1)); 253132451Sroberto memcpy(&xpkt.refid, "GPS", 4); 254132451Sroberto xpkt.ppoll = rpkt->ppoll; 255132451Sroberto xpkt.precision = rpkt->precision; 256132451Sroberto xpkt.rootdelay = 0; 257132451Sroberto xpkt.rootdispersion = 0; 258132451Sroberto 259132451Sroberto /* 260132451Sroberto * Insert the timestamps. 261132451Sroberto */ 262132451Sroberto xpkt.org = rpkt->xmt; 263132451Sroberto dtemp = poisson(n->ndly, n->snse); /* client->server delay */ 264132451Sroberto DTOLFP(dtemp + n->clk_time, &xpkt.rec); 265132451Sroberto dtemp += poisson(n->pdly, 0); /* server delay */ 266132451Sroberto DTOLFP(dtemp + n->clk_time, &xpkt.xmt); 267132451Sroberto xpkt.reftime = xpkt.xmt; 268132451Sroberto dtemp += poisson(n->ndly, n->snse); /* server->client delay */ 269132451Sroberto 270132451Sroberto /* 271132451Sroberto * Insert the I/O stuff. 272132451Sroberto */ 273132451Sroberto rbuf.receiver = receive; 274132451Sroberto get_systime(&rbuf.recv_time); 275132451Sroberto rbuf.recv_length = LEN_PKT_NOMAC; 276132451Sroberto rbuf.recv_pkt = xpkt; 277132451Sroberto memcpy(&rbuf.srcadr, dest, sizeof(struct sockaddr_storage)); 278132451Sroberto memcpy(&rbuf.recv_srcadr, dest, 279132451Sroberto sizeof(struct sockaddr_storage)); 280132451Sroberto if ((rbuf.dstadr = malloc(sizeof(struct interface))) == NULL) 281132451Sroberto abortsim("server-malloc"); 282132451Sroberto memcpy(rbuf.dstadr, inter, sizeof(struct interface)); 283132451Sroberto 284132451Sroberto /* 285132451Sroberto * Very carefully predict the time of arrival for the received 286132451Sroberto * packet. 287132451Sroberto */ 288132451Sroberto LFPTOD(&xpkt.org, etemp); 289132451Sroberto etemp += dtemp; 290132451Sroberto xvnt = event(etemp, PACKET); 291132451Sroberto xvnt.rcv_buf = rbuf; 292132451Sroberto push(xvnt, &n->events); 293132451Sroberto return (0); 294132451Sroberto} 295132451Sroberto 296132451Sroberto 297132451Sroberto/* 298132451Sroberto * netpkt() - receive packet 299132451Sroberto */ 300132451Srobertovoid 301132451Srobertonetpkt( 302132451Sroberto Node *n, 303132451Sroberto Event e 304132451Sroberto ) 305132451Sroberto{ 306132451Sroberto struct recvbuf *rbuf; 307132451Sroberto struct recvbuf *obuf; 308132451Sroberto 309132451Sroberto /* 310132451Sroberto * Insert the packet on the receive queue and record the arrival 311132451Sroberto * time. 312132451Sroberto */ 313132451Sroberto if ((rbuf = malloc(sizeof(struct recvbuf))) == NULL) 314132451Sroberto abortsim("ntprcv-malloc"); 315132451Sroberto memcpy(rbuf, &e.rcv_buf, sizeof(struct recvbuf)); 316132451Sroberto rbuf->receiver = receive; 317132451Sroberto DTOLFP(n->ntp_time, &rbuf->recv_time); 318132451Sroberto obuf = n->rbuflist; 319132451Sroberto 320132451Sroberto /* 321132451Sroberto * In the present incarnation, no more than one buffer can be on 322182007Sroberto * the queue; 323132451Sroberto */ 324132451Sroberto if (obuf == NULL) { 325132451Sroberto n->rbuflist = rbuf; 326132451Sroberto } 327132451Sroberto} 328132451Sroberto 329132451Sroberto 330132451Sroberto/* 331132451Sroberto * ndbeep() - progress indicator 332132451Sroberto */ 333132451Srobertovoid 334132451Srobertondbeep( 335132451Sroberto Node *n, 336132451Sroberto Event e 337132451Sroberto ) 338132451Sroberto{ 339132451Sroberto static int first_time = 1; 340132451Sroberto char *dash = "-----------------"; 341132451Sroberto 342132451Sroberto if(n->bdly > 0) { 343132451Sroberto if (first_time) { 344132451Sroberto printf( 345132451Sroberto "\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' '); 346132451Sroberto printf("\t%s\t%s\t%s\n", dash, dash, dash); 347132451Sroberto first_time = 0; 348132451Sroberto push(event(n->bdly, BEEP), &n->events); 349132451Sroberto push(event(n->sim_time, BEEP), &n->events); 350132451Sroberto printf("\t%16.6f\t%16.6f\t%16.6f\n", 351132451Sroberto n->time, n->clk_time, n->ntp_time); 352132451Sroberto return; 353132451Sroberto } 354132451Sroberto printf("\t%16.6f\t%16.6f\t%16.6f\n", 355132451Sroberto n->time, n->clk_time, n->ntp_time); 356132451Sroberto push(event(e.time + n->bdly, BEEP), &n->events); 357132451Sroberto } 358132451Sroberto} 359132451Sroberto 360132451Sroberto 361132451Sroberto/* 362132451Sroberto * Abort simulation 363132451Sroberto */ 364132451Srobertovoid 365132451Srobertoabortsim( 366132451Sroberto char *errmsg 367132451Sroberto ) 368132451Sroberto{ 369132451Sroberto perror(errmsg); 370132451Sroberto exit(1); 371132451Sroberto} 372