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