1132451Sroberto/*
2132451Sroberto * NTP simulator engine - Harish Nair
3132451Sroberto * University of Delaware, 2001
4132451Sroberto */
5132451Sroberto#include "ntpd.h"
6132451Sroberto#include "ntpsim.h"
7182007Sroberto#include "ntpdsim-opts.h"
8132451Sroberto
9132451Sroberto/*
10132451Sroberto * Defines...
11132451Sroberto */
12132451Sroberto#define SIM_TIME 86400		/* end simulation time */
13132451Sroberto#define NET_DLY .001            /* network delay */
14132451Sroberto#define PROC_DLY .001		/* processing delay */
15132451Sroberto#define BEEP_DLY 3600           /* beep interval (s) */
16132451Sroberto#define	SLEW	500e-6		/* correction rate (PPM) */
17132451Sroberto
18132451Sroberto/*
19132451Sroberto * Function pointers
20132451Sroberto */
21132451Srobertovoid (*funcPtr[]) (Node *, Event) = {
22132451Sroberto	&ndbeep, &ndeclk, &ntptmr, &netpkt
23132451Sroberto};
24132451Sroberto
25132451Sroberto
26132451Sroberto/*
27132451Sroberto * ntpsim - initialize global variables and event queue and start
28132451Sroberto */
29132451Srobertoint
30132451Srobertontpsim(
31132451Sroberto	int	argc,
32132451Sroberto	char	*argv[]
33132451Sroberto	)
34132451Sroberto{
35132451Sroberto	Event	e;
36132451Sroberto	double	maxtime;
37132451Sroberto	struct timeval seed;
38132451Sroberto
39132451Sroberto	/*
40132451Sroberto	 * Initialize the global node
41132451Sroberto	 */
42132451Sroberto	ntp_node.time = 0;		/* simulation time */
43132451Sroberto	ntp_node.sim_time = SIM_TIME;	/* end simulation time (-S) */
44132451Sroberto	ntp_node.ntp_time = 0;		/* client disciplined time */
45132451Sroberto	ntp_node.adj = 0;		/* remaining time correction */
46132451Sroberto	ntp_node.slew = SLEW;		/* correction rate (-H) */
47132451Sroberto
48132451Sroberto	ntp_node.clk_time = 0;		/* server time (-O) */
49132451Sroberto	ntp_node.ferr = 0;		/* frequency error (-T) */
50132451Sroberto	ntp_node.fnse = 0;		/* random walk noise (-W) */
51132451Sroberto	ntp_node.ndly = NET_DLY;	/* network delay (-Y) */
52132451Sroberto	ntp_node.snse = 0;		/* phase noise (-C) */
53132451Sroberto	ntp_node.pdly = PROC_DLY;	/* processing delay (-Z) */
54132451Sroberto	ntp_node.bdly = BEEP_DLY;	/* beep interval (-B) */
55132451Sroberto
56132451Sroberto	ntp_node.events = NULL;
57132451Sroberto	ntp_node.rbuflist = NULL;
58132451Sroberto
59132451Sroberto	/*
60132451Sroberto	 * Initialize ntp variables
61132451Sroberto	 */
62132451Sroberto	initializing = 1;
63132451Sroberto        init_auth();
64132451Sroberto        init_util();
65132451Sroberto        init_restrict();
66132451Sroberto        init_mon();
67132451Sroberto        init_timer();
68132451Sroberto        init_lib();
69132451Sroberto        init_request();
70132451Sroberto        init_control();
71132451Sroberto        init_peer();
72132451Sroberto        init_proto();
73132451Sroberto        init_io();
74132451Sroberto        init_loopfilter();
75132451Sroberto        mon_start(MON_OFF);
76182007Sroberto
77182007Sroberto	{
78182007Sroberto		int optct = optionProcess(&ntpdsimOptions, argc, argv);
79182007Sroberto		argc -= optct;
80182007Sroberto		argv += optct;
81182007Sroberto	}
82182007Sroberto
83132451Sroberto	getconfig(argc, argv);
84182007Sroberto
85132451Sroberto        initializing = 0;
86182007Sroberto	loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
87132451Sroberto
88132451Sroberto	/*
89132451Sroberto	 * Watch out here, we want the real time, not the silly stuff.
90132451Sroberto	 */
91132451Sroberto	gettimeofday(&seed, NULL);
92182007Sroberto	ntp_srandom(seed.tv_usec);
93132451Sroberto
94132451Sroberto	/*
95132451Sroberto	 * Push a beep and timer interrupt on the queue
96132451Sroberto	 */
97132451Sroberto	push(event(0, BEEP), &ntp_node.events);
98132451Sroberto	push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events);
99132451Sroberto
100132451Sroberto	/*
101132451Sroberto	 * Pop the queue until nothing is left or time is exceeded
102132451Sroberto	 */
103132451Sroberto	maxtime = ntp_node.time + ntp_node.sim_time;
104132451Sroberto	while (ntp_node.time <= maxtime && ntp_node.events != NULL ) {
105132451Sroberto		e = pop(&ntp_node.events);
106132451Sroberto		ndeclk(&ntp_node, e);
107132451Sroberto		funcPtr[e.function](&ntp_node, e);
108132451Sroberto	}
109132451Sroberto	return (0);
110132451Sroberto}
111132451Sroberto
112132451Sroberto
113132451Sroberto/*
114132451Sroberto * Return an event
115132451Sroberto */
116132451SrobertoEvent
117132451Srobertoevent(
118132451Sroberto	double t,
119132451Sroberto	funcTkn f
120132451Sroberto	)
121132451Sroberto{
122132451Sroberto	Event e;
123132451Sroberto
124132451Sroberto	e.time = t;
125132451Sroberto	e.function = f;
126132451Sroberto	return (e);
127132451Sroberto}
128132451Sroberto
129132451Sroberto/*
130132451Sroberto * Create an event queue
131132451Sroberto */
132132451SrobertoQueue
133132451Srobertoqueue(
134132451Sroberto	Event e,
135132451Sroberto	Queue q
136132451Sroberto	)
137132451Sroberto{
138132451Sroberto	Queue ret;
139132451Sroberto
140132451Sroberto	if ((ret = (Queue)malloc(sizeof(struct List))) == NULL)
141132451Sroberto                abortsim("queue-malloc");
142132451Sroberto	ret->event = e;
143132451Sroberto	ret->next = q;
144132451Sroberto	return (ret);
145132451Sroberto}
146132451Sroberto
147132451Sroberto
148132451Sroberto/*
149132451Sroberto * Push an event into the event queue
150132451Sroberto */
151132451Srobertovoid push(
152132451Sroberto	Event e,
153132451Sroberto	Queue *qp
154132451Sroberto	)
155132451Sroberto{
156132451Sroberto	Queue *tmp = qp;
157132451Sroberto
158132451Sroberto	while (*tmp != NULL && ((*tmp)->event.time < e.time))
159132451Sroberto		tmp = &((*tmp)->next);
160132451Sroberto	*tmp = queue(e, (*tmp));
161132451Sroberto}
162132451Sroberto
163132451Sroberto
164132451Sroberto/*
165132451Sroberto * Pop the first event from the event queue
166132451Sroberto */
167132451SrobertoEvent
168132451Srobertopop(
169132451Sroberto	Queue *qp
170132451Sroberto	)
171132451Sroberto{
172132451Sroberto	Event ret;
173132451Sroberto	Queue tmp;
174132451Sroberto
175132451Sroberto	tmp = *qp;
176132451Sroberto	if (tmp == NULL)
177132451Sroberto	    abortsim("pop - empty queue");
178132451Sroberto	ret = tmp->event;
179132451Sroberto	*qp = tmp->next;
180132451Sroberto	free(tmp);
181132451Sroberto	return (ret);
182132451Sroberto}
183132451Sroberto
184132451Sroberto
185132451Sroberto/*
186132451Sroberto * Update clocks
187132451Sroberto */
188132451Srobertovoid
189132451Srobertondeclk(
190132451Sroberto	Node *n,
191132451Sroberto	Event e
192132451Sroberto	)
193132451Sroberto{
194132451Sroberto	node_clock(n, e.time);
195132451Sroberto}
196132451Sroberto
197132451Sroberto
198132451Sroberto/*
199132451Sroberto * Timer interrupt. Eventually, this results in calling the
200132451Sroberto * srvr_rplyi() routine below.
201132451Sroberto */
202132451Srobertovoid
203132451Srobertontptmr(
204132451Sroberto	Node *n,
205132451Sroberto	Event e
206132451Sroberto	)
207132451Sroberto{
208132451Sroberto	struct recvbuf *rbuf;
209132451Sroberto
210132451Sroberto	timer();
211132451Sroberto
212132451Sroberto	/*
213132451Sroberto	 * Process buffers received. They had better be in order by
214182007Sroberto	 * receive timestamp. Note that there are no additional buffers
215182007Sroberto	 * in the current implementation of ntpsim.
216132451Sroberto	 */
217132451Sroberto	while (n->rbuflist != NULL) {
218132451Sroberto		rbuf = n->rbuflist;
219182007Sroberto		n->rbuflist = NULL;
220132451Sroberto		(rbuf->receiver)(rbuf);
221132451Sroberto		free(rbuf);
222132451Sroberto	}
223132451Sroberto
224132451Sroberto	/*
225132451Sroberto	 * Arm the next timer interrupt.
226132451Sroberto	 */
227132451Sroberto	push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events);
228132451Sroberto}
229132451Sroberto
230132451Sroberto
231132451Sroberto/*
232132451Sroberto * srvr_rply() - send packet
233132451Sroberto */
234132451Srobertoint srvr_rply(
235132451Sroberto	Node *n,
236132451Sroberto	struct sockaddr_storage *dest,
237132451Sroberto	struct interface *inter, struct pkt *rpkt
238132451Sroberto	)
239132451Sroberto{
240132451Sroberto	struct pkt xpkt;
241132451Sroberto	struct recvbuf rbuf;
242132451Sroberto	Event   xvnt;
243132451Sroberto	double	dtemp, etemp;
244132451Sroberto
245132451Sroberto	/*
246132451Sroberto	 * Insert packet header values. We make this look like a
247132451Sroberto	 * stratum-1 server with a GPS clock, but nobody will ever
248132451Sroberto	 * notice that.
249132451Sroberto	 */
250132451Sroberto	xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
251132451Sroberto	    MODE_SERVER);
252132451Sroberto	xpkt.stratum = STRATUM_TO_PKT(((u_char)1));
253132451Sroberto	memcpy(&xpkt.refid, "GPS", 4);
254132451Sroberto	xpkt.ppoll = rpkt->ppoll;
255132451Sroberto        xpkt.precision = rpkt->precision;
256132451Sroberto        xpkt.rootdelay = 0;
257132451Sroberto        xpkt.rootdispersion = 0;
258132451Sroberto
259132451Sroberto	/*
260132451Sroberto	 * Insert the timestamps.
261132451Sroberto	 */
262132451Sroberto        xpkt.org = rpkt->xmt;
263132451Sroberto	dtemp = poisson(n->ndly, n->snse); /* client->server delay */
264132451Sroberto	DTOLFP(dtemp + n->clk_time, &xpkt.rec);
265132451Sroberto	dtemp += poisson(n->pdly, 0);	/* server delay */
266132451Sroberto	DTOLFP(dtemp + n->clk_time, &xpkt.xmt);
267132451Sroberto	xpkt.reftime = xpkt.xmt;
268132451Sroberto	dtemp += poisson(n->ndly, n->snse); /* server->client delay */
269132451Sroberto
270132451Sroberto	/*
271132451Sroberto	 * Insert the I/O stuff.
272132451Sroberto	 */
273132451Sroberto	rbuf.receiver = receive;
274132451Sroberto        get_systime(&rbuf.recv_time);
275132451Sroberto        rbuf.recv_length = LEN_PKT_NOMAC;
276132451Sroberto        rbuf.recv_pkt = xpkt;
277132451Sroberto        memcpy(&rbuf.srcadr, dest, sizeof(struct sockaddr_storage));
278132451Sroberto        memcpy(&rbuf.recv_srcadr, dest,
279132451Sroberto	    sizeof(struct sockaddr_storage));
280132451Sroberto        if ((rbuf.dstadr = malloc(sizeof(struct interface))) == NULL)
281132451Sroberto		abortsim("server-malloc");
282132451Sroberto        memcpy(rbuf.dstadr, inter, sizeof(struct interface));
283132451Sroberto
284132451Sroberto	/*
285132451Sroberto	 * Very carefully predict the time of arrival for the received
286132451Sroberto	 * packet.
287132451Sroberto	 */
288132451Sroberto	LFPTOD(&xpkt.org, etemp);
289132451Sroberto	etemp += dtemp;
290132451Sroberto	xvnt = event(etemp, PACKET);
291132451Sroberto	xvnt.rcv_buf = rbuf;
292132451Sroberto	push(xvnt, &n->events);
293132451Sroberto	return (0);
294132451Sroberto}
295132451Sroberto
296132451Sroberto
297132451Sroberto/*
298132451Sroberto * netpkt() - receive packet
299132451Sroberto */
300132451Srobertovoid
301132451Srobertonetpkt(
302132451Sroberto	Node *n,
303132451Sroberto	Event e
304132451Sroberto	)
305132451Sroberto{
306132451Sroberto	struct recvbuf *rbuf;
307132451Sroberto	struct recvbuf *obuf;
308132451Sroberto
309132451Sroberto	/*
310132451Sroberto	 * Insert the packet on the receive queue and record the arrival
311132451Sroberto	 * time.
312132451Sroberto	 */
313132451Sroberto	if ((rbuf = malloc(sizeof(struct recvbuf))) == NULL)
314132451Sroberto		abortsim("ntprcv-malloc");
315132451Sroberto	memcpy(rbuf, &e.rcv_buf, sizeof(struct recvbuf));
316132451Sroberto	rbuf->receiver = receive;
317132451Sroberto	DTOLFP(n->ntp_time, &rbuf->recv_time);
318132451Sroberto	obuf = n->rbuflist;
319132451Sroberto
320132451Sroberto	/*
321132451Sroberto	 * In the present incarnation, no more than one buffer can be on
322182007Sroberto	 * the queue;
323132451Sroberto	 */
324132451Sroberto	if (obuf == NULL) {
325132451Sroberto		n->rbuflist = rbuf;
326132451Sroberto	}
327132451Sroberto}
328132451Sroberto
329132451Sroberto
330132451Sroberto/*
331132451Sroberto * ndbeep() - progress indicator
332132451Sroberto */
333132451Srobertovoid
334132451Srobertondbeep(
335132451Sroberto	Node *n,
336132451Sroberto	Event e
337132451Sroberto	)
338132451Sroberto{
339132451Sroberto	static int first_time = 1;
340132451Sroberto	char *dash = "-----------------";
341132451Sroberto
342132451Sroberto	if(n->bdly > 0) {
343132451Sroberto		if (first_time) {
344132451Sroberto			printf(
345132451Sroberto			    "\t%4c    T    %4c\t%4c  T+ERR  %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' ');
346132451Sroberto			printf("\t%s\t%s\t%s\n", dash, dash, dash);
347132451Sroberto			first_time = 0;
348132451Sroberto			push(event(n->bdly, BEEP), &n->events);
349132451Sroberto        		push(event(n->sim_time, BEEP), &n->events);
350132451Sroberto			printf("\t%16.6f\t%16.6f\t%16.6f\n",
351132451Sroberto                            n->time, n->clk_time, n->ntp_time);
352132451Sroberto			return;
353132451Sroberto		}
354132451Sroberto		printf("\t%16.6f\t%16.6f\t%16.6f\n",
355132451Sroberto		    n->time, n->clk_time, n->ntp_time);
356132451Sroberto		push(event(e.time + n->bdly, BEEP), &n->events);
357132451Sroberto	}
358132451Sroberto}
359132451Sroberto
360132451Sroberto
361132451Sroberto/*
362132451Sroberto * Abort simulation
363132451Sroberto */
364132451Srobertovoid
365132451Srobertoabortsim(
366132451Sroberto	char *errmsg
367132451Sroberto	)
368132451Sroberto{
369132451Sroberto        perror(errmsg);
370132451Sroberto        exit(1);
371132451Sroberto}
372