1 /* 2 * NTP simulator engine - Harish Nair 3 * University of Delaware, 2001 4 */ 5 #include "ntpd.h" 6 #include "ntpsim.h" 7 #include "ntpdsim-opts.h" 8 9 /* 10 * Defines... 11 */ 12 #define SIM_TIME 86400 /* end simulation time */ 13 #define NET_DLY .001 /* network delay */ 14 #define PROC_DLY .001 /* processing delay */ 15 #define BEEP_DLY 3600 /* beep interval (s) */ 16 #define SLEW 500e-6 /* correction rate (PPM) */ 17 18 /* 19 * Function pointers 20 */ 21 void (*funcPtr[]) (Node *, Event) = { 22 &ndbeep, &ndeclk, &ntptmr, &netpkt 23 }; 24 25 26 /* 27 * ntpsim - initialize global variables and event queue and start 28 */ 29 int 30 ntpsim( 31 int argc, 32 char *argv[] 33 ) 34 { 35 Event e; 36 double maxtime; 37 struct timeval seed; 38 39 /* 40 * Initialize the global node 41 */ 42 ntp_node.time = 0; /* simulation time */ 43 ntp_node.sim_time = SIM_TIME; /* end simulation time (-S) */ 44 ntp_node.ntp_time = 0; /* client disciplined time */ 45 ntp_node.adj = 0; /* remaining time correction */ 46 ntp_node.slew = SLEW; /* correction rate (-H) */ 47 48 ntp_node.clk_time = 0; /* server time (-O) */ 49 ntp_node.ferr = 0; /* frequency error (-T) */ 50 ntp_node.fnse = 0; /* random walk noise (-W) */ 51 ntp_node.ndly = NET_DLY; /* network delay (-Y) */ 52 ntp_node.snse = 0; /* phase noise (-C) */ 53 ntp_node.pdly = PROC_DLY; /* processing delay (-Z) */ 54 ntp_node.bdly = BEEP_DLY; /* beep interval (-B) */ 55 56 ntp_node.events = NULL; 57 ntp_node.rbuflist = NULL; 58 59 /* 60 * Initialize ntp variables 61 */ 62 initializing = 1; 63 init_auth(); 64 init_util(); 65 init_restrict(); 66 init_mon(); 67 init_timer(); 68 init_lib(); 69 init_request(); 70 init_control(); 71 init_peer(); 72 init_proto(); 73 init_io(); 74 init_loopfilter(); 75 mon_start(MON_OFF); 76 77 { 78 int optct = optionProcess(&ntpdsimOptions, argc, argv); 79 argc -= optct; 80 argv += optct; 81 } 82 83 getconfig(argc, argv); 84 85 initializing = 0; 86 loop_config(LOOP_DRIFTCOMP, old_drift / 1e6); 87 88 /* 89 * Watch out here, we want the real time, not the silly stuff. 90 */ 91 gettimeofday(&seed, NULL); 92 ntp_srandom(seed.tv_usec); 93 94 /* 95 * Push a beep and timer interrupt on the queue 96 */ 97 push(event(0, BEEP), &ntp_node.events); 98 push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events); 99 100 /* 101 * Pop the queue until nothing is left or time is exceeded 102 */ 103 maxtime = ntp_node.time + ntp_node.sim_time; 104 while (ntp_node.time <= maxtime && ntp_node.events != NULL ) { 105 e = pop(&ntp_node.events); 106 ndeclk(&ntp_node, e); 107 funcPtr[e.function](&ntp_node, e); 108 } 109 return (0); 110 } 111 112 113 /* 114 * Return an event 115 */ 116 Event 117 event( 118 double t, 119 funcTkn f 120 ) 121 { 122 Event e; 123 124 e.time = t; 125 e.function = f; 126 return (e); 127 } 128 129 /* 130 * Create an event queue 131 */ 132 Queue 133 queue( 134 Event e, 135 Queue q 136 ) 137 { 138 Queue ret; 139 140 if ((ret = (Queue)malloc(sizeof(struct List))) == NULL) 141 abortsim("queue-malloc"); 142 ret->event = e; 143 ret->next = q; 144 return (ret); 145 } 146 147 148 /* 149 * Push an event into the event queue 150 */ 151 void push( 152 Event e, 153 Queue *qp 154 ) 155 { 156 Queue *tmp = qp; 157 158 while (*tmp != NULL && ((*tmp)->event.time < e.time)) 159 tmp = &((*tmp)->next); 160 *tmp = queue(e, (*tmp)); 161 } 162 163 164 /* 165 * Pop the first event from the event queue 166 */ 167 Event 168 pop( 169 Queue *qp 170 ) 171 { 172 Event ret; 173 Queue tmp; 174 175 tmp = *qp; 176 if (tmp == NULL) 177 abortsim("pop - empty queue"); 178 ret = tmp->event; 179 *qp = tmp->next; 180 free(tmp); 181 return (ret); 182 } 183 184 185 /* 186 * Update clocks 187 */ 188 void 189 ndeclk( 190 Node *n, 191 Event e 192 ) 193 { 194 node_clock(n, e.time); 195 } 196 197 198 /* 199 * Timer interrupt. Eventually, this results in calling the 200 * srvr_rplyi() routine below. 201 */ 202 void 203 ntptmr( 204 Node *n, 205 Event e 206 ) 207 { 208 struct recvbuf *rbuf; 209 210 timer(); 211 212 /* 213 * Process buffers received. They had better be in order by 214 * receive timestamp. Note that there are no additional buffers 215 * in the current implementation of ntpsim. 216 */ 217 while (n->rbuflist != NULL) { 218 rbuf = n->rbuflist; 219 n->rbuflist = NULL; 220 (rbuf->receiver)(rbuf); 221 free(rbuf); 222 } 223 224 /* 225 * Arm the next timer interrupt. 226 */ 227 push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events); 228 } 229 230 231 /* 232 * srvr_rply() - send packet 233 */ 234 int srvr_rply( 235 Node *n, 236 struct sockaddr_storage *dest, 237 struct interface *inter, struct pkt *rpkt 238 ) 239 { 240 struct pkt xpkt; 241 struct recvbuf rbuf; 242 Event xvnt; 243 double dtemp, etemp; 244 245 /* 246 * Insert packet header values. We make this look like a 247 * stratum-1 server with a GPS clock, but nobody will ever 248 * notice that. 249 */ 250 xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, 251 MODE_SERVER); 252 xpkt.stratum = STRATUM_TO_PKT(((u_char)1)); 253 memcpy(&xpkt.refid, "GPS", 4); 254 xpkt.ppoll = rpkt->ppoll; 255 xpkt.precision = rpkt->precision; 256 xpkt.rootdelay = 0; 257 xpkt.rootdispersion = 0; 258 259 /* 260 * Insert the timestamps. 261 */ 262 xpkt.org = rpkt->xmt; 263 dtemp = poisson(n->ndly, n->snse); /* client->server delay */ 264 DTOLFP(dtemp + n->clk_time, &xpkt.rec); 265 dtemp += poisson(n->pdly, 0); /* server delay */ 266 DTOLFP(dtemp + n->clk_time, &xpkt.xmt); 267 xpkt.reftime = xpkt.xmt; 268 dtemp += poisson(n->ndly, n->snse); /* server->client delay */ 269 270 /* 271 * Insert the I/O stuff. 272 */ 273 rbuf.receiver = receive; 274 get_systime(&rbuf.recv_time); 275 rbuf.recv_length = LEN_PKT_NOMAC; 276 rbuf.recv_pkt = xpkt; 277 memcpy(&rbuf.srcadr, dest, sizeof(struct sockaddr_storage)); 278 memcpy(&rbuf.recv_srcadr, dest, 279 sizeof(struct sockaddr_storage)); 280 if ((rbuf.dstadr = malloc(sizeof(struct interface))) == NULL) 281 abortsim("server-malloc"); 282 memcpy(rbuf.dstadr, inter, sizeof(struct interface)); 283 284 /* 285 * Very carefully predict the time of arrival for the received 286 * packet. 287 */ 288 LFPTOD(&xpkt.org, etemp); 289 etemp += dtemp; 290 xvnt = event(etemp, PACKET); 291 xvnt.rcv_buf = rbuf; 292 push(xvnt, &n->events); 293 return (0); 294 } 295 296 297 /* 298 * netpkt() - receive packet 299 */ 300 void 301 netpkt( 302 Node *n, 303 Event e 304 ) 305 { 306 struct recvbuf *rbuf; 307 struct recvbuf *obuf; 308 309 /* 310 * Insert the packet on the receive queue and record the arrival 311 * time. 312 */ 313 if ((rbuf = malloc(sizeof(struct recvbuf))) == NULL) 314 abortsim("ntprcv-malloc"); 315 memcpy(rbuf, &e.rcv_buf, sizeof(struct recvbuf)); 316 rbuf->receiver = receive; 317 DTOLFP(n->ntp_time, &rbuf->recv_time); 318 obuf = n->rbuflist; 319 320 /* 321 * In the present incarnation, no more than one buffer can be on 322 * the queue; 323 */ 324 if (obuf == NULL) { 325 n->rbuflist = rbuf; 326 } 327 } 328 329 330 /* 331 * ndbeep() - progress indicator 332 */ 333 void 334 ndbeep( 335 Node *n, 336 Event e 337 ) 338 { 339 static int first_time = 1; 340 char *dash = "-----------------"; 341 342 if(n->bdly > 0) { 343 if (first_time) { 344 printf( 345 "\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' '); 346 printf("\t%s\t%s\t%s\n", dash, dash, dash); 347 first_time = 0; 348 push(event(n->bdly, BEEP), &n->events); 349 push(event(n->sim_time, BEEP), &n->events); 350 printf("\t%16.6f\t%16.6f\t%16.6f\n", 351 n->time, n->clk_time, n->ntp_time); 352 return; 353 } 354 printf("\t%16.6f\t%16.6f\t%16.6f\n", 355 n->time, n->clk_time, n->ntp_time); 356 push(event(e.time + n->bdly, BEEP), &n->events); 357 } 358 } 359 360 361 /* 362 * Abort simulation 363 */ 364 void 365 abortsim( 366 char *errmsg 367 ) 368 { 369 perror(errmsg); 370 exit(1); 371 } 372