xref: /freebsd/contrib/ntp/ntpd/ntpsim.c (revision 3a92d97ff0f22d21608e1c19b83104c4937523b6)
1 /*
2  * NTP simulator engine - Harish Nair
3  * University of Delaware, 2001
4  */
5 #include "ntpd.h"
6 #include "ntpsim.h"
7 #include "ntpdsim-opts.h"
8 
9 /*
10  * Defines...
11  */
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) */
17 
18 /*
19  * Function pointers
20  */
21 void (*funcPtr[]) (Node *, Event) = {
22 	&ndbeep, &ndeclk, &ntptmr, &netpkt
23 };
24 
25 
26 /*
27  * ntpsim - initialize global variables and event queue and start
28  */
29 int
30 ntpsim(
31 	int	argc,
32 	char	*argv[]
33 	)
34 {
35 	Event	e;
36 	double	maxtime;
37 	struct timeval seed;
38 
39 	/*
40 	 * Initialize the global node
41 	 */
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) */
47 
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) */
55 
56 	ntp_node.events = NULL;
57 	ntp_node.rbuflist = NULL;
58 
59 	/*
60 	 * Initialize ntp variables
61 	 */
62 	initializing = 1;
63         init_auth();
64         init_util();
65         init_restrict();
66         init_mon();
67         init_timer();
68         init_lib();
69         init_request();
70         init_control();
71         init_peer();
72         init_proto();
73         init_io();
74         init_loopfilter();
75         mon_start(MON_OFF);
76 
77 	{
78 		int optct = optionProcess(&ntpdsimOptions, argc, argv);
79 		argc -= optct;
80 		argv += optct;
81 	}
82 
83 	getconfig(argc, argv);
84 
85         initializing = 0;
86 	loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
87 
88 	/*
89 	 * Watch out here, we want the real time, not the silly stuff.
90 	 */
91 	gettimeofday(&seed, NULL);
92 	ntp_srandom(seed.tv_usec);
93 
94 	/*
95 	 * Push a beep and timer interrupt on the queue
96 	 */
97 	push(event(0, BEEP), &ntp_node.events);
98 	push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events);
99 
100 	/*
101 	 * Pop the queue until nothing is left or time is exceeded
102 	 */
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);
108 	}
109 	return (0);
110 }
111 
112 
113 /*
114  * Return an event
115  */
116 Event
117 event(
118 	double t,
119 	funcTkn f
120 	)
121 {
122 	Event e;
123 
124 	e.time = t;
125 	e.function = f;
126 	return (e);
127 }
128 
129 /*
130  * Create an event queue
131  */
132 Queue
133 queue(
134 	Event e,
135 	Queue q
136 	)
137 {
138 	Queue ret;
139 
140 	if ((ret = (Queue)malloc(sizeof(struct List))) == NULL)
141                 abortsim("queue-malloc");
142 	ret->event = e;
143 	ret->next = q;
144 	return (ret);
145 }
146 
147 
148 /*
149  * Push an event into the event queue
150  */
151 void push(
152 	Event e,
153 	Queue *qp
154 	)
155 {
156 	Queue *tmp = qp;
157 
158 	while (*tmp != NULL && ((*tmp)->event.time < e.time))
159 		tmp = &((*tmp)->next);
160 	*tmp = queue(e, (*tmp));
161 }
162 
163 
164 /*
165  * Pop the first event from the event queue
166  */
167 Event
168 pop(
169 	Queue *qp
170 	)
171 {
172 	Event ret;
173 	Queue tmp;
174 
175 	tmp = *qp;
176 	if (tmp == NULL)
177 	    abortsim("pop - empty queue");
178 	ret = tmp->event;
179 	*qp = tmp->next;
180 	free(tmp);
181 	return (ret);
182 }
183 
184 
185 /*
186  * Update clocks
187  */
188 void
189 ndeclk(
190 	Node *n,
191 	Event e
192 	)
193 {
194 	node_clock(n, e.time);
195 }
196 
197 
198 /*
199  * Timer interrupt. Eventually, this results in calling the
200  * srvr_rplyi() routine below.
201  */
202 void
203 ntptmr(
204 	Node *n,
205 	Event e
206 	)
207 {
208 	struct recvbuf *rbuf;
209 
210 	timer();
211 
212 	/*
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.
216 	 */
217 	while (n->rbuflist != NULL) {
218 		rbuf = n->rbuflist;
219 		n->rbuflist = NULL;
220 		(rbuf->receiver)(rbuf);
221 		free(rbuf);
222 	}
223 
224 	/*
225 	 * Arm the next timer interrupt.
226 	 */
227 	push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events);
228 }
229 
230 
231 /*
232  * srvr_rply() - send packet
233  */
234 int srvr_rply(
235 	Node *n,
236 	struct sockaddr_storage *dest,
237 	struct interface *inter, struct pkt *rpkt
238 	)
239 {
240 	struct pkt xpkt;
241 	struct recvbuf rbuf;
242 	Event   xvnt;
243 	double	dtemp, etemp;
244 
245 	/*
246 	 * Insert packet header values. We make this look like a
247 	 * stratum-1 server with a GPS clock, but nobody will ever
248 	 * notice that.
249 	 */
250 	xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
251 	    MODE_SERVER);
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;
256         xpkt.rootdelay = 0;
257         xpkt.rootdispersion = 0;
258 
259 	/*
260 	 * Insert the timestamps.
261 	 */
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 */
269 
270 	/*
271 	 * Insert the I/O stuff.
272 	 */
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));
283 
284 	/*
285 	 * Very carefully predict the time of arrival for the received
286 	 * packet.
287 	 */
288 	LFPTOD(&xpkt.org, etemp);
289 	etemp += dtemp;
290 	xvnt = event(etemp, PACKET);
291 	xvnt.rcv_buf = rbuf;
292 	push(xvnt, &n->events);
293 	return (0);
294 }
295 
296 
297 /*
298  * netpkt() - receive packet
299  */
300 void
301 netpkt(
302 	Node *n,
303 	Event e
304 	)
305 {
306 	struct recvbuf *rbuf;
307 	struct recvbuf *obuf;
308 
309 	/*
310 	 * Insert the packet on the receive queue and record the arrival
311 	 * time.
312 	 */
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);
318 	obuf = n->rbuflist;
319 
320 	/*
321 	 * In the present incarnation, no more than one buffer can be on
322 	 * the queue;
323 	 */
324 	if (obuf == NULL) {
325 		n->rbuflist = rbuf;
326 	}
327 }
328 
329 
330 /*
331  * ndbeep() - progress indicator
332  */
333 void
334 ndbeep(
335 	Node *n,
336 	Event e
337 	)
338 {
339 	static int first_time = 1;
340 	char *dash = "-----------------";
341 
342 	if(n->bdly > 0) {
343 		if (first_time) {
344 			printf(
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);
347 			first_time = 0;
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);
352 			return;
353 		}
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);
357 	}
358 }
359 
360 
361 /*
362  * Abort simulation
363  */
364 void
365 abortsim(
366 	char *errmsg
367 	)
368 {
369         perror(errmsg);
370         exit(1);
371 }
372