]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - ntpd/ntpsim.c
Flatten the dist and various 4.n.n trees in preparation of future ntp imports.
[FreeBSD/FreeBSD.git] / ntpd / ntpsim.c
1 /*
2  * NTP simulator engine - Harish Nair
3  * University of Delaware, 2001
4  */
5 #include "ntpd.h"
6 #include "ntpsim.h"
7
8 /*
9  * Defines...
10  */
11 #define SIM_TIME 86400          /* end simulation time */
12 #define NET_DLY .001            /* network delay */
13 #define PROC_DLY .001           /* processing delay */
14 #define BEEP_DLY 3600           /* beep interval (s) */
15 #define SLEW    500e-6          /* correction rate (PPM) */
16
17 /*
18  * Function pointers
19  */
20 void (*funcPtr[]) (Node *, Event) = {
21         &ndbeep, &ndeclk, &ntptmr, &netpkt
22 };
23
24
25 /*
26  * ntpsim - initialize global variables and event queue and start
27  */
28 int
29 ntpsim(
30         int     argc,
31         char    *argv[]
32         )
33 {
34         Event   e;
35         double  maxtime;
36         struct timeval seed;
37
38         /*
39          * Initialize the global node
40          */
41         ntp_node.time = 0;              /* simulation time */
42         ntp_node.sim_time = SIM_TIME;   /* end simulation time (-S) */
43         ntp_node.ntp_time = 0;          /* client disciplined time */
44         ntp_node.adj = 0;               /* remaining time correction */
45         ntp_node.slew = SLEW;           /* correction rate (-H) */
46
47         ntp_node.clk_time = 0;          /* server time (-O) */
48         ntp_node.ferr = 0;              /* frequency error (-T) */
49         ntp_node.fnse = 0;              /* random walk noise (-W) */
50         ntp_node.ndly = NET_DLY;        /* network delay (-Y) */
51         ntp_node.snse = 0;              /* phase noise (-C) */
52         ntp_node.pdly = PROC_DLY;       /* processing delay (-Z) */
53         ntp_node.bdly = BEEP_DLY;       /* beep interval (-B) */
54
55         ntp_node.events = NULL;
56         ntp_node.rbuflist = NULL;
57
58         /*
59          * Initialize ntp variables
60          */
61         initializing = 1;
62         init_auth();
63         init_util();
64         init_restrict();
65         init_mon();
66         init_timer();
67         init_lib();
68         init_random();
69         init_request();
70         init_control();
71         init_peer();
72         init_proto();
73         init_io();
74         init_loopfilter();
75         mon_start(MON_OFF);
76         getconfig(argc, argv);
77         initializing = 0;
78
79         /*
80          * Watch out here, we want the real time, not the silly stuff.
81          */
82         gettimeofday(&seed, NULL);
83         srand48(seed.tv_usec);
84
85         /*
86          * Push a beep and timer interrupt on the queue
87          */
88         push(event(0, BEEP), &ntp_node.events);
89         push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events);
90
91         /*
92          * Pop the queue until nothing is left or time is exceeded
93          */
94         maxtime = ntp_node.time + ntp_node.sim_time;
95         while (ntp_node.time <= maxtime && ntp_node.events != NULL ) {
96                 e = pop(&ntp_node.events);
97                 ndeclk(&ntp_node, e);
98                 funcPtr[e.function](&ntp_node, e);
99         }
100         return (0);
101 }
102
103
104 /*
105  * Return an event
106  */
107 Event
108 event(
109         double t,
110         funcTkn f
111         )
112 {
113         Event e;
114
115         e.time = t;
116         e.function = f;
117         return (e);
118 }
119
120 /*
121  * Create an event queue
122  */
123 Queue
124 queue(
125         Event e,
126         Queue q
127         )
128 {
129         Queue ret;
130
131         if ((ret = (Queue)malloc(sizeof(struct List))) == NULL)
132                 abortsim("queue-malloc");
133         ret->event = e;
134         ret->next = q;
135         return (ret);
136 }
137
138
139 /*
140  * Push an event into the event queue
141  */
142 void push(
143         Event e,
144         Queue *qp
145         )
146 {
147         Queue *tmp = qp;
148
149         while (*tmp != NULL && ((*tmp)->event.time < e.time))
150                 tmp = &((*tmp)->next);
151         *tmp = queue(e, (*tmp));
152 }
153
154
155 /*
156  * Pop the first event from the event queue
157  */
158 Event
159 pop(
160         Queue *qp
161         )
162 {
163         Event ret;
164         Queue tmp;
165
166         tmp = *qp;
167         if (tmp == NULL)
168             abortsim("pop - empty queue");
169         ret = tmp->event;
170         *qp = tmp->next;
171         free(tmp);
172         return (ret);
173 }
174
175
176 /*
177  * Update clocks
178  */
179 void
180 ndeclk(
181         Node *n,
182         Event e
183         )
184 {
185         node_clock(n, e.time);
186 }
187
188
189 /*
190  * Timer interrupt. Eventually, this results in calling the
191  * srvr_rplyi() routine below.
192  */
193 void
194 ntptmr(
195         Node *n,
196         Event e
197         )
198 {
199         struct recvbuf *rbuf;
200
201         timer();
202
203         /*
204          * Process buffers received. They had better be in order by
205          * receive timestamp.
206          */
207         while (n->rbuflist != NULL) {
208                 rbuf = n->rbuflist;
209                 n->rbuflist = rbuf->next;
210                 (rbuf->receiver)(rbuf);
211                 free(rbuf);
212         }
213
214         /*
215          * Arm the next timer interrupt.
216          */
217         push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events);
218 }
219
220
221 /*
222  * srvr_rply() - send packet
223  */
224 int srvr_rply(
225         Node *n,
226         struct sockaddr_storage *dest,
227         struct interface *inter, struct pkt *rpkt
228         )
229 {
230         struct pkt xpkt;
231         struct recvbuf rbuf;
232         Event   xvnt;
233         double  dtemp, etemp;
234
235         /*
236          * Insert packet header values. We make this look like a
237          * stratum-1 server with a GPS clock, but nobody will ever
238          * notice that.
239          */
240         xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
241             MODE_SERVER);
242         xpkt.stratum = STRATUM_TO_PKT(((u_char)1));
243         memcpy(&xpkt.refid, "GPS", 4);
244         xpkt.ppoll = rpkt->ppoll;
245         xpkt.precision = rpkt->precision;
246         xpkt.rootdelay = 0;
247         xpkt.rootdispersion = 0;
248
249         /*
250          * Insert the timestamps.
251          */
252         xpkt.org = rpkt->xmt;
253         dtemp = poisson(n->ndly, n->snse); /* client->server delay */
254         DTOLFP(dtemp + n->clk_time, &xpkt.rec);
255         dtemp += poisson(n->pdly, 0);   /* server delay */
256         DTOLFP(dtemp + n->clk_time, &xpkt.xmt);
257         xpkt.reftime = xpkt.xmt;
258         dtemp += poisson(n->ndly, n->snse); /* server->client delay */
259
260         /*
261          * Insert the I/O stuff.
262          */
263         rbuf.receiver = receive;
264         get_systime(&rbuf.recv_time);
265         rbuf.recv_length = LEN_PKT_NOMAC;
266         rbuf.recv_pkt = xpkt;
267         memcpy(&rbuf.srcadr, dest, sizeof(struct sockaddr_storage));
268         memcpy(&rbuf.recv_srcadr, dest,
269             sizeof(struct sockaddr_storage));
270         if ((rbuf.dstadr = malloc(sizeof(struct interface))) == NULL)
271                 abortsim("server-malloc");
272         memcpy(rbuf.dstadr, inter, sizeof(struct interface));
273         rbuf.next = NULL;
274
275         /*
276          * Very carefully predict the time of arrival for the received
277          * packet. 
278          */ 
279         LFPTOD(&xpkt.org, etemp);
280         etemp += dtemp;
281         xvnt = event(etemp, PACKET);
282         xvnt.rcv_buf = rbuf;
283         push(xvnt, &n->events);
284         return (0);
285 }
286
287
288 /*
289  * netpkt() - receive packet
290  */
291 void
292 netpkt(
293         Node *n,
294         Event e
295         )
296 {
297         struct recvbuf *rbuf;
298         struct recvbuf *obuf;
299
300         /*
301          * Insert the packet on the receive queue and record the arrival
302          * time.
303          */
304         if ((rbuf = malloc(sizeof(struct recvbuf))) == NULL)
305                 abortsim("ntprcv-malloc");
306         memcpy(rbuf, &e.rcv_buf, sizeof(struct recvbuf));
307         rbuf->receiver = receive;
308         DTOLFP(n->ntp_time, &rbuf->recv_time);
309         rbuf->next = NULL;
310         obuf = n->rbuflist;
311
312         /*
313          * In the present incarnation, no more than one buffer can be on
314          * the queue; however, we sniff the queue anyway as a hint for
315          * further development.
316          */
317         if (obuf == NULL) {
318                 n->rbuflist = rbuf;
319         } else {
320                 while (obuf->next != NULL)
321                         obuf = obuf->next;
322                 obuf->next = rbuf;
323         }
324 }
325
326
327 /*
328  * ndbeep() - progress indicator
329  */
330 void
331 ndbeep(
332         Node *n,
333         Event e
334         )
335 {
336         static int first_time = 1;
337         char *dash = "-----------------";
338
339         if(n->bdly > 0) {
340                 if (first_time) {
341                         printf(
342                             "\t%4c    T    %4c\t%4c  T+ERR  %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' ');
343                         printf("\t%s\t%s\t%s\n", dash, dash, dash);
344                         first_time = 0;
345                         push(event(n->bdly, BEEP), &n->events);  
346                         push(event(n->sim_time, BEEP), &n->events);
347                         printf("\t%16.6f\t%16.6f\t%16.6f\n",
348                             n->time, n->clk_time, n->ntp_time);
349                         return;
350                 }
351                 printf("\t%16.6f\t%16.6f\t%16.6f\n",
352                     n->time, n->clk_time, n->ntp_time);
353                 push(event(e.time + n->bdly, BEEP), &n->events);
354         }
355 }
356
357
358 /*
359  * Abort simulation
360  */
361 void
362 abortsim(
363         char *errmsg
364         )
365 {
366         perror(errmsg);
367         exit(1);
368 }