/contrib/ntp/ntpd/ntpsim.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 371 lines · 234 code · 47 blank · 90 comment · 20 complexity · efb116120dd40dca4dc65a79392c2225 MD5 · raw file

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