1 /* $NetBSD: ntpsim.c,v 1.3 2006/06/11 19:34:12 kardel Exp $ */
4 * NTP simulator engine - Harish Nair
5 * University of Delaware, 2001
9 #include "ntpdsim-opts.h"
14 #define SIM_TIME 86400 /* end simulation time */
15 #define NET_DLY .001 /* network delay */
16 #define PROC_DLY .001 /* processing delay */
17 #define BEEP_DLY 3600 /* beep interval (s) */
18 #define SLEW 500e-6 /* correction rate (PPM) */
23 void (*funcPtr
[]) (Node
*, Event
) = {
24 &ndbeep
, &ndeclk
, &ntptmr
, &netpkt
29 * ntpsim - initialize global variables and event queue and start
42 * Initialize the global node
44 ntp_node
.time
= 0; /* simulation time */
45 ntp_node
.sim_time
= SIM_TIME
; /* end simulation time (-S) */
46 ntp_node
.ntp_time
= 0; /* client disciplined time */
47 ntp_node
.adj
= 0; /* remaining time correction */
48 ntp_node
.slew
= SLEW
; /* correction rate (-H) */
50 ntp_node
.clk_time
= 0; /* server time (-O) */
51 ntp_node
.ferr
= 0; /* frequency error (-T) */
52 ntp_node
.fnse
= 0; /* random walk noise (-W) */
53 ntp_node
.ndly
= NET_DLY
; /* network delay (-Y) */
54 ntp_node
.snse
= 0; /* phase noise (-C) */
55 ntp_node
.pdly
= PROC_DLY
; /* processing delay (-Z) */
56 ntp_node
.bdly
= BEEP_DLY
; /* beep interval (-B) */
58 ntp_node
.events
= NULL
;
59 ntp_node
.rbuflist
= NULL
;
62 * Initialize ntp variables
80 int optct
= optionProcess(&ntpdsimOptions
, argc
, argv
);
85 getconfig(argc
, argv
);
88 loop_config(LOOP_DRIFTCOMP
, old_drift
/ 1e6
);
91 * Watch out here, we want the real time, not the silly stuff.
93 gettimeofday(&seed
, NULL
);
94 ntp_srandom(seed
.tv_usec
);
97 * Push a beep and timer interrupt on the queue
99 push(event(0, BEEP
), &ntp_node
.events
);
100 push(event(ntp_node
.time
+ 1.0, TIMER
), &ntp_node
.events
);
103 * Pop the queue until nothing is left or time is exceeded
105 maxtime
= ntp_node
.time
+ ntp_node
.sim_time
;
106 while (ntp_node
.time
<= maxtime
&& ntp_node
.events
!= NULL
) {
107 e
= pop(&ntp_node
.events
);
108 ndeclk(&ntp_node
, e
);
109 funcPtr
[e
.function
](&ntp_node
, e
);
132 * Create an event queue
142 if ((ret
= (Queue
)malloc(sizeof(struct List
))) == NULL
)
143 abortsim("queue-malloc");
151 * Push an event into the event queue
160 while (*tmp
!= NULL
&& ((*tmp
)->event
.time
< e
.time
))
161 tmp
= &((*tmp
)->next
);
162 *tmp
= queue(e
, (*tmp
));
167 * Pop the first event from the event queue
179 abortsim("pop - empty queue");
196 node_clock(n
, e
.time
);
201 * Timer interrupt. Eventually, this results in calling the
202 * srvr_rplyi() routine below.
210 struct recvbuf
*rbuf
;
215 * Process buffers received. They had better be in order by
216 * receive timestamp. Note that there are no additional buffers
217 * in the current implementation of ntpsim.
219 while (n
->rbuflist
!= NULL
) {
222 (rbuf
->receiver
)(rbuf
);
227 * Arm the next timer interrupt.
229 push(event(e
.time
+ (1 << EVENT_TIMEOUT
), TIMER
), &n
->events
);
234 * srvr_rply() - send packet
238 struct sockaddr_storage
*dest
,
239 struct interface
*inter
, struct pkt
*rpkt
248 * Insert packet header values. We make this look like a
249 * stratum-1 server with a GPS clock, but nobody will ever
252 xpkt
.li_vn_mode
= PKT_LI_VN_MODE(LEAP_NOWARNING
, NTP_VERSION
,
254 xpkt
.stratum
= STRATUM_TO_PKT(((u_char
)1));
255 memcpy(&xpkt
.refid
, "GPS", 4);
256 xpkt
.ppoll
= rpkt
->ppoll
;
257 xpkt
.precision
= rpkt
->precision
;
259 xpkt
.rootdispersion
= 0;
262 * Insert the timestamps.
264 xpkt
.org
= rpkt
->xmt
;
265 dtemp
= poisson(n
->ndly
, n
->snse
); /* client->server delay */
266 DTOLFP(dtemp
+ n
->clk_time
, &xpkt
.rec
);
267 dtemp
+= poisson(n
->pdly
, 0); /* server delay */
268 DTOLFP(dtemp
+ n
->clk_time
, &xpkt
.xmt
);
269 xpkt
.reftime
= xpkt
.xmt
;
270 dtemp
+= poisson(n
->ndly
, n
->snse
); /* server->client delay */
273 * Insert the I/O stuff.
275 rbuf
.receiver
= receive
;
276 get_systime(&rbuf
.recv_time
);
277 rbuf
.recv_length
= LEN_PKT_NOMAC
;
278 rbuf
.recv_pkt
= xpkt
;
279 memcpy(&rbuf
.srcadr
, dest
, sizeof(struct sockaddr_storage
));
280 memcpy(&rbuf
.recv_srcadr
, dest
,
281 sizeof(struct sockaddr_storage
));
282 if ((rbuf
.dstadr
= malloc(sizeof(struct interface
))) == NULL
)
283 abortsim("server-malloc");
284 memcpy(rbuf
.dstadr
, inter
, sizeof(struct interface
));
287 * Very carefully predict the time of arrival for the received
290 LFPTOD(&xpkt
.org
, etemp
);
292 xvnt
= event(etemp
, PACKET
);
294 push(xvnt
, &n
->events
);
300 * netpkt() - receive packet
308 struct recvbuf
*rbuf
;
309 struct recvbuf
*obuf
;
312 * Insert the packet on the receive queue and record the arrival
315 if ((rbuf
= malloc(sizeof(struct recvbuf
))) == NULL
)
316 abortsim("ntprcv-malloc");
317 memcpy(rbuf
, &e
.rcv_buf
, sizeof(struct recvbuf
));
318 rbuf
->receiver
= receive
;
319 DTOLFP(n
->ntp_time
, &rbuf
->recv_time
);
323 * In the present incarnation, no more than one buffer can be on
333 * ndbeep() - progress indicator
341 static int first_time
= 1;
342 char *dash
= "-----------------";
347 "\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' ');
348 printf("\t%s\t%s\t%s\n", dash
, dash
, dash
);
350 push(event(n
->bdly
, BEEP
), &n
->events
);
351 push(event(n
->sim_time
, BEEP
), &n
->events
);
352 printf("\t%16.6f\t%16.6f\t%16.6f\n",
353 n
->time
, n
->clk_time
, n
->ntp_time
);
356 printf("\t%16.6f\t%16.6f\t%16.6f\n",
357 n
->time
, n
->clk_time
, n
->ntp_time
);
358 push(event(e
.time
+ n
->bdly
, BEEP
), &n
->events
);