ntpsim.c revision 330141
1234949Sbapt/* ntpdsim.c
2234949Sbapt *
3268899Sbapt * The source code for the ntp discrete event simulator.
4234949Sbapt *
5272955Srodrigc * Written By:	Sachin Kamboj
6234949Sbapt *		University of Delaware
7251143Sbapt *		Newark, DE 19711
8251143Sbapt * Copyright (c) 2006
9251143Sbapt * (Some code shamelessly based on the original NTP discrete event simulator)
10234949Sbapt */
11234949Sbapt
12251143Sbapt#include <config.h>
13251143Sbapt#ifdef SIM
14251143Sbapt#include "ntpd.h"
15251143Sbapt#include "ntp_config.h"
16234949Sbapt
17234949Sbapt/* forward prototypes */
18251143Sbaptint determine_event_ordering(const Event *e1, const Event *e2);
19234949Sbaptint determine_recv_buf_ordering(const struct recvbuf *b1,
20234949Sbapt				const struct recvbuf *b2);
21234949Sbaptvoid create_server_associations(void);
22234949Sbaptvoid init_sim_io(void);
23251143Sbapt
24251143Sbapt/* Global Variable Definitions */
25251143Sbaptsim_info simulation;		/* Simulation Control Variables */
26234949Sbaptlocal_clock_info simclock;	/* Local Clock Variables */
27234949Sbaptqueue *event_queue;		/* Event Queue */
28251143Sbaptqueue *recv_queue;		/* Receive Queue */
29234949Sbaptstatic double sys_residual = 0;	/* adjustment residue (s) */
30234949Sbapt
31234949Sbaptvoid (*event_ptr[]) (Event *) = {
32234949Sbapt    sim_event_beep, sim_update_clocks, sim_event_timer, sim_event_recv_packet
33234949Sbapt};			/* Function pointer to the events */
34234949Sbapt
35234949Sbapt
36234949Sbapt/*
37234949Sbapt * Define a function to compare two events to determine which one occurs
38234949Sbapt * first.
39234949Sbapt */
40234949Sbaptint
41234949Sbaptdetermine_event_ordering(
42234949Sbapt	const Event *e1,
43234949Sbapt	const Event *e2
44234949Sbapt	)
45234949Sbapt{
46234949Sbapt	return (e1->time - e2->time);
47234949Sbapt}
48234949Sbapt
49234949Sbapt
50234949Sbapt/*
51234949Sbapt * Define a function to compare two received packets to determine which
52234949Sbapt * one is received first.
53234949Sbapt */
54234949Sbaptint
55234949Sbaptdetermine_recv_buf_ordering(
56234949Sbapt	const struct recvbuf *b1,
57234949Sbapt	const struct recvbuf *b2
58234949Sbapt	)
59234949Sbapt{
60234949Sbapt	double recv_time1;
61234949Sbapt	double recv_time2;
62234949Sbapt
63234949Sbapt	/* Simply convert the time received to double and subtract */
64234949Sbapt	LFPTOD(&b1->recv_time, recv_time1);
65234949Sbapt	LFPTOD(&b2->recv_time, recv_time2);
66234949Sbapt
67234949Sbapt	return (int)(recv_time1 - recv_time2);
68234949Sbapt}
69234949Sbapt
70234949Sbapt
71268899Sbapt/* Define a function to create the server associations */
72234949Sbaptvoid create_server_associations(void)
73234949Sbapt{
74234949Sbapt	int i;
75234949Sbapt
76234949Sbapt	for (i = 0; i < simulation.num_of_servers; ++i) {
77234949Sbapt		printf("%s\n", stoa(simulation.servers[i].addr));
78234949Sbapt		if (peer_config(simulation.servers[i].addr,
79234949Sbapt				NULL,
80234949Sbapt				loopback_interface,
81234949Sbapt				MODE_CLIENT,
82234949Sbapt				-1,
83234949Sbapt				NTP_VERSION,
84234949Sbapt				NTP_MINDPOLL,
85234949Sbapt				NTP_MAXDPOLL,
86234949Sbapt				0, /* peerflags */
87234949Sbapt				0, /* ttl */
88234949Sbapt				0, /* peerkey */
89234949Sbapt				NULL /* group ident */) == 0) {
90234949Sbapt			fprintf(stderr,
91234949Sbapt				"ERROR!! Could not create association for: %s\n",
92234949Sbapt				stoa(simulation.servers[i].addr));
93234949Sbapt		}
94234949Sbapt	}
95234949Sbapt}
96234949Sbapt
97234949Sbapt
98234949Sbapt/* Main Simulator Code */
99234949Sbapt
100234949Sbaptint
101234949Sbaptntpsim(
102234949Sbapt	int	argc,
103234949Sbapt	char *	argv[]
104234949Sbapt	)
105234949Sbapt{
106234949Sbapt	Event *		curr_event;
107234949Sbapt	struct timeval	seed;
108234949Sbapt
109234949Sbapt	/* Initialize the local Clock */
110234949Sbapt	simclock.local_time = 0;
111234949Sbapt	simclock.adj = 0;
112234949Sbapt	simclock.slew = 500e-6;
113234949Sbapt
114234949Sbapt	/* Initialize the simulation */
115234949Sbapt	simulation.num_of_servers = 0;
116234949Sbapt	simulation.beep_delay = BEEP_DLY;
117234949Sbapt	simulation.sim_time = 0;
118234949Sbapt	simulation.end_time = SIM_TIME;
119251143Sbapt
120234949Sbapt	/* Initialize ntp modules */
121234949Sbapt	initializing = TRUE;
122234949Sbapt	msyslog_term = TRUE;
123234949Sbapt	init_sim_io();
124234949Sbapt	init_auth();
125234949Sbapt	init_util();
126251143Sbapt	init_restrict();
127251143Sbapt	init_mon();
128251143Sbapt	init_timer();
129251143Sbapt	init_lib();
130234949Sbapt	init_request();
131234949Sbapt	init_control();
132234949Sbapt	init_peer();
133234949Sbapt	init_proto();
134234949Sbapt	init_loopfilter();
135234949Sbapt	mon_start(MON_OFF);
136234949Sbapt
137234949Sbapt	/* Call getconfig to parse the configuration file */
138234949Sbapt	getconfig(argc, argv);
139234949Sbapt	loop_config(LOOP_DRIFTINIT, 0);
140234949Sbapt	initializing = FALSE;
141234949Sbapt
142234949Sbapt	/*
143234949Sbapt	 * Watch out here, we want the real time, not the silly stuff.
144234949Sbapt	 */
145234949Sbapt	gettimeofday(&seed, NULL);
146234949Sbapt	ntp_srandom(seed.tv_usec);
147234949Sbapt
148234949Sbapt	/* Initialize the event queue */
149234949Sbapt	event_queue = create_priority_queue((q_order_func)
150234949Sbapt	    determine_event_ordering);
151234949Sbapt
152251143Sbapt	/* Initialize the receive queue */
153234949Sbapt	recv_queue = create_priority_queue((q_order_func)
154234949Sbapt	    determine_recv_buf_ordering);
155234949Sbapt
156234949Sbapt	/* Push a beep and a timer on the event queue */
157234949Sbapt	enqueue(event_queue, event(0, BEEP));
158234949Sbapt	enqueue(event_queue, event(simulation.sim_time + 1.0, TIMER));
159234949Sbapt
160234949Sbapt	/*
161234949Sbapt	 * Pop the queue until nothing is left or time is exceeded
162234949Sbapt	 */
163234949Sbapt	/* maxtime = simulation.sim_time + simulation.end_time;*/
164234949Sbapt	while (simulation.sim_time <= simulation.end_time &&
165234949Sbapt	   (!empty(event_queue))) {
166234949Sbapt		curr_event = dequeue(event_queue);
167234949Sbapt		/* Update all the clocks to the time on the event */
168234949Sbapt		sim_update_clocks(curr_event);
169234949Sbapt
170234949Sbapt		/* Execute the function associated with the event */
171234949Sbapt		(*event_ptr[curr_event->function])(curr_event);
172234949Sbapt		free_node(curr_event);
173234949Sbapt	}
174234949Sbapt	printf("sys_received: %lu\n", sys_received);
175234949Sbapt	printf("sys_badlength: %lu\n", sys_badlength);
176234949Sbapt	printf("sys_declined: %lu\n", sys_declined);
177234949Sbapt	printf("sys_restricted: %lu\n", sys_restricted);
178234949Sbapt	printf("sys_newversion: %lu\n", sys_newversion);
179234949Sbapt	printf("sys_oldversion: %lu\n", sys_oldversion);
180234949Sbapt	printf("sys_limitrejected: %lu\n", sys_limitrejected);
181234949Sbapt	printf("sys_badauth: %lu\n", sys_badauth);
182234949Sbapt
183234949Sbapt	return (0);
184234949Sbapt}
185234949Sbapt
186234949Sbapt
187234949Sbaptvoid
188234949Sbaptinit_sim_io(void)
189234949Sbapt{
190234949Sbapt	loopback_interface = emalloc_zero(sizeof(*loopback_interface));
191234949Sbapt	ep_list = loopback_interface;
192234949Sbapt	strlcpy(loopback_interface->name, "IPv4loop",
193234949Sbapt		sizeof(loopback_interface->name));
194234949Sbapt	loopback_interface->flags = INT_UP | INT_LOOPBACK;
195234949Sbapt	loopback_interface->fd = -1;
196234949Sbapt	loopback_interface->bfd = -1;
197234949Sbapt	loopback_interface->ifnum = 1;
198234949Sbapt	loopback_interface->family = AF_INET;
199234949Sbapt	AF(&loopback_interface->sin) = AF_INET;
200234949Sbapt	SET_ADDR4(&loopback_interface->sin, LOOPBACKADR);
201234949Sbapt	SET_PORT(&loopback_interface->sin, NTP_PORT);
202234949Sbapt	AF(&loopback_interface->mask) = AF_INET;
203234949Sbapt	SET_ADDR4(&loopback_interface->mask, LOOPNETMASK);
204234949Sbapt}
205234949Sbapt
206234949Sbapt
207234949Sbapt/* Define a function to create an return an Event  */
208234949Sbapt
209234949SbaptEvent *event(double t, funcTkn f)
210234949Sbapt{
211234949Sbapt    Event *e;
212234949Sbapt
213234949Sbapt    if ((e = get_node(sizeof(*e))) == NULL)
214234949Sbapt	abortsim("get_node failed in event");
215234949Sbapt    e->time = t;
216234949Sbapt    e->function = f;
217234949Sbapt    return (e);
218234949Sbapt}
219234949Sbapt
220234949Sbapt/* NTP SIMULATION FUNCTIONS */
221251143Sbapt
222251143Sbapt/* Define a function for processing a timer interrupt.
223251143Sbapt * On every timer interrupt, call the NTP timer to send packets and process
224251143Sbapt * the clock and then call the receive function to receive packets.
225251143Sbapt */
226251143Sbaptvoid sim_event_timer(Event *e)
227234949Sbapt{
228234949Sbapt    struct recvbuf *rbuf;
229234949Sbapt
230234949Sbapt    /* Call the NTP timer.
231234949Sbapt     * This will be responsible for actually "sending the packets."
232234949Sbapt     * Since this is a simulation, the packets sent over the network
233234949Sbapt     * will be processed by the simulate_server routine below.
234234949Sbapt     */
235234949Sbapt    timer();
236234949Sbapt
237234949Sbapt    /* Process received buffers */
238234949Sbapt    while (!empty(recv_queue)) {
239234949Sbapt	rbuf = (struct recvbuf *)dequeue(recv_queue);
240234949Sbapt	(*rbuf->receiver)(rbuf);
241234949Sbapt	free_node(rbuf);
242234949Sbapt    }
243234949Sbapt
244234949Sbapt    /* Arm the next timer interrupt. */
245234949Sbapt    enqueue(event_queue,
246234949Sbapt	    event(simulation.sim_time + (1 << EVENT_TIMEOUT), TIMER));
247234949Sbapt}
248234949Sbapt
249234949Sbapt
250234949Sbapt
251251143Sbapt/* Define a function to simulate a server.
252234949Sbapt * This function processes the sent packet according to the server script,
253234949Sbapt * creates a reply packet and pushes the reply packet onto the event queue
254234949Sbapt */
255268899Sbaptint simulate_server(
256251143Sbapt    sockaddr_u *serv_addr,	/* Address of the server */
257251143Sbapt    endpt *	inter,		/* Interface on which the reply should
258251143Sbapt				   be inserted */
259234949Sbapt    struct pkt *rpkt		/* Packet sent to the server that
260268899Sbapt				   needs to be processed. */
261234949Sbapt    )
262251143Sbapt{
263234949Sbapt    struct pkt xpkt;		/* Packet to be transmitted back
264234949Sbapt				   to the client */
265251143Sbapt    struct recvbuf rbuf;	/* Buffer for the received packet */
266234949Sbapt    Event *e;			/* Packet receive event */
267234949Sbapt    server_info *server;	/* Pointer to the server being simulated */
268268899Sbapt    script_info *curr_script;	/* Current script being processed */
269251143Sbapt    int i;
270234949Sbapt    double d1, d2, d3;		/* Delays while the packet is enroute */
271234949Sbapt    double t1, t2, t3, t4;	/* The four timestamps in the packet */
272251143Sbapt    l_fp lfp_host;		/* host-order l_fp */
273234949Sbapt
274234949Sbapt    ZERO(xpkt);
275234949Sbapt    ZERO(rbuf);
276234949Sbapt
277234949Sbapt    /* Search for the server with the desired address */
278234949Sbapt    server = NULL;
279234949Sbapt    for (i = 0; i < simulation.num_of_servers; ++i) {
280234949Sbapt	if (memcmp(simulation.servers[i].addr, serv_addr,
281234949Sbapt		   sizeof(*serv_addr)) == 0) {
282234949Sbapt	    server = &simulation.servers[i];
283234949Sbapt	    break;
284234949Sbapt	}
285234949Sbapt    }
286272955Srodrigc
287234949Sbapt    fprintf(stderr, "Received packet from %s on %s\n",
288234949Sbapt	    stoa(serv_addr), latoa(inter));
289272955Srodrigc    if (server == NULL)
290234949Sbapt	abortsim("Server with specified address not found!!!");
291234949Sbapt
292251143Sbapt    /* Get the current script for the server */
293234949Sbapt    curr_script = server->curr_script;
294234949Sbapt
295234949Sbapt    /* Create a server reply packet.
296234949Sbapt     * Masquerade the reply as a stratum-1 server with a GPS clock
297234949Sbapt     */
298234949Sbapt    xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
299251143Sbapt				     MODE_SERVER);
300234949Sbapt    xpkt.stratum = STRATUM_TO_PKT(((u_char)1));
301268899Sbapt    memcpy(&xpkt.refid, "GPS", 4);
302234949Sbapt    xpkt.ppoll = rpkt->ppoll;
303234949Sbapt    xpkt.precision = rpkt->precision;
304234949Sbapt    xpkt.rootdelay = 0;
305251143Sbapt    xpkt.rootdisp = 0;
306234949Sbapt
307234949Sbapt    /* TIMESTAMP CALCULATIONS
308234949Sbapt	    t1				 t4
309234949Sbapt	     \				/
310234949Sbapt	  d1  \			       / d3
311234949Sbapt	       \		      /
312234949Sbapt	       t2 ----------------- t3
313234949Sbapt			 d2
314251143Sbapt    */
315234949Sbapt    /* Compute the delays */
316234949Sbapt    d1 = poisson(curr_script->prop_delay, curr_script->jitter);
317234949Sbapt    d2 = poisson(curr_script->proc_delay, 0);
318234949Sbapt    d3 = poisson(curr_script->prop_delay, curr_script->jitter);
319234949Sbapt
320234949Sbapt    /* Note: In the transmitted packet:
321234949Sbapt     * 1. t1 and t4 are times in the client according to the local clock.
322234949Sbapt     * 2. t2 and t3 are server times according to the simulated server.
323234949Sbapt     * Compute t1, t2, t3 and t4
324234949Sbapt     * Note: This function is called at time t1.
325234949Sbapt     */
326234949Sbapt
327234949Sbapt    NTOHL_FP(&rpkt->xmt, &lfp_host);
328234949Sbapt    LFPTOD(&lfp_host, t1);
329268899Sbapt    t2 = server->server_time + d1;
330234949Sbapt    t3 = server->server_time + d1 + d2;
331234949Sbapt    t4 = t1 + d1 + d2 + d3;
332234949Sbapt
333234949Sbapt    /* Save the timestamps */
334234949Sbapt    xpkt.org = rpkt->xmt;
335234949Sbapt    DTOLFP(t2, &lfp_host);
336234949Sbapt    HTONL_FP(&lfp_host, &xpkt.rec);
337234949Sbapt    DTOLFP(t3, &lfp_host);
338251143Sbapt    HTONL_FP(&lfp_host, &xpkt.xmt);
339234949Sbapt    xpkt.reftime = xpkt.xmt;
340234949Sbapt
341234949Sbapt    /*
342251143Sbapt     * Ok, we are done with the packet. Now initialize the receive
343251143Sbapt     * buffer for the packet.
344251143Sbapt     */
345251143Sbapt    rbuf.used = 1;
346234949Sbapt    rbuf.receiver = &receive;   /* callback to process the packet */
347234949Sbapt    rbuf.recv_length = LEN_PKT_NOMAC;
348234949Sbapt    rbuf.recv_pkt = xpkt;
349251143Sbapt    rbuf.dstadr = inter;
350234949Sbapt    rbuf.fd = inter->fd;
351234949Sbapt    memcpy(&rbuf.srcadr, serv_addr, sizeof(rbuf.srcadr));
352234949Sbapt    memcpy(&rbuf.recv_srcadr, serv_addr, sizeof(rbuf.recv_srcadr));
353251143Sbapt
354234949Sbapt    /*
355234949Sbapt     * Create a packet event and insert it onto the event_queue at the
356234949Sbapt     * arrival time (t4) of the packet at the client
357234949Sbapt     */
358251143Sbapt    e = event(t4, PACKET);
359251143Sbapt    e->rcv_buf = rbuf;
360234949Sbapt    enqueue(event_queue, e);
361234949Sbapt
362234949Sbapt    /*
363234949Sbapt     * Check if the time of the script has expired. If yes, delete it.
364234949Sbapt     */
365234949Sbapt    if (curr_script->duration > simulation.sim_time &&
366234949Sbapt	NULL == HEAD_PFIFO(server->script)) {
367234949Sbapt	printf("Hello\n");
368251143Sbapt	/*
369234949Sbapt	 * For some reason freeing up the curr_script memory kills the
370234949Sbapt	 * simulation. Further debugging is needed to determine why.
371268899Sbapt	 * free(curr_script);
372234949Sbapt	 */
373234949Sbapt	UNLINK_FIFO(curr_script, *server->script, link);
374251143Sbapt    }
375234949Sbapt
376234949Sbapt    return (0);
377268899Sbapt}
378234949Sbapt
379234949Sbapt
380234949Sbapt/* Define a function to update all the clocks
381234949Sbapt * Most of the code is modified from the systime.c file by Prof. Mills
382234949Sbapt */
383251143Sbapt
384234949Sbaptvoid sim_update_clocks(Event *e)
385234949Sbapt{
386268899Sbapt    double time_gap;
387251143Sbapt    double adj;
388234949Sbapt    int i;
389234949Sbapt
390234949Sbapt    /* Compute the time between the last update event and this update */
391251143Sbapt    time_gap = e->time - simulation.sim_time;
392251143Sbapt
393234949Sbapt    if (time_gap < 0)
394234949Sbapt	    printf("WARNING: e->time %.6g comes before sim_time %.6g (gap %+.6g)\n",
395234949Sbapt		   e->time, simulation.sim_time, time_gap);
396234949Sbapt
397234949Sbapt    /* Advance the client clock */
398234949Sbapt    if (e->time + time_gap < simclock.local_time)
399234949Sbapt	    printf("WARNING: e->time + gap %.6g comes before local_time %.6g\n",
400234949Sbapt		   e->time + time_gap, simclock.local_time);
401234949Sbapt    simclock.local_time = e->time + time_gap;
402234949Sbapt
403234949Sbapt    /* Advance the simulation time */
404234949Sbapt    simulation.sim_time = e->time;
405234949Sbapt
406272955Srodrigc    /* Advance the server clocks adjusted for systematic and random frequency
407234949Sbapt     * errors. The random error is a random walk computed as the
408234949Sbapt     * integral of samples from a Gaussian distribution.
409272955Srodrigc     */
410234949Sbapt    for (i = 0; i < simulation.num_of_servers; ++i) {
411234949Sbapt	simulation.servers[i].curr_script->freq_offset +=
412251143Sbapt	    gauss(0, time_gap * simulation.servers[i].curr_script->wander);
413234949Sbapt
414234949Sbapt	simulation.servers[i].server_time += time_gap *
415234949Sbapt	    (1 + simulation.servers[i].curr_script->freq_offset);
416234949Sbapt    }
417234949Sbapt
418251143Sbapt    /* Perform the adjtime() function. If the adjustment completed
419234949Sbapt     * in the previous interval, amortize the entire amount; if not,
420234949Sbapt     * carry the leftover to the next interval.
421268899Sbapt     */
422234949Sbapt
423234949Sbapt    adj = time_gap * simclock.slew;
424234949Sbapt    if (adj < fabs(simclock.adj)) {
425234949Sbapt	if (simclock.adj < 0) {
426251143Sbapt	    simclock.adj += adj;
427234949Sbapt	    simclock.local_time -= adj;
428234949Sbapt	} else {
429234949Sbapt	    simclock.adj -= adj;
430234949Sbapt	    simclock.local_time += adj;
431234949Sbapt	}
432234949Sbapt    } else {
433234949Sbapt	simclock.local_time += simclock.adj;
434251143Sbapt	simclock.adj = 0;
435234949Sbapt    }
436234949Sbapt}
437251143Sbapt
438251143Sbapt
439234949Sbapt/* Define a function that processes a receive packet event.
440234949Sbapt * This function simply inserts the packet received onto the receive queue
441234949Sbapt */
442234949Sbapt
443234949Sbaptvoid sim_event_recv_packet(Event *e)
444234949Sbapt{
445234949Sbapt    struct recvbuf *rbuf;
446234949Sbapt
447234949Sbapt    /* Allocate a receive buffer and copy the packet to it */
448234949Sbapt    if ((rbuf = get_node(sizeof(*rbuf))) == NULL)
449234949Sbapt	abortsim("get_node failed in sim_event_recv_packet");
450234949Sbapt    memcpy(rbuf, &e->rcv_buf, sizeof(*rbuf));
451234949Sbapt
452234949Sbapt    /* Store the local time in the received packet */
453234949Sbapt    DTOLFP(simclock.local_time, &rbuf->recv_time);
454234949Sbapt
455234949Sbapt    /* Insert the packet received onto the receive queue */
456234949Sbapt    enqueue(recv_queue, rbuf);
457234949Sbapt}
458234949Sbapt
459234949Sbapt
460234949Sbapt
461234949Sbapt/* Define a function to output simulation statistics on a beep event
462234949Sbapt */
463234949Sbapt
464234949Sbapt/*** TODO: Need to decide on how to output for multiple servers ***/
465234949Sbaptvoid sim_event_beep(Event *e)
466234949Sbapt{
467234949Sbapt#if 0
468234949Sbapt    static int first_time = 1;
469234949Sbapt    char *dash = "-----------------";
470234949Sbapt#endif
471234949Sbapt
472234949Sbapt    fprintf(stderr, "BEEP!!!\n");
473234949Sbapt    enqueue(event_queue, event(e->time + simulation.beep_delay, BEEP));
474234949Sbapt#if 0
475234949Sbapt    if(simulation.beep_delay > 0) {
476234949Sbapt	if (first_time) {
477234949Sbapt	    printf("\t%4c    T    %4c\t%4c  T+ERR  %3c\t%5cT+ERR+NTP\n",
478234949Sbapt	           ' ', ' ', ' ', ' ',' ');
479234949Sbapt	    printf("\t%s\t%s\t%s\n", dash, dash, dash);
480234949Sbapt	    first_time = 0;
481234949Sbapt
482234949Sbapt	    printf("\t%16.6f\t%16.6f\t%16.6f\n",
483234949Sbapt	           n->time, n->clk_time, n->ntp_time);
484234949Sbapt	    return;
485234949Sbapt	}
486234949Sbapt	printf("\t%16.6f\t%16.6f\t%16.6f\n",
487234949Sbapt	       simclock.local_time,
488234949Sbapt	       n->time, n->clk_time, n->ntp_time);
489234949Sbapt#endif
490234949Sbapt
491234949Sbapt}
492234949Sbapt
493234949Sbapt
494234949Sbapt/* Define a function to abort the simulation on an error and spit out an
495234949Sbapt * error message
496234949Sbapt */
497234949Sbapt
498234949Sbaptvoid abortsim(char *errmsg)
499234949Sbapt{
500234949Sbapt    perror(errmsg);
501234949Sbapt    exit(1);
502234949Sbapt}
503234949Sbapt
504234949Sbapt
505234949Sbapt
506234949Sbapt/* CODE ORIGINALLY IN libntp/systime.c
507234949Sbapt * -----------------------------------
508234949Sbapt * This code was a part of the original NTP simulator and originally
509234949Sbapt * had its home in the libntp/systime.c file.
510234949Sbapt *
511234949Sbapt * It has been shamelessly moved to here and has been modified for the
512234949Sbapt * purposes of the current simulator.
513234949Sbapt */
514234949Sbapt
515234949Sbapt
516234949Sbapt/*
517234949Sbapt * get_systime - return the system time in NTP timestamp format
518234949Sbapt */
519234949Sbaptvoid
520234949Sbaptget_systime(
521234949Sbapt    l_fp *now		/* current system time in l_fp */        )
522234949Sbapt{
523234949Sbapt    /*
524234949Sbapt     * To fool the code that determines the local clock precision,
525234949Sbapt     * we advance the clock a minimum of 200 nanoseconds on every
526234949Sbapt     * clock read. This is appropriate for a typical modern machine
527234949Sbapt     * with nanosecond clocks. Note we make no attempt here to
528234949Sbapt     * simulate reading error, since the error is so small. This may
529234949Sbapt     * change when the need comes to implement picosecond clocks.
530234949Sbapt     */
531234949Sbapt    if (simclock.local_time == simclock.last_read_time)
532234949Sbapt        simclock.local_time += 200e-9;
533234949Sbapt
534234949Sbapt    simclock.last_read_time = simclock.local_time;
535234949Sbapt    DTOLFP(simclock.local_time, now);
536234949Sbapt/* OLD Code
537234949Sbapt   if (ntp_node.ntp_time == ntp_node.last_time)
538234949Sbapt   ntp_node.ntp_time += 200e-9;
539234949Sbapt   ntp_node.last_time = ntp_node.ntp_time;
540234949Sbapt   DTOLFP(ntp_node.ntp_time, now);
541234949Sbapt*/
542234949Sbapt}
543234949Sbapt
544234949Sbapt
545234949Sbapt/*
546234949Sbapt * adj_systime - advance or retard the system clock exactly like the
547234949Sbapt * real thng.
548234949Sbapt */
549234949Sbaptint				/* always succeeds */
550234949Sbaptadj_systime(
551234949Sbapt    double now		/* time adjustment (s) */
552234949Sbapt    )
553234949Sbapt{
554234949Sbapt    struct timeval adjtv;	/* new adjustment */
555234949Sbapt    double	dtemp;
556234949Sbapt    long	ticks;
557234949Sbapt    int	isneg = 0;
558234949Sbapt
559234949Sbapt    /*
560234949Sbapt     * Most Unix adjtime() implementations adjust the system clock
561234949Sbapt     * in microsecond quanta, but some adjust in 10-ms quanta. We
562234949Sbapt     * carefully round the adjustment to the nearest quantum, then
563234949Sbapt     * adjust in quanta and keep the residue for later.
564234949Sbapt     */
565234949Sbapt    dtemp = now + sys_residual;
566234949Sbapt    if (dtemp < 0) {
567234949Sbapt	isneg = 1;
568234949Sbapt	dtemp = -dtemp;
569234949Sbapt    }
570234949Sbapt    adjtv.tv_sec = (long)dtemp;
571234949Sbapt    dtemp -= adjtv.tv_sec;
572234949Sbapt    ticks = (long)(dtemp / sys_tick + .5);
573234949Sbapt    adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
574234949Sbapt    dtemp -= adjtv.tv_usec / 1e6;
575234949Sbapt    sys_residual = dtemp;
576234949Sbapt
577234949Sbapt    /*
578234949Sbapt     * Convert to signed seconds and microseconds for the Unix
579234949Sbapt     * adjtime() system call. Note we purposely lose the adjtime()
580234949Sbapt     * leftover.
581234949Sbapt     */
582234949Sbapt    if (isneg) {
583234949Sbapt	adjtv.tv_sec = -adjtv.tv_sec;
584234949Sbapt	adjtv.tv_usec = -adjtv.tv_usec;
585234949Sbapt	sys_residual = -sys_residual;
586234949Sbapt    }
587234949Sbapt    simclock.adj = now;
588234949Sbapt/*	ntp_node.adj = now; */
589234949Sbapt    return (1);
590234949Sbapt}
591234949Sbapt
592234949Sbapt
593234949Sbapt/*
594234949Sbapt * step_systime - step the system clock. We are religious here.
595234949Sbapt */
596234949Sbaptint				/* always succeeds */
597234949Sbaptstep_systime(
598234949Sbapt    double now		/* step adjustment (s) */
599234949Sbapt    )
600234949Sbapt{
601234949Sbapt#ifdef DEBUG
602234949Sbapt    if (debug)
603234949Sbapt	printf("step_systime: time %.6f adj %.6f\n",
604234949Sbapt	       simclock.local_time, now);
605234949Sbapt#endif
606234949Sbapt    simclock.local_time += now;
607234949Sbapt    return (1);
608234949Sbapt}
609234949Sbapt
610234949Sbapt/*
611234949Sbapt * gauss() - returns samples from a gaussion distribution
612234949Sbapt */
613234949Sbaptdouble				/* Gaussian sample */
614234949Sbaptgauss(
615234949Sbapt    double m,		/* sample mean */
616234949Sbapt    double s		/* sample standard deviation (sigma) */
617234949Sbapt    )
618234949Sbapt{
619234949Sbapt    double q1, q2;
620234949Sbapt
621234949Sbapt    /*
622234949Sbapt     * Roll a sample from a Gaussian distribution with mean m and
623234949Sbapt     * standard deviation s. For m = 0, s = 1, mean(y) = 0,
624234949Sbapt     * std(y) = 1.
625234949Sbapt     */
626234949Sbapt    if (s == 0)
627234949Sbapt        return (m);
628234949Sbapt    while ((q1 = drand48()) == 0)
629234949Sbapt	/* empty statement */;
630234949Sbapt    q2 = drand48();
631234949Sbapt    return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2));
632234949Sbapt}
633234949Sbapt
634234949Sbapt
635234949Sbapt/*
636234949Sbapt * poisson() - returns samples from a network delay distribution
637234949Sbapt */
638234949Sbaptdouble				/* delay sample (s) */
639234949Sbaptpoisson(
640234949Sbapt    double m,		/* fixed propagation delay (s) */
641234949Sbapt    double s		/* exponential parameter (mu) */
642234949Sbapt    )
643234949Sbapt{
644234949Sbapt    double q1;
645234949Sbapt
646234949Sbapt    /*
647234949Sbapt     * Roll a sample from a composite distribution with propagation
648234949Sbapt     * delay m and exponential distribution time with parameter s.
649234949Sbapt     * For m = 0, s = 1, mean(y) = std(y) = 1.
650234949Sbapt     */
651234949Sbapt    if (s == 0)
652234949Sbapt        return (m);
653234949Sbapt    while ((q1 = drand48()) == 0)
654234949Sbapt	/* empty statement */;
655234949Sbapt    return (m - s * log(q1 * s));
656234949Sbapt}
657234949Sbapt
658234949Sbapt#endif
659234949Sbapt