xref: /freebsd/contrib/ntp/ntpd/ntpsim.c (revision ea906c4152774dff300bb26fbfc1e4188351c89a)
19c2daa00SOllivier Robert /*
29c2daa00SOllivier Robert  * NTP simulator engine - Harish Nair
39c2daa00SOllivier Robert  * University of Delaware, 2001
49c2daa00SOllivier Robert  */
59c2daa00SOllivier Robert #include "ntpd.h"
69c2daa00SOllivier Robert #include "ntpsim.h"
7ea906c41SOllivier Robert #include "ntpdsim-opts.h"
89c2daa00SOllivier Robert 
99c2daa00SOllivier Robert /*
109c2daa00SOllivier Robert  * Defines...
119c2daa00SOllivier Robert  */
129c2daa00SOllivier Robert #define SIM_TIME 86400		/* end simulation time */
139c2daa00SOllivier Robert #define NET_DLY .001            /* network delay */
149c2daa00SOllivier Robert #define PROC_DLY .001		/* processing delay */
159c2daa00SOllivier Robert #define BEEP_DLY 3600           /* beep interval (s) */
169c2daa00SOllivier Robert #define	SLEW	500e-6		/* correction rate (PPM) */
179c2daa00SOllivier Robert 
189c2daa00SOllivier Robert /*
199c2daa00SOllivier Robert  * Function pointers
209c2daa00SOllivier Robert  */
219c2daa00SOllivier Robert void (*funcPtr[]) (Node *, Event) = {
229c2daa00SOllivier Robert 	&ndbeep, &ndeclk, &ntptmr, &netpkt
239c2daa00SOllivier Robert };
249c2daa00SOllivier Robert 
259c2daa00SOllivier Robert 
269c2daa00SOllivier Robert /*
279c2daa00SOllivier Robert  * ntpsim - initialize global variables and event queue and start
289c2daa00SOllivier Robert  */
299c2daa00SOllivier Robert int
309c2daa00SOllivier Robert ntpsim(
319c2daa00SOllivier Robert 	int	argc,
329c2daa00SOllivier Robert 	char	*argv[]
339c2daa00SOllivier Robert 	)
349c2daa00SOllivier Robert {
359c2daa00SOllivier Robert 	Event	e;
369c2daa00SOllivier Robert 	double	maxtime;
379c2daa00SOllivier Robert 	struct timeval seed;
389c2daa00SOllivier Robert 
399c2daa00SOllivier Robert 	/*
409c2daa00SOllivier Robert 	 * Initialize the global node
419c2daa00SOllivier Robert 	 */
429c2daa00SOllivier Robert 	ntp_node.time = 0;		/* simulation time */
439c2daa00SOllivier Robert 	ntp_node.sim_time = SIM_TIME;	/* end simulation time (-S) */
449c2daa00SOllivier Robert 	ntp_node.ntp_time = 0;		/* client disciplined time */
459c2daa00SOllivier Robert 	ntp_node.adj = 0;		/* remaining time correction */
469c2daa00SOllivier Robert 	ntp_node.slew = SLEW;		/* correction rate (-H) */
479c2daa00SOllivier Robert 
489c2daa00SOllivier Robert 	ntp_node.clk_time = 0;		/* server time (-O) */
499c2daa00SOllivier Robert 	ntp_node.ferr = 0;		/* frequency error (-T) */
509c2daa00SOllivier Robert 	ntp_node.fnse = 0;		/* random walk noise (-W) */
519c2daa00SOllivier Robert 	ntp_node.ndly = NET_DLY;	/* network delay (-Y) */
529c2daa00SOllivier Robert 	ntp_node.snse = 0;		/* phase noise (-C) */
539c2daa00SOllivier Robert 	ntp_node.pdly = PROC_DLY;	/* processing delay (-Z) */
549c2daa00SOllivier Robert 	ntp_node.bdly = BEEP_DLY;	/* beep interval (-B) */
559c2daa00SOllivier Robert 
569c2daa00SOllivier Robert 	ntp_node.events = NULL;
579c2daa00SOllivier Robert 	ntp_node.rbuflist = NULL;
589c2daa00SOllivier Robert 
599c2daa00SOllivier Robert 	/*
609c2daa00SOllivier Robert 	 * Initialize ntp variables
619c2daa00SOllivier Robert 	 */
629c2daa00SOllivier Robert 	initializing = 1;
639c2daa00SOllivier Robert         init_auth();
649c2daa00SOllivier Robert         init_util();
659c2daa00SOllivier Robert         init_restrict();
669c2daa00SOllivier Robert         init_mon();
679c2daa00SOllivier Robert         init_timer();
689c2daa00SOllivier Robert         init_lib();
699c2daa00SOllivier Robert         init_request();
709c2daa00SOllivier Robert         init_control();
719c2daa00SOllivier Robert         init_peer();
729c2daa00SOllivier Robert         init_proto();
739c2daa00SOllivier Robert         init_io();
749c2daa00SOllivier Robert         init_loopfilter();
759c2daa00SOllivier Robert         mon_start(MON_OFF);
76ea906c41SOllivier Robert 
77ea906c41SOllivier Robert 	{
78ea906c41SOllivier Robert 		int optct = optionProcess(&ntpdsimOptions, argc, argv);
79ea906c41SOllivier Robert 		argc -= optct;
80ea906c41SOllivier Robert 		argv += optct;
81ea906c41SOllivier Robert 	}
82ea906c41SOllivier Robert 
839c2daa00SOllivier Robert 	getconfig(argc, argv);
84ea906c41SOllivier Robert 
859c2daa00SOllivier Robert         initializing = 0;
86ea906c41SOllivier Robert 	loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
879c2daa00SOllivier Robert 
889c2daa00SOllivier Robert 	/*
899c2daa00SOllivier Robert 	 * Watch out here, we want the real time, not the silly stuff.
909c2daa00SOllivier Robert 	 */
919c2daa00SOllivier Robert 	gettimeofday(&seed, NULL);
92ea906c41SOllivier Robert 	ntp_srandom(seed.tv_usec);
939c2daa00SOllivier Robert 
949c2daa00SOllivier Robert 	/*
959c2daa00SOllivier Robert 	 * Push a beep and timer interrupt on the queue
969c2daa00SOllivier Robert 	 */
979c2daa00SOllivier Robert 	push(event(0, BEEP), &ntp_node.events);
989c2daa00SOllivier Robert 	push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events);
999c2daa00SOllivier Robert 
1009c2daa00SOllivier Robert 	/*
1019c2daa00SOllivier Robert 	 * Pop the queue until nothing is left or time is exceeded
1029c2daa00SOllivier Robert 	 */
1039c2daa00SOllivier Robert 	maxtime = ntp_node.time + ntp_node.sim_time;
1049c2daa00SOllivier Robert 	while (ntp_node.time <= maxtime && ntp_node.events != NULL ) {
1059c2daa00SOllivier Robert 		e = pop(&ntp_node.events);
1069c2daa00SOllivier Robert 		ndeclk(&ntp_node, e);
1079c2daa00SOllivier Robert 		funcPtr[e.function](&ntp_node, e);
1089c2daa00SOllivier Robert 	}
1099c2daa00SOllivier Robert 	return (0);
1109c2daa00SOllivier Robert }
1119c2daa00SOllivier Robert 
1129c2daa00SOllivier Robert 
1139c2daa00SOllivier Robert /*
1149c2daa00SOllivier Robert  * Return an event
1159c2daa00SOllivier Robert  */
1169c2daa00SOllivier Robert Event
1179c2daa00SOllivier Robert event(
1189c2daa00SOllivier Robert 	double t,
1199c2daa00SOllivier Robert 	funcTkn f
1209c2daa00SOllivier Robert 	)
1219c2daa00SOllivier Robert {
1229c2daa00SOllivier Robert 	Event e;
1239c2daa00SOllivier Robert 
1249c2daa00SOllivier Robert 	e.time = t;
1259c2daa00SOllivier Robert 	e.function = f;
1269c2daa00SOllivier Robert 	return (e);
1279c2daa00SOllivier Robert }
1289c2daa00SOllivier Robert 
1299c2daa00SOllivier Robert /*
1309c2daa00SOllivier Robert  * Create an event queue
1319c2daa00SOllivier Robert  */
1329c2daa00SOllivier Robert Queue
1339c2daa00SOllivier Robert queue(
1349c2daa00SOllivier Robert 	Event e,
1359c2daa00SOllivier Robert 	Queue q
1369c2daa00SOllivier Robert 	)
1379c2daa00SOllivier Robert {
1389c2daa00SOllivier Robert 	Queue ret;
1399c2daa00SOllivier Robert 
1409c2daa00SOllivier Robert 	if ((ret = (Queue)malloc(sizeof(struct List))) == NULL)
1419c2daa00SOllivier Robert                 abortsim("queue-malloc");
1429c2daa00SOllivier Robert 	ret->event = e;
1439c2daa00SOllivier Robert 	ret->next = q;
1449c2daa00SOllivier Robert 	return (ret);
1459c2daa00SOllivier Robert }
1469c2daa00SOllivier Robert 
1479c2daa00SOllivier Robert 
1489c2daa00SOllivier Robert /*
1499c2daa00SOllivier Robert  * Push an event into the event queue
1509c2daa00SOllivier Robert  */
1519c2daa00SOllivier Robert void push(
1529c2daa00SOllivier Robert 	Event e,
1539c2daa00SOllivier Robert 	Queue *qp
1549c2daa00SOllivier Robert 	)
1559c2daa00SOllivier Robert {
1569c2daa00SOllivier Robert 	Queue *tmp = qp;
1579c2daa00SOllivier Robert 
1589c2daa00SOllivier Robert 	while (*tmp != NULL && ((*tmp)->event.time < e.time))
1599c2daa00SOllivier Robert 		tmp = &((*tmp)->next);
1609c2daa00SOllivier Robert 	*tmp = queue(e, (*tmp));
1619c2daa00SOllivier Robert }
1629c2daa00SOllivier Robert 
1639c2daa00SOllivier Robert 
1649c2daa00SOllivier Robert /*
1659c2daa00SOllivier Robert  * Pop the first event from the event queue
1669c2daa00SOllivier Robert  */
1679c2daa00SOllivier Robert Event
1689c2daa00SOllivier Robert pop(
1699c2daa00SOllivier Robert 	Queue *qp
1709c2daa00SOllivier Robert 	)
1719c2daa00SOllivier Robert {
1729c2daa00SOllivier Robert 	Event ret;
1739c2daa00SOllivier Robert 	Queue tmp;
1749c2daa00SOllivier Robert 
1759c2daa00SOllivier Robert 	tmp = *qp;
1769c2daa00SOllivier Robert 	if (tmp == NULL)
1779c2daa00SOllivier Robert 	    abortsim("pop - empty queue");
1789c2daa00SOllivier Robert 	ret = tmp->event;
1799c2daa00SOllivier Robert 	*qp = tmp->next;
1809c2daa00SOllivier Robert 	free(tmp);
1819c2daa00SOllivier Robert 	return (ret);
1829c2daa00SOllivier Robert }
1839c2daa00SOllivier Robert 
1849c2daa00SOllivier Robert 
1859c2daa00SOllivier Robert /*
1869c2daa00SOllivier Robert  * Update clocks
1879c2daa00SOllivier Robert  */
1889c2daa00SOllivier Robert void
1899c2daa00SOllivier Robert ndeclk(
1909c2daa00SOllivier Robert 	Node *n,
1919c2daa00SOllivier Robert 	Event e
1929c2daa00SOllivier Robert 	)
1939c2daa00SOllivier Robert {
1949c2daa00SOllivier Robert 	node_clock(n, e.time);
1959c2daa00SOllivier Robert }
1969c2daa00SOllivier Robert 
1979c2daa00SOllivier Robert 
1989c2daa00SOllivier Robert /*
1999c2daa00SOllivier Robert  * Timer interrupt. Eventually, this results in calling the
2009c2daa00SOllivier Robert  * srvr_rplyi() routine below.
2019c2daa00SOllivier Robert  */
2029c2daa00SOllivier Robert void
2039c2daa00SOllivier Robert ntptmr(
2049c2daa00SOllivier Robert 	Node *n,
2059c2daa00SOllivier Robert 	Event e
2069c2daa00SOllivier Robert 	)
2079c2daa00SOllivier Robert {
2089c2daa00SOllivier Robert 	struct recvbuf *rbuf;
2099c2daa00SOllivier Robert 
2109c2daa00SOllivier Robert 	timer();
2119c2daa00SOllivier Robert 
2129c2daa00SOllivier Robert 	/*
2139c2daa00SOllivier Robert 	 * Process buffers received. They had better be in order by
214ea906c41SOllivier Robert 	 * receive timestamp. Note that there are no additional buffers
215ea906c41SOllivier Robert 	 * in the current implementation of ntpsim.
2169c2daa00SOllivier Robert 	 */
2179c2daa00SOllivier Robert 	while (n->rbuflist != NULL) {
2189c2daa00SOllivier Robert 		rbuf = n->rbuflist;
219ea906c41SOllivier Robert 		n->rbuflist = NULL;
2209c2daa00SOllivier Robert 		(rbuf->receiver)(rbuf);
2219c2daa00SOllivier Robert 		free(rbuf);
2229c2daa00SOllivier Robert 	}
2239c2daa00SOllivier Robert 
2249c2daa00SOllivier Robert 	/*
2259c2daa00SOllivier Robert 	 * Arm the next timer interrupt.
2269c2daa00SOllivier Robert 	 */
2279c2daa00SOllivier Robert 	push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events);
2289c2daa00SOllivier Robert }
2299c2daa00SOllivier Robert 
2309c2daa00SOllivier Robert 
2319c2daa00SOllivier Robert /*
2329c2daa00SOllivier Robert  * srvr_rply() - send packet
2339c2daa00SOllivier Robert  */
2349c2daa00SOllivier Robert int srvr_rply(
2359c2daa00SOllivier Robert 	Node *n,
2369c2daa00SOllivier Robert 	struct sockaddr_storage *dest,
2379c2daa00SOllivier Robert 	struct interface *inter, struct pkt *rpkt
2389c2daa00SOllivier Robert 	)
2399c2daa00SOllivier Robert {
2409c2daa00SOllivier Robert 	struct pkt xpkt;
2419c2daa00SOllivier Robert 	struct recvbuf rbuf;
2429c2daa00SOllivier Robert 	Event   xvnt;
2439c2daa00SOllivier Robert 	double	dtemp, etemp;
2449c2daa00SOllivier Robert 
2459c2daa00SOllivier Robert 	/*
2469c2daa00SOllivier Robert 	 * Insert packet header values. We make this look like a
2479c2daa00SOllivier Robert 	 * stratum-1 server with a GPS clock, but nobody will ever
2489c2daa00SOllivier Robert 	 * notice that.
2499c2daa00SOllivier Robert 	 */
2509c2daa00SOllivier Robert 	xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
2519c2daa00SOllivier Robert 	    MODE_SERVER);
2529c2daa00SOllivier Robert 	xpkt.stratum = STRATUM_TO_PKT(((u_char)1));
2539c2daa00SOllivier Robert 	memcpy(&xpkt.refid, "GPS", 4);
2549c2daa00SOllivier Robert 	xpkt.ppoll = rpkt->ppoll;
2559c2daa00SOllivier Robert         xpkt.precision = rpkt->precision;
2569c2daa00SOllivier Robert         xpkt.rootdelay = 0;
2579c2daa00SOllivier Robert         xpkt.rootdispersion = 0;
2589c2daa00SOllivier Robert 
2599c2daa00SOllivier Robert 	/*
2609c2daa00SOllivier Robert 	 * Insert the timestamps.
2619c2daa00SOllivier Robert 	 */
2629c2daa00SOllivier Robert         xpkt.org = rpkt->xmt;
2639c2daa00SOllivier Robert 	dtemp = poisson(n->ndly, n->snse); /* client->server delay */
2649c2daa00SOllivier Robert 	DTOLFP(dtemp + n->clk_time, &xpkt.rec);
2659c2daa00SOllivier Robert 	dtemp += poisson(n->pdly, 0);	/* server delay */
2669c2daa00SOllivier Robert 	DTOLFP(dtemp + n->clk_time, &xpkt.xmt);
2679c2daa00SOllivier Robert 	xpkt.reftime = xpkt.xmt;
2689c2daa00SOllivier Robert 	dtemp += poisson(n->ndly, n->snse); /* server->client delay */
2699c2daa00SOllivier Robert 
2709c2daa00SOllivier Robert 	/*
2719c2daa00SOllivier Robert 	 * Insert the I/O stuff.
2729c2daa00SOllivier Robert 	 */
2739c2daa00SOllivier Robert 	rbuf.receiver = receive;
2749c2daa00SOllivier Robert         get_systime(&rbuf.recv_time);
2759c2daa00SOllivier Robert         rbuf.recv_length = LEN_PKT_NOMAC;
2769c2daa00SOllivier Robert         rbuf.recv_pkt = xpkt;
2779c2daa00SOllivier Robert         memcpy(&rbuf.srcadr, dest, sizeof(struct sockaddr_storage));
2789c2daa00SOllivier Robert         memcpy(&rbuf.recv_srcadr, dest,
2799c2daa00SOllivier Robert 	    sizeof(struct sockaddr_storage));
2809c2daa00SOllivier Robert         if ((rbuf.dstadr = malloc(sizeof(struct interface))) == NULL)
2819c2daa00SOllivier Robert 		abortsim("server-malloc");
2829c2daa00SOllivier Robert         memcpy(rbuf.dstadr, inter, sizeof(struct interface));
2839c2daa00SOllivier Robert 
2849c2daa00SOllivier Robert 	/*
2859c2daa00SOllivier Robert 	 * Very carefully predict the time of arrival for the received
2869c2daa00SOllivier Robert 	 * packet.
2879c2daa00SOllivier Robert 	 */
2889c2daa00SOllivier Robert 	LFPTOD(&xpkt.org, etemp);
2899c2daa00SOllivier Robert 	etemp += dtemp;
2909c2daa00SOllivier Robert 	xvnt = event(etemp, PACKET);
2919c2daa00SOllivier Robert 	xvnt.rcv_buf = rbuf;
2929c2daa00SOllivier Robert 	push(xvnt, &n->events);
2939c2daa00SOllivier Robert 	return (0);
2949c2daa00SOllivier Robert }
2959c2daa00SOllivier Robert 
2969c2daa00SOllivier Robert 
2979c2daa00SOllivier Robert /*
2989c2daa00SOllivier Robert  * netpkt() - receive packet
2999c2daa00SOllivier Robert  */
3009c2daa00SOllivier Robert void
3019c2daa00SOllivier Robert netpkt(
3029c2daa00SOllivier Robert 	Node *n,
3039c2daa00SOllivier Robert 	Event e
3049c2daa00SOllivier Robert 	)
3059c2daa00SOllivier Robert {
3069c2daa00SOllivier Robert 	struct recvbuf *rbuf;
3079c2daa00SOllivier Robert 	struct recvbuf *obuf;
3089c2daa00SOllivier Robert 
3099c2daa00SOllivier Robert 	/*
3109c2daa00SOllivier Robert 	 * Insert the packet on the receive queue and record the arrival
3119c2daa00SOllivier Robert 	 * time.
3129c2daa00SOllivier Robert 	 */
3139c2daa00SOllivier Robert 	if ((rbuf = malloc(sizeof(struct recvbuf))) == NULL)
3149c2daa00SOllivier Robert 		abortsim("ntprcv-malloc");
3159c2daa00SOllivier Robert 	memcpy(rbuf, &e.rcv_buf, sizeof(struct recvbuf));
3169c2daa00SOllivier Robert 	rbuf->receiver = receive;
3179c2daa00SOllivier Robert 	DTOLFP(n->ntp_time, &rbuf->recv_time);
3189c2daa00SOllivier Robert 	obuf = n->rbuflist;
3199c2daa00SOllivier Robert 
3209c2daa00SOllivier Robert 	/*
3219c2daa00SOllivier Robert 	 * In the present incarnation, no more than one buffer can be on
322ea906c41SOllivier Robert 	 * the queue;
3239c2daa00SOllivier Robert 	 */
3249c2daa00SOllivier Robert 	if (obuf == NULL) {
3259c2daa00SOllivier Robert 		n->rbuflist = rbuf;
3269c2daa00SOllivier Robert 	}
3279c2daa00SOllivier Robert }
3289c2daa00SOllivier Robert 
3299c2daa00SOllivier Robert 
3309c2daa00SOllivier Robert /*
3319c2daa00SOllivier Robert  * ndbeep() - progress indicator
3329c2daa00SOllivier Robert  */
3339c2daa00SOllivier Robert void
3349c2daa00SOllivier Robert ndbeep(
3359c2daa00SOllivier Robert 	Node *n,
3369c2daa00SOllivier Robert 	Event e
3379c2daa00SOllivier Robert 	)
3389c2daa00SOllivier Robert {
3399c2daa00SOllivier Robert 	static int first_time = 1;
3409c2daa00SOllivier Robert 	char *dash = "-----------------";
3419c2daa00SOllivier Robert 
3429c2daa00SOllivier Robert 	if(n->bdly > 0) {
3439c2daa00SOllivier Robert 		if (first_time) {
3449c2daa00SOllivier Robert 			printf(
3459c2daa00SOllivier Robert 			    "\t%4c    T    %4c\t%4c  T+ERR  %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' ');
3469c2daa00SOllivier Robert 			printf("\t%s\t%s\t%s\n", dash, dash, dash);
3479c2daa00SOllivier Robert 			first_time = 0;
3489c2daa00SOllivier Robert 			push(event(n->bdly, BEEP), &n->events);
3499c2daa00SOllivier Robert         		push(event(n->sim_time, BEEP), &n->events);
3509c2daa00SOllivier Robert 			printf("\t%16.6f\t%16.6f\t%16.6f\n",
3519c2daa00SOllivier Robert                             n->time, n->clk_time, n->ntp_time);
3529c2daa00SOllivier Robert 			return;
3539c2daa00SOllivier Robert 		}
3549c2daa00SOllivier Robert 		printf("\t%16.6f\t%16.6f\t%16.6f\n",
3559c2daa00SOllivier Robert 		    n->time, n->clk_time, n->ntp_time);
3569c2daa00SOllivier Robert 		push(event(e.time + n->bdly, BEEP), &n->events);
3579c2daa00SOllivier Robert 	}
3589c2daa00SOllivier Robert }
3599c2daa00SOllivier Robert 
3609c2daa00SOllivier Robert 
3619c2daa00SOllivier Robert /*
3629c2daa00SOllivier Robert  * Abort simulation
3639c2daa00SOllivier Robert  */
3649c2daa00SOllivier Robert void
3659c2daa00SOllivier Robert abortsim(
3669c2daa00SOllivier Robert 	char *errmsg
3679c2daa00SOllivier Robert 	)
3689c2daa00SOllivier Robert {
3699c2daa00SOllivier Robert         perror(errmsg);
3709c2daa00SOllivier Robert         exit(1);
3719c2daa00SOllivier Robert }
372