]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/ntpd/ntpsim.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / 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 #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 }