1285612Sdelphij/* ntpdsim.c 2285612Sdelphij * 3285612Sdelphij * The source code for the ntp discrete event simulator. 4285612Sdelphij * 5285612Sdelphij * Written By: Sachin Kamboj 6285612Sdelphij * University of Delaware 7285612Sdelphij * Newark, DE 19711 8285612Sdelphij * Copyright (c) 2006 9285612Sdelphij * (Some code shamelessly based on the original NTP discrete event simulator) 10132451Sroberto */ 11285612Sdelphij 12285612Sdelphij#include <config.h> 13285612Sdelphij#ifdef SIM 14132451Sroberto#include "ntpd.h" 15285612Sdelphij#include "ntp_config.h" 16132451Sroberto 17285612Sdelphij/* forward prototypes */ 18285612Sdelphijint determine_event_ordering(const Event *e1, const Event *e2); 19285612Sdelphijint determine_recv_buf_ordering(const struct recvbuf *b1, 20285612Sdelphij const struct recvbuf *b2); 21285612Sdelphijvoid create_server_associations(void); 22285612Sdelphijvoid init_sim_io(void); 23132451Sroberto 24285612Sdelphij/* Global Variable Definitions */ 25285612Sdelphijsim_info simulation; /* Simulation Control Variables */ 26285612Sdelphijlocal_clock_info simclock; /* Local Clock Variables */ 27285612Sdelphijqueue *event_queue; /* Event Queue */ 28285612Sdelphijqueue *recv_queue; /* Receive Queue */ 29285612Sdelphijstatic double sys_residual = 0; /* adjustment residue (s) */ 30285612Sdelphij 31285612Sdelphijvoid (*event_ptr[]) (Event *) = { 32285612Sdelphij sim_event_beep, sim_update_clocks, sim_event_timer, sim_event_recv_packet 33285612Sdelphij}; /* Function pointer to the events */ 34285612Sdelphij 35285612Sdelphij 36132451Sroberto/* 37285612Sdelphij * Define a function to compare two events to determine which one occurs 38285612Sdelphij * first. 39132451Sroberto */ 40285612Sdelphijint 41285612Sdelphijdetermine_event_ordering( 42285612Sdelphij const Event *e1, 43285612Sdelphij const Event *e2 44285612Sdelphij ) 45285612Sdelphij{ 46285612Sdelphij return (e1->time - e2->time); 47285612Sdelphij} 48132451Sroberto 49132451Sroberto 50132451Sroberto/* 51285612Sdelphij * Define a function to compare two received packets to determine which 52285612Sdelphij * one is received first. 53132451Sroberto */ 54132451Srobertoint 55285612Sdelphijdetermine_recv_buf_ordering( 56285612Sdelphij const struct recvbuf *b1, 57285612Sdelphij const struct recvbuf *b2 58132451Sroberto ) 59132451Sroberto{ 60285612Sdelphij double recv_time1; 61285612Sdelphij double recv_time2; 62132451Sroberto 63285612Sdelphij /* Simply convert the time received to double and subtract */ 64285612Sdelphij LFPTOD(&b1->recv_time, recv_time1); 65285612Sdelphij LFPTOD(&b2->recv_time, recv_time2); 66132451Sroberto 67285612Sdelphij return (int)(recv_time1 - recv_time2); 68285612Sdelphij} 69132451Sroberto 70132451Sroberto 71285612Sdelphij/* Define a function to create the server associations */ 72285612Sdelphijvoid create_server_associations(void) 73285612Sdelphij{ 74285612Sdelphij int i; 75182007Sroberto 76285612Sdelphij for (i = 0; i < simulation.num_of_servers; ++i) { 77285612Sdelphij printf("%s\n", stoa(simulation.servers[i].addr)); 78285612Sdelphij if (peer_config(simulation.servers[i].addr, 79285612Sdelphij NULL, 80285612Sdelphij loopback_interface, 81285612Sdelphij MODE_CLIENT, 82330141Sdelphij -1, 83285612Sdelphij NTP_VERSION, 84285612Sdelphij NTP_MINDPOLL, 85285612Sdelphij NTP_MAXDPOLL, 86285612Sdelphij 0, /* peerflags */ 87285612Sdelphij 0, /* ttl */ 88285612Sdelphij 0, /* peerkey */ 89285612Sdelphij NULL /* group ident */) == 0) { 90285612Sdelphij fprintf(stderr, 91285612Sdelphij "ERROR!! Could not create association for: %s\n", 92285612Sdelphij stoa(simulation.servers[i].addr)); 93285612Sdelphij } 94182007Sroberto } 95285612Sdelphij} 96182007Sroberto 97285612Sdelphij 98285612Sdelphij/* Main Simulator Code */ 99285612Sdelphij 100285612Sdelphijint 101285612Sdelphijntpsim( 102285612Sdelphij int argc, 103285612Sdelphij char * argv[] 104285612Sdelphij ) 105285612Sdelphij{ 106285612Sdelphij Event * curr_event; 107285612Sdelphij struct timeval seed; 108285612Sdelphij 109285612Sdelphij /* Initialize the local Clock */ 110285612Sdelphij simclock.local_time = 0; 111285612Sdelphij simclock.adj = 0; 112285612Sdelphij simclock.slew = 500e-6; 113285612Sdelphij 114285612Sdelphij /* Initialize the simulation */ 115285612Sdelphij simulation.num_of_servers = 0; 116285612Sdelphij simulation.beep_delay = BEEP_DLY; 117285612Sdelphij simulation.sim_time = 0; 118285612Sdelphij simulation.end_time = SIM_TIME; 119285612Sdelphij 120285612Sdelphij /* Initialize ntp modules */ 121285612Sdelphij initializing = TRUE; 122285612Sdelphij msyslog_term = TRUE; 123285612Sdelphij init_sim_io(); 124285612Sdelphij init_auth(); 125285612Sdelphij init_util(); 126285612Sdelphij init_restrict(); 127285612Sdelphij init_mon(); 128285612Sdelphij init_timer(); 129285612Sdelphij init_lib(); 130285612Sdelphij init_request(); 131285612Sdelphij init_control(); 132285612Sdelphij init_peer(); 133285612Sdelphij init_proto(); 134285612Sdelphij init_loopfilter(); 135285612Sdelphij mon_start(MON_OFF); 136285612Sdelphij 137285612Sdelphij /* Call getconfig to parse the configuration file */ 138132451Sroberto getconfig(argc, argv); 139285612Sdelphij loop_config(LOOP_DRIFTINIT, 0); 140285612Sdelphij initializing = FALSE; 141182007Sroberto 142132451Sroberto /* 143132451Sroberto * Watch out here, we want the real time, not the silly stuff. 144132451Sroberto */ 145132451Sroberto gettimeofday(&seed, NULL); 146182007Sroberto ntp_srandom(seed.tv_usec); 147132451Sroberto 148285612Sdelphij /* Initialize the event queue */ 149285612Sdelphij event_queue = create_priority_queue((q_order_func) 150285612Sdelphij determine_event_ordering); 151132451Sroberto 152285612Sdelphij /* Initialize the receive queue */ 153285612Sdelphij recv_queue = create_priority_queue((q_order_func) 154285612Sdelphij determine_recv_buf_ordering); 155285612Sdelphij 156285612Sdelphij /* Push a beep and a timer on the event queue */ 157285612Sdelphij enqueue(event_queue, event(0, BEEP)); 158285612Sdelphij enqueue(event_queue, event(simulation.sim_time + 1.0, TIMER)); 159285612Sdelphij 160285612Sdelphij /* 161132451Sroberto * Pop the queue until nothing is left or time is exceeded 162132451Sroberto */ 163285612Sdelphij /* maxtime = simulation.sim_time + simulation.end_time;*/ 164285612Sdelphij while (simulation.sim_time <= simulation.end_time && 165285612Sdelphij (!empty(event_queue))) { 166285612Sdelphij curr_event = dequeue(event_queue); 167285612Sdelphij /* Update all the clocks to the time on the event */ 168285612Sdelphij sim_update_clocks(curr_event); 169285612Sdelphij 170285612Sdelphij /* Execute the function associated with the event */ 171285612Sdelphij (*event_ptr[curr_event->function])(curr_event); 172285612Sdelphij free_node(curr_event); 173132451Sroberto } 174285612Sdelphij printf("sys_received: %lu\n", sys_received); 175285612Sdelphij printf("sys_badlength: %lu\n", sys_badlength); 176285612Sdelphij printf("sys_declined: %lu\n", sys_declined); 177285612Sdelphij printf("sys_restricted: %lu\n", sys_restricted); 178285612Sdelphij printf("sys_newversion: %lu\n", sys_newversion); 179285612Sdelphij printf("sys_oldversion: %lu\n", sys_oldversion); 180285612Sdelphij printf("sys_limitrejected: %lu\n", sys_limitrejected); 181285612Sdelphij printf("sys_badauth: %lu\n", sys_badauth); 182285612Sdelphij 183132451Sroberto return (0); 184132451Sroberto} 185132451Sroberto 186132451Sroberto 187285612Sdelphijvoid 188285612Sdelphijinit_sim_io(void) 189132451Sroberto{ 190285612Sdelphij loopback_interface = emalloc_zero(sizeof(*loopback_interface)); 191285612Sdelphij ep_list = loopback_interface; 192285612Sdelphij strlcpy(loopback_interface->name, "IPv4loop", 193285612Sdelphij sizeof(loopback_interface->name)); 194285612Sdelphij loopback_interface->flags = INT_UP | INT_LOOPBACK; 195285612Sdelphij loopback_interface->fd = -1; 196285612Sdelphij loopback_interface->bfd = -1; 197285612Sdelphij loopback_interface->ifnum = 1; 198285612Sdelphij loopback_interface->family = AF_INET; 199285612Sdelphij AF(&loopback_interface->sin) = AF_INET; 200285612Sdelphij SET_ADDR4(&loopback_interface->sin, LOOPBACKADR); 201285612Sdelphij SET_PORT(&loopback_interface->sin, NTP_PORT); 202285612Sdelphij AF(&loopback_interface->mask) = AF_INET; 203285612Sdelphij SET_ADDR4(&loopback_interface->mask, LOOPNETMASK); 204285612Sdelphij} 205132451Sroberto 206285612Sdelphij 207285612Sdelphij/* Define a function to create an return an Event */ 208285612Sdelphij 209285612SdelphijEvent *event(double t, funcTkn f) 210285612Sdelphij{ 211285612Sdelphij Event *e; 212285612Sdelphij 213285612Sdelphij if ((e = get_node(sizeof(*e))) == NULL) 214285612Sdelphij abortsim("get_node failed in event"); 215285612Sdelphij e->time = t; 216285612Sdelphij e->function = f; 217285612Sdelphij return (e); 218132451Sroberto} 219132451Sroberto 220285612Sdelphij/* NTP SIMULATION FUNCTIONS */ 221285612Sdelphij 222285612Sdelphij/* Define a function for processing a timer interrupt. 223285612Sdelphij * On every timer interrupt, call the NTP timer to send packets and process 224285612Sdelphij * the clock and then call the receive function to receive packets. 225132451Sroberto */ 226285612Sdelphijvoid sim_event_timer(Event *e) 227132451Sroberto{ 228285612Sdelphij struct recvbuf *rbuf; 229132451Sroberto 230285612Sdelphij /* Call the NTP timer. 231285612Sdelphij * This will be responsible for actually "sending the packets." 232285612Sdelphij * Since this is a simulation, the packets sent over the network 233285612Sdelphij * will be processed by the simulate_server routine below. 234285612Sdelphij */ 235285612Sdelphij timer(); 236285612Sdelphij 237285612Sdelphij /* Process received buffers */ 238285612Sdelphij while (!empty(recv_queue)) { 239285612Sdelphij rbuf = (struct recvbuf *)dequeue(recv_queue); 240285612Sdelphij (*rbuf->receiver)(rbuf); 241285612Sdelphij free_node(rbuf); 242285612Sdelphij } 243285612Sdelphij 244285612Sdelphij /* Arm the next timer interrupt. */ 245285612Sdelphij enqueue(event_queue, 246285612Sdelphij event(simulation.sim_time + (1 << EVENT_TIMEOUT), TIMER)); 247132451Sroberto} 248132451Sroberto 249132451Sroberto 250285612Sdelphij 251285612Sdelphij/* Define a function to simulate a server. 252285612Sdelphij * This function processes the sent packet according to the server script, 253285612Sdelphij * creates a reply packet and pushes the reply packet onto the event queue 254132451Sroberto */ 255285612Sdelphijint simulate_server( 256285612Sdelphij sockaddr_u *serv_addr, /* Address of the server */ 257285612Sdelphij endpt * inter, /* Interface on which the reply should 258285612Sdelphij be inserted */ 259285612Sdelphij struct pkt *rpkt /* Packet sent to the server that 260285612Sdelphij needs to be processed. */ 261285612Sdelphij ) 262132451Sroberto{ 263285612Sdelphij struct pkt xpkt; /* Packet to be transmitted back 264285612Sdelphij to the client */ 265285612Sdelphij struct recvbuf rbuf; /* Buffer for the received packet */ 266285612Sdelphij Event *e; /* Packet receive event */ 267285612Sdelphij server_info *server; /* Pointer to the server being simulated */ 268285612Sdelphij script_info *curr_script; /* Current script being processed */ 269285612Sdelphij int i; 270285612Sdelphij double d1, d2, d3; /* Delays while the packet is enroute */ 271285612Sdelphij double t1, t2, t3, t4; /* The four timestamps in the packet */ 272285612Sdelphij l_fp lfp_host; /* host-order l_fp */ 273132451Sroberto 274285612Sdelphij ZERO(xpkt); 275285612Sdelphij ZERO(rbuf); 276285612Sdelphij 277285612Sdelphij /* Search for the server with the desired address */ 278285612Sdelphij server = NULL; 279285612Sdelphij for (i = 0; i < simulation.num_of_servers; ++i) { 280285612Sdelphij if (memcmp(simulation.servers[i].addr, serv_addr, 281285612Sdelphij sizeof(*serv_addr)) == 0) { 282285612Sdelphij server = &simulation.servers[i]; 283285612Sdelphij break; 284285612Sdelphij } 285285612Sdelphij } 286285612Sdelphij 287285612Sdelphij fprintf(stderr, "Received packet from %s on %s\n", 288285612Sdelphij stoa(serv_addr), latoa(inter)); 289285612Sdelphij if (server == NULL) 290285612Sdelphij abortsim("Server with specified address not found!!!"); 291285612Sdelphij 292285612Sdelphij /* Get the current script for the server */ 293285612Sdelphij curr_script = server->curr_script; 294285612Sdelphij 295285612Sdelphij /* Create a server reply packet. 296285612Sdelphij * Masquerade the reply as a stratum-1 server with a GPS clock 297285612Sdelphij */ 298285612Sdelphij xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, 299285612Sdelphij MODE_SERVER); 300285612Sdelphij xpkt.stratum = STRATUM_TO_PKT(((u_char)1)); 301285612Sdelphij memcpy(&xpkt.refid, "GPS", 4); 302285612Sdelphij xpkt.ppoll = rpkt->ppoll; 303285612Sdelphij xpkt.precision = rpkt->precision; 304285612Sdelphij xpkt.rootdelay = 0; 305285612Sdelphij xpkt.rootdisp = 0; 306285612Sdelphij 307285612Sdelphij /* TIMESTAMP CALCULATIONS 308285612Sdelphij t1 t4 309285612Sdelphij \ / 310285612Sdelphij d1 \ / d3 311285612Sdelphij \ / 312285612Sdelphij t2 ----------------- t3 313285612Sdelphij d2 314285612Sdelphij */ 315285612Sdelphij /* Compute the delays */ 316285612Sdelphij d1 = poisson(curr_script->prop_delay, curr_script->jitter); 317285612Sdelphij d2 = poisson(curr_script->proc_delay, 0); 318285612Sdelphij d3 = poisson(curr_script->prop_delay, curr_script->jitter); 319285612Sdelphij 320285612Sdelphij /* Note: In the transmitted packet: 321285612Sdelphij * 1. t1 and t4 are times in the client according to the local clock. 322285612Sdelphij * 2. t2 and t3 are server times according to the simulated server. 323285612Sdelphij * Compute t1, t2, t3 and t4 324285612Sdelphij * Note: This function is called at time t1. 325285612Sdelphij */ 326285612Sdelphij 327285612Sdelphij NTOHL_FP(&rpkt->xmt, &lfp_host); 328285612Sdelphij LFPTOD(&lfp_host, t1); 329285612Sdelphij t2 = server->server_time + d1; 330285612Sdelphij t3 = server->server_time + d1 + d2; 331285612Sdelphij t4 = t1 + d1 + d2 + d3; 332285612Sdelphij 333285612Sdelphij /* Save the timestamps */ 334285612Sdelphij xpkt.org = rpkt->xmt; 335285612Sdelphij DTOLFP(t2, &lfp_host); 336285612Sdelphij HTONL_FP(&lfp_host, &xpkt.rec); 337285612Sdelphij DTOLFP(t3, &lfp_host); 338285612Sdelphij HTONL_FP(&lfp_host, &xpkt.xmt); 339285612Sdelphij xpkt.reftime = xpkt.xmt; 340285612Sdelphij 341285612Sdelphij /* 342285612Sdelphij * Ok, we are done with the packet. Now initialize the receive 343285612Sdelphij * buffer for the packet. 344285612Sdelphij */ 345285612Sdelphij rbuf.used = 1; 346285612Sdelphij rbuf.receiver = &receive; /* callback to process the packet */ 347285612Sdelphij rbuf.recv_length = LEN_PKT_NOMAC; 348285612Sdelphij rbuf.recv_pkt = xpkt; 349285612Sdelphij rbuf.dstadr = inter; 350285612Sdelphij rbuf.fd = inter->fd; 351285612Sdelphij memcpy(&rbuf.srcadr, serv_addr, sizeof(rbuf.srcadr)); 352285612Sdelphij memcpy(&rbuf.recv_srcadr, serv_addr, sizeof(rbuf.recv_srcadr)); 353285612Sdelphij 354285612Sdelphij /* 355285612Sdelphij * Create a packet event and insert it onto the event_queue at the 356285612Sdelphij * arrival time (t4) of the packet at the client 357285612Sdelphij */ 358285612Sdelphij e = event(t4, PACKET); 359285612Sdelphij e->rcv_buf = rbuf; 360285612Sdelphij enqueue(event_queue, e); 361285612Sdelphij 362285612Sdelphij /* 363285612Sdelphij * Check if the time of the script has expired. If yes, delete it. 364285612Sdelphij */ 365285612Sdelphij if (curr_script->duration > simulation.sim_time && 366285612Sdelphij NULL == HEAD_PFIFO(server->script)) { 367285612Sdelphij printf("Hello\n"); 368285612Sdelphij /* 369285612Sdelphij * For some reason freeing up the curr_script memory kills the 370285612Sdelphij * simulation. Further debugging is needed to determine why. 371285612Sdelphij * free(curr_script); 372285612Sdelphij */ 373285612Sdelphij UNLINK_FIFO(curr_script, *server->script, link); 374285612Sdelphij } 375285612Sdelphij 376285612Sdelphij return (0); 377132451Sroberto} 378132451Sroberto 379132451Sroberto 380285612Sdelphij/* Define a function to update all the clocks 381285612Sdelphij * Most of the code is modified from the systime.c file by Prof. Mills 382132451Sroberto */ 383285612Sdelphij 384285612Sdelphijvoid sim_update_clocks(Event *e) 385132451Sroberto{ 386285612Sdelphij double time_gap; 387285612Sdelphij double adj; 388285612Sdelphij int i; 389132451Sroberto 390285612Sdelphij /* Compute the time between the last update event and this update */ 391285612Sdelphij time_gap = e->time - simulation.sim_time; 392285612Sdelphij 393285612Sdelphij if (time_gap < 0) 394285612Sdelphij printf("WARNING: e->time %.6g comes before sim_time %.6g (gap %+.6g)\n", 395285612Sdelphij e->time, simulation.sim_time, time_gap); 396285612Sdelphij 397285612Sdelphij /* Advance the client clock */ 398285612Sdelphij if (e->time + time_gap < simclock.local_time) 399285612Sdelphij printf("WARNING: e->time + gap %.6g comes before local_time %.6g\n", 400285612Sdelphij e->time + time_gap, simclock.local_time); 401285612Sdelphij simclock.local_time = e->time + time_gap; 402285612Sdelphij 403285612Sdelphij /* Advance the simulation time */ 404285612Sdelphij simulation.sim_time = e->time; 405285612Sdelphij 406285612Sdelphij /* Advance the server clocks adjusted for systematic and random frequency 407285612Sdelphij * errors. The random error is a random walk computed as the 408285612Sdelphij * integral of samples from a Gaussian distribution. 409285612Sdelphij */ 410285612Sdelphij for (i = 0; i < simulation.num_of_servers; ++i) { 411285612Sdelphij simulation.servers[i].curr_script->freq_offset += 412285612Sdelphij gauss(0, time_gap * simulation.servers[i].curr_script->wander); 413285612Sdelphij 414285612Sdelphij simulation.servers[i].server_time += time_gap * 415285612Sdelphij (1 + simulation.servers[i].curr_script->freq_offset); 416285612Sdelphij } 417285612Sdelphij 418285612Sdelphij /* Perform the adjtime() function. If the adjustment completed 419285612Sdelphij * in the previous interval, amortize the entire amount; if not, 420285612Sdelphij * carry the leftover to the next interval. 421285612Sdelphij */ 422285612Sdelphij 423285612Sdelphij adj = time_gap * simclock.slew; 424285612Sdelphij if (adj < fabs(simclock.adj)) { 425285612Sdelphij if (simclock.adj < 0) { 426285612Sdelphij simclock.adj += adj; 427285612Sdelphij simclock.local_time -= adj; 428285612Sdelphij } else { 429285612Sdelphij simclock.adj -= adj; 430285612Sdelphij simclock.local_time += adj; 431285612Sdelphij } 432285612Sdelphij } else { 433285612Sdelphij simclock.local_time += simclock.adj; 434285612Sdelphij simclock.adj = 0; 435285612Sdelphij } 436132451Sroberto} 437132451Sroberto 438132451Sroberto 439285612Sdelphij/* Define a function that processes a receive packet event. 440285612Sdelphij * This function simply inserts the packet received onto the receive queue 441285612Sdelphij */ 442285612Sdelphij 443285612Sdelphijvoid sim_event_recv_packet(Event *e) 444132451Sroberto{ 445285612Sdelphij struct recvbuf *rbuf; 446285612Sdelphij 447285612Sdelphij /* Allocate a receive buffer and copy the packet to it */ 448285612Sdelphij if ((rbuf = get_node(sizeof(*rbuf))) == NULL) 449285612Sdelphij abortsim("get_node failed in sim_event_recv_packet"); 450285612Sdelphij memcpy(rbuf, &e->rcv_buf, sizeof(*rbuf)); 451285612Sdelphij 452285612Sdelphij /* Store the local time in the received packet */ 453285612Sdelphij DTOLFP(simclock.local_time, &rbuf->recv_time); 454285612Sdelphij 455285612Sdelphij /* Insert the packet received onto the receive queue */ 456285612Sdelphij enqueue(recv_queue, rbuf); 457132451Sroberto} 458132451Sroberto 459132451Sroberto 460285612Sdelphij 461285612Sdelphij/* Define a function to output simulation statistics on a beep event 462132451Sroberto */ 463285612Sdelphij 464285612Sdelphij/*** TODO: Need to decide on how to output for multiple servers ***/ 465285612Sdelphijvoid sim_event_beep(Event *e) 466132451Sroberto{ 467285612Sdelphij#if 0 468285612Sdelphij static int first_time = 1; 469285612Sdelphij char *dash = "-----------------"; 470285612Sdelphij#endif 471132451Sroberto 472285612Sdelphij fprintf(stderr, "BEEP!!!\n"); 473285612Sdelphij enqueue(event_queue, event(e->time + simulation.beep_delay, BEEP)); 474285612Sdelphij#if 0 475285612Sdelphij if(simulation.beep_delay > 0) { 476285612Sdelphij if (first_time) { 477285612Sdelphij printf("\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n", 478285612Sdelphij ' ', ' ', ' ', ' ',' '); 479285612Sdelphij printf("\t%s\t%s\t%s\n", dash, dash, dash); 480285612Sdelphij first_time = 0; 481132451Sroberto 482285612Sdelphij printf("\t%16.6f\t%16.6f\t%16.6f\n", 483285612Sdelphij n->time, n->clk_time, n->ntp_time); 484285612Sdelphij return; 485132451Sroberto } 486285612Sdelphij printf("\t%16.6f\t%16.6f\t%16.6f\n", 487285612Sdelphij simclock.local_time, 488285612Sdelphij n->time, n->clk_time, n->ntp_time); 489285612Sdelphij#endif 490132451Sroberto 491132451Sroberto} 492132451Sroberto 493132451Sroberto 494285612Sdelphij/* Define a function to abort the simulation on an error and spit out an 495285612Sdelphij * error message 496132451Sroberto */ 497285612Sdelphij 498285612Sdelphijvoid abortsim(char *errmsg) 499132451Sroberto{ 500285612Sdelphij perror(errmsg); 501285612Sdelphij exit(1); 502285612Sdelphij} 503132451Sroberto 504132451Sroberto 505132451Sroberto 506285612Sdelphij/* CODE ORIGINALLY IN libntp/systime.c 507285612Sdelphij * ----------------------------------- 508285612Sdelphij * This code was a part of the original NTP simulator and originally 509285612Sdelphij * had its home in the libntp/systime.c file. 510285612Sdelphij * 511285612Sdelphij * It has been shamelessly moved to here and has been modified for the 512285612Sdelphij * purposes of the current simulator. 513285612Sdelphij */ 514132451Sroberto 515132451Sroberto 516132451Sroberto/* 517285612Sdelphij * get_systime - return the system time in NTP timestamp format 518132451Sroberto */ 519132451Srobertovoid 520285612Sdelphijget_systime( 521285612Sdelphij l_fp *now /* current system time in l_fp */ ) 522132451Sroberto{ 523285612Sdelphij /* 524285612Sdelphij * To fool the code that determines the local clock precision, 525285612Sdelphij * we advance the clock a minimum of 200 nanoseconds on every 526285612Sdelphij * clock read. This is appropriate for a typical modern machine 527285612Sdelphij * with nanosecond clocks. Note we make no attempt here to 528285612Sdelphij * simulate reading error, since the error is so small. This may 529285612Sdelphij * change when the need comes to implement picosecond clocks. 530285612Sdelphij */ 531285612Sdelphij if (simclock.local_time == simclock.last_read_time) 532285612Sdelphij simclock.local_time += 200e-9; 533132451Sroberto 534285612Sdelphij simclock.last_read_time = simclock.local_time; 535285612Sdelphij DTOLFP(simclock.local_time, now); 536285612Sdelphij/* OLD Code 537285612Sdelphij if (ntp_node.ntp_time == ntp_node.last_time) 538285612Sdelphij ntp_node.ntp_time += 200e-9; 539285612Sdelphij ntp_node.last_time = ntp_node.ntp_time; 540285612Sdelphij DTOLFP(ntp_node.ntp_time, now); 541285612Sdelphij*/ 542132451Sroberto} 543285612Sdelphij 544285612Sdelphij 545285612Sdelphij/* 546285612Sdelphij * adj_systime - advance or retard the system clock exactly like the 547285612Sdelphij * real thng. 548285612Sdelphij */ 549285612Sdelphijint /* always succeeds */ 550285612Sdelphijadj_systime( 551285612Sdelphij double now /* time adjustment (s) */ 552285612Sdelphij ) 553285612Sdelphij{ 554285612Sdelphij struct timeval adjtv; /* new adjustment */ 555285612Sdelphij double dtemp; 556285612Sdelphij long ticks; 557285612Sdelphij int isneg = 0; 558132451Sroberto 559285612Sdelphij /* 560285612Sdelphij * Most Unix adjtime() implementations adjust the system clock 561285612Sdelphij * in microsecond quanta, but some adjust in 10-ms quanta. We 562285612Sdelphij * carefully round the adjustment to the nearest quantum, then 563285612Sdelphij * adjust in quanta and keep the residue for later. 564285612Sdelphij */ 565285612Sdelphij dtemp = now + sys_residual; 566285612Sdelphij if (dtemp < 0) { 567285612Sdelphij isneg = 1; 568285612Sdelphij dtemp = -dtemp; 569285612Sdelphij } 570285612Sdelphij adjtv.tv_sec = (long)dtemp; 571285612Sdelphij dtemp -= adjtv.tv_sec; 572285612Sdelphij ticks = (long)(dtemp / sys_tick + .5); 573285612Sdelphij adjtv.tv_usec = (long)(ticks * sys_tick * 1e6); 574285612Sdelphij dtemp -= adjtv.tv_usec / 1e6; 575285612Sdelphij sys_residual = dtemp; 576132451Sroberto 577285612Sdelphij /* 578285612Sdelphij * Convert to signed seconds and microseconds for the Unix 579285612Sdelphij * adjtime() system call. Note we purposely lose the adjtime() 580285612Sdelphij * leftover. 581285612Sdelphij */ 582285612Sdelphij if (isneg) { 583285612Sdelphij adjtv.tv_sec = -adjtv.tv_sec; 584285612Sdelphij adjtv.tv_usec = -adjtv.tv_usec; 585285612Sdelphij sys_residual = -sys_residual; 586285612Sdelphij } 587285612Sdelphij simclock.adj = now; 588285612Sdelphij/* ntp_node.adj = now; */ 589285612Sdelphij return (1); 590285612Sdelphij} 591285612Sdelphij 592285612Sdelphij 593132451Sroberto/* 594285612Sdelphij * step_systime - step the system clock. We are religious here. 595132451Sroberto */ 596285612Sdelphijint /* always succeeds */ 597285612Sdelphijstep_systime( 598285612Sdelphij double now /* step adjustment (s) */ 599285612Sdelphij ) 600132451Sroberto{ 601285612Sdelphij#ifdef DEBUG 602285612Sdelphij if (debug) 603285612Sdelphij printf("step_systime: time %.6f adj %.6f\n", 604285612Sdelphij simclock.local_time, now); 605285612Sdelphij#endif 606285612Sdelphij simclock.local_time += now; 607285612Sdelphij return (1); 608285612Sdelphij} 609285612Sdelphij 610285612Sdelphij/* 611285612Sdelphij * gauss() - returns samples from a gaussion distribution 612285612Sdelphij */ 613285612Sdelphijdouble /* Gaussian sample */ 614285612Sdelphijgauss( 615285612Sdelphij double m, /* sample mean */ 616285612Sdelphij double s /* sample standard deviation (sigma) */ 617285612Sdelphij ) 618285612Sdelphij{ 619285612Sdelphij double q1, q2; 620132451Sroberto 621285612Sdelphij /* 622285612Sdelphij * Roll a sample from a Gaussian distribution with mean m and 623285612Sdelphij * standard deviation s. For m = 0, s = 1, mean(y) = 0, 624285612Sdelphij * std(y) = 1. 625285612Sdelphij */ 626285612Sdelphij if (s == 0) 627285612Sdelphij return (m); 628285612Sdelphij while ((q1 = drand48()) == 0) 629285612Sdelphij /* empty statement */; 630285612Sdelphij q2 = drand48(); 631285612Sdelphij return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2)); 632132451Sroberto} 633132451Sroberto 634285612Sdelphij 635132451Sroberto/* 636285612Sdelphij * poisson() - returns samples from a network delay distribution 637132451Sroberto */ 638285612Sdelphijdouble /* delay sample (s) */ 639285612Sdelphijpoisson( 640285612Sdelphij double m, /* fixed propagation delay (s) */ 641285612Sdelphij double s /* exponential parameter (mu) */ 642285612Sdelphij ) 643132451Sroberto{ 644285612Sdelphij double q1; 645285612Sdelphij 646285612Sdelphij /* 647285612Sdelphij * Roll a sample from a composite distribution with propagation 648285612Sdelphij * delay m and exponential distribution time with parameter s. 649285612Sdelphij * For m = 0, s = 1, mean(y) = std(y) = 1. 650285612Sdelphij */ 651285612Sdelphij if (s == 0) 652285612Sdelphij return (m); 653285612Sdelphij while ((q1 = drand48()) == 0) 654285612Sdelphij /* empty statement */; 655285612Sdelphij return (m - s * log(q1 * s)); 656132451Sroberto} 657285612Sdelphij 658285612Sdelphij#endif 659