2 * NTP simulator engine - Harish Nair
3 * University of Delaware, 2001
7 #include "ntpdsim-opts.h"
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) */
21 void (*funcPtr[]) (Node *, Event) = {
22 &ndbeep, &ndeclk, &ntptmr, &netpkt
27 * ntpsim - initialize global variables and event queue and start
40 * Initialize the global node
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) */
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) */
56 ntp_node.events = NULL;
57 ntp_node.rbuflist = NULL;
60 * Initialize ntp variables
78 int optct = optionProcess(&ntpdsimOptions, argc, argv);
83 getconfig(argc, argv);
86 loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
89 * Watch out here, we want the real time, not the silly stuff.
91 gettimeofday(&seed, NULL);
92 ntp_srandom(seed.tv_usec);
95 * Push a beep and timer interrupt on the queue
97 push(event(0, BEEP), &ntp_node.events);
98 push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events);
101 * Pop the queue until nothing is left or time is exceeded
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);
130 * Create an event queue
140 if ((ret = (Queue)malloc(sizeof(struct List))) == NULL)
141 abortsim("queue-malloc");
149 * Push an event into the event queue
158 while (*tmp != NULL && ((*tmp)->event.time < e.time))
159 tmp = &((*tmp)->next);
160 *tmp = queue(e, (*tmp));
165 * Pop the first event from the event queue
177 abortsim("pop - empty queue");
194 node_clock(n, e.time);
199 * Timer interrupt. Eventually, this results in calling the
200 * srvr_rplyi() routine below.
208 struct recvbuf *rbuf;
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.
217 while (n->rbuflist != NULL) {
220 (rbuf->receiver)(rbuf);
225 * Arm the next timer interrupt.
227 push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events);
232 * srvr_rply() - send packet
236 struct sockaddr_storage *dest,
237 struct interface *inter, struct pkt *rpkt
246 * Insert packet header values. We make this look like a
247 * stratum-1 server with a GPS clock, but nobody will ever
250 xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
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;
257 xpkt.rootdispersion = 0;
260 * Insert the timestamps.
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 */
271 * Insert the I/O stuff.
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));
285 * Very carefully predict the time of arrival for the received
288 LFPTOD(&xpkt.org, etemp);
290 xvnt = event(etemp, PACKET);
292 push(xvnt, &n->events);
298 * netpkt() - receive packet
306 struct recvbuf *rbuf;
307 struct recvbuf *obuf;
310 * Insert the packet on the receive queue and record the arrival
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);
321 * In the present incarnation, no more than one buffer can be on
331 * ndbeep() - progress indicator
339 static int first_time = 1;
340 char *dash = "-----------------";
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);
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);
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);