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