2
* NTP simulator engine - Harish Nair
3
* University of Delaware, 2001
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) */
20
void (*funcPtr[]) (Node *, Event) = {
21
&ndbeep, &ndeclk, &ntptmr, &netpkt
26
* ntpsim - initialize global variables and event queue and start
39
* Initialize the global node
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) */
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) */
55
ntp_node.events = NULL;
56
ntp_node.rbuflist = NULL;
59
* Initialize ntp variables
76
getconfig(argc, argv);
80
* Watch out here, we want the real time, not the silly stuff.
82
gettimeofday(&seed, NULL);
83
srand48(seed.tv_usec);
86
* Push a beep and timer interrupt on the queue
88
push(event(0, BEEP), &ntp_node.events);
89
push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events);
92
* Pop the queue until nothing is left or time is exceeded
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);
98
funcPtr[e.function](&ntp_node, e);
121
* Create an event queue
131
if ((ret = (Queue)malloc(sizeof(struct List))) == NULL)
132
abortsim("queue-malloc");
140
* Push an event into the event queue
149
while (*tmp != NULL && ((*tmp)->event.time < e.time))
150
tmp = &((*tmp)->next);
151
*tmp = queue(e, (*tmp));
156
* Pop the first event from the event queue
168
abortsim("pop - empty queue");
185
node_clock(n, e.time);
190
* Timer interrupt. Eventually, this results in calling the
191
* srvr_rplyi() routine below.
199
struct recvbuf *rbuf;
204
* Process buffers received. They had better be in order by
207
while (n->rbuflist != NULL) {
209
n->rbuflist = rbuf->next;
210
(rbuf->receiver)(rbuf);
215
* Arm the next timer interrupt.
217
push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events);
222
* srvr_rply() - send packet
226
struct sockaddr_storage *dest,
227
struct interface *inter, struct pkt *rpkt
236
* Insert packet header values. We make this look like a
237
* stratum-1 server with a GPS clock, but nobody will ever
240
xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
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;
247
xpkt.rootdispersion = 0;
250
* Insert the timestamps.
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 */
261
* Insert the I/O stuff.
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));
276
* Very carefully predict the time of arrival for the received
279
LFPTOD(&xpkt.org, etemp);
281
xvnt = event(etemp, PACKET);
283
push(xvnt, &n->events);
289
* netpkt() - receive packet
297
struct recvbuf *rbuf;
298
struct recvbuf *obuf;
301
* Insert the packet on the receive queue and record the arrival
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);
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.
320
while (obuf->next != NULL)
328
* ndbeep() - progress indicator
336
static int first_time = 1;
337
char *dash = "-----------------";
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);
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);
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);