diff options
Diffstat (limited to 'contrib/ntp/ntpd/ntpsim.c')
-rw-r--r-- | contrib/ntp/ntpd/ntpsim.c | 856 |
1 files changed, 571 insertions, 285 deletions
diff --git a/contrib/ntp/ntpd/ntpsim.c b/contrib/ntp/ntpd/ntpsim.c index d5ed587..b7c3218 100644 --- a/contrib/ntp/ntpd/ntpsim.c +++ b/contrib/ntp/ntpd/ntpsim.c @@ -1,89 +1,142 @@ -/* - * NTP simulator engine - Harish Nair - * University of Delaware, 2001 +/* ntpdsim.c + * + * The source code for the ntp discrete event simulator. + * + * Written By: Sachin Kamboj + * University of Delaware + * Newark, DE 19711 + * Copyright (c) 2006 + * (Some code shamelessly based on the original NTP discrete event simulator) */ + +#include <config.h> +#ifdef SIM #include "ntpd.h" -#include "ntpsim.h" -#include "ntpdsim-opts.h" +#include "ntp_config.h" + +/* forward prototypes */ +int determine_event_ordering(const Event *e1, const Event *e2); +int determine_recv_buf_ordering(const struct recvbuf *b1, + const struct recvbuf *b2); +void create_server_associations(void); +void init_sim_io(void); + +/* Global Variable Definitions */ +sim_info simulation; /* Simulation Control Variables */ +local_clock_info simclock; /* Local Clock Variables */ +queue *event_queue; /* Event Queue */ +queue *recv_queue; /* Receive Queue */ +static double sys_residual = 0; /* adjustment residue (s) */ + +void (*event_ptr[]) (Event *) = { + sim_event_beep, sim_update_clocks, sim_event_timer, sim_event_recv_packet +}; /* Function pointer to the events */ -/* - * Defines... - */ -#define SIM_TIME 86400 /* end simulation time */ -#define NET_DLY .001 /* network delay */ -#define PROC_DLY .001 /* processing delay */ -#define BEEP_DLY 3600 /* beep interval (s) */ -#define SLEW 500e-6 /* correction rate (PPM) */ /* - * Function pointers + * Define a function to compare two events to determine which one occurs + * first. */ -void (*funcPtr[]) (Node *, Event) = { - &ndbeep, &ndeclk, &ntptmr, &netpkt -}; +int +determine_event_ordering( + const Event *e1, + const Event *e2 + ) +{ + return (e1->time - e2->time); +} /* - * ntpsim - initialize global variables and event queue and start + * Define a function to compare two received packets to determine which + * one is received first. */ int -ntpsim( - int argc, - char *argv[] +determine_recv_buf_ordering( + const struct recvbuf *b1, + const struct recvbuf *b2 ) { - Event e; - double maxtime; - struct timeval seed; + double recv_time1; + double recv_time2; - /* - * Initialize the global node - */ - ntp_node.time = 0; /* simulation time */ - ntp_node.sim_time = SIM_TIME; /* end simulation time (-S) */ - ntp_node.ntp_time = 0; /* client disciplined time */ - ntp_node.adj = 0; /* remaining time correction */ - ntp_node.slew = SLEW; /* correction rate (-H) */ - - ntp_node.clk_time = 0; /* server time (-O) */ - ntp_node.ferr = 0; /* frequency error (-T) */ - ntp_node.fnse = 0; /* random walk noise (-W) */ - ntp_node.ndly = NET_DLY; /* network delay (-Y) */ - ntp_node.snse = 0; /* phase noise (-C) */ - ntp_node.pdly = PROC_DLY; /* processing delay (-Z) */ - ntp_node.bdly = BEEP_DLY; /* beep interval (-B) */ - - ntp_node.events = NULL; - ntp_node.rbuflist = NULL; + /* Simply convert the time received to double and subtract */ + LFPTOD(&b1->recv_time, recv_time1); + LFPTOD(&b2->recv_time, recv_time2); - /* - * Initialize ntp variables - */ - initializing = 1; - init_auth(); - init_util(); - init_restrict(); - init_mon(); - init_timer(); - init_lib(); - init_request(); - init_control(); - init_peer(); - init_proto(); - init_io(); - init_loopfilter(); - mon_start(MON_OFF); - - { - int optct = optionProcess(&ntpdsimOptions, argc, argv); - argc -= optct; - argv += optct; + return (int)(recv_time1 - recv_time2); +} + + +/* Define a function to create the server associations */ +void create_server_associations(void) +{ + int i; + + for (i = 0; i < simulation.num_of_servers; ++i) { + printf("%s\n", stoa(simulation.servers[i].addr)); + if (peer_config(simulation.servers[i].addr, + NULL, + loopback_interface, + MODE_CLIENT, + NTP_VERSION, + NTP_MINDPOLL, + NTP_MAXDPOLL, + 0, /* peerflags */ + 0, /* ttl */ + 0, /* peerkey */ + NULL /* group ident */) == 0) { + fprintf(stderr, + "ERROR!! Could not create association for: %s\n", + stoa(simulation.servers[i].addr)); + } } +} - getconfig(argc, argv); - initializing = 0; - loop_config(LOOP_DRIFTCOMP, old_drift / 1e6); +/* Main Simulator Code */ + +int +ntpsim( + int argc, + char * argv[] + ) +{ + Event * curr_event; + struct timeval seed; + + /* Initialize the local Clock */ + simclock.local_time = 0; + simclock.adj = 0; + simclock.slew = 500e-6; + + /* Initialize the simulation */ + simulation.num_of_servers = 0; + simulation.beep_delay = BEEP_DLY; + simulation.sim_time = 0; + simulation.end_time = SIM_TIME; + + /* Initialize ntp modules */ + initializing = TRUE; + msyslog_term = TRUE; + init_sim_io(); + init_auth(); + init_util(); + init_restrict(); + init_mon(); + init_timer(); + init_lib(); + init_request(); + init_control(); + init_peer(); + init_proto(); + init_loopfilter(); + mon_start(MON_OFF); + + /* Call getconfig to parse the configuration file */ + getconfig(argc, argv); + loop_config(LOOP_DRIFTINIT, 0); + initializing = FALSE; /* * Watch out here, we want the real time, not the silly stuff. @@ -91,281 +144,514 @@ ntpsim( gettimeofday(&seed, NULL); ntp_srandom(seed.tv_usec); - /* - * Push a beep and timer interrupt on the queue - */ - push(event(0, BEEP), &ntp_node.events); - push(event(ntp_node.time + 1.0, TIMER), &ntp_node.events); + /* Initialize the event queue */ + event_queue = create_priority_queue((q_order_func) + determine_event_ordering); - /* + /* Initialize the receive queue */ + recv_queue = create_priority_queue((q_order_func) + determine_recv_buf_ordering); + + /* Push a beep and a timer on the event queue */ + enqueue(event_queue, event(0, BEEP)); + enqueue(event_queue, event(simulation.sim_time + 1.0, TIMER)); + + /* * Pop the queue until nothing is left or time is exceeded */ - maxtime = ntp_node.time + ntp_node.sim_time; - while (ntp_node.time <= maxtime && ntp_node.events != NULL ) { - e = pop(&ntp_node.events); - ndeclk(&ntp_node, e); - funcPtr[e.function](&ntp_node, e); + /* maxtime = simulation.sim_time + simulation.end_time;*/ + while (simulation.sim_time <= simulation.end_time && + (!empty(event_queue))) { + curr_event = dequeue(event_queue); + /* Update all the clocks to the time on the event */ + sim_update_clocks(curr_event); + + /* Execute the function associated with the event */ + (*event_ptr[curr_event->function])(curr_event); + free_node(curr_event); } + printf("sys_received: %lu\n", sys_received); + printf("sys_badlength: %lu\n", sys_badlength); + printf("sys_declined: %lu\n", sys_declined); + printf("sys_restricted: %lu\n", sys_restricted); + printf("sys_newversion: %lu\n", sys_newversion); + printf("sys_oldversion: %lu\n", sys_oldversion); + printf("sys_limitrejected: %lu\n", sys_limitrejected); + printf("sys_badauth: %lu\n", sys_badauth); + return (0); } -/* - * Return an event - */ -Event -event( - double t, - funcTkn f - ) +void +init_sim_io(void) { - Event e; - - e.time = t; - e.function = f; - return (e); + loopback_interface = emalloc_zero(sizeof(*loopback_interface)); + ep_list = loopback_interface; + strlcpy(loopback_interface->name, "IPv4loop", + sizeof(loopback_interface->name)); + loopback_interface->flags = INT_UP | INT_LOOPBACK; + loopback_interface->fd = -1; + loopback_interface->bfd = -1; + loopback_interface->ifnum = 1; + loopback_interface->family = AF_INET; + AF(&loopback_interface->sin) = AF_INET; + SET_ADDR4(&loopback_interface->sin, LOOPBACKADR); + SET_PORT(&loopback_interface->sin, NTP_PORT); + AF(&loopback_interface->mask) = AF_INET; + SET_ADDR4(&loopback_interface->mask, LOOPNETMASK); } -/* - * Create an event queue - */ -Queue -queue( - Event e, - Queue q - ) + +/* Define a function to create an return an Event */ + +Event *event(double t, funcTkn f) { - Queue ret; + Event *e; - if ((ret = (Queue)malloc(sizeof(struct List))) == NULL) - abortsim("queue-malloc"); - ret->event = e; - ret->next = q; - return (ret); + if ((e = get_node(sizeof(*e))) == NULL) + abortsim("get_node failed in event"); + e->time = t; + e->function = f; + return (e); } +/* NTP SIMULATION FUNCTIONS */ -/* - * Push an event into the event queue +/* Define a function for processing a timer interrupt. + * On every timer interrupt, call the NTP timer to send packets and process + * the clock and then call the receive function to receive packets. */ -void push( - Event e, - Queue *qp - ) +void sim_event_timer(Event *e) { - Queue *tmp = qp; - - while (*tmp != NULL && ((*tmp)->event.time < e.time)) - tmp = &((*tmp)->next); - *tmp = queue(e, (*tmp)); + struct recvbuf *rbuf; + + /* Call the NTP timer. + * This will be responsible for actually "sending the packets." + * Since this is a simulation, the packets sent over the network + * will be processed by the simulate_server routine below. + */ + timer(); + + /* Process received buffers */ + while (!empty(recv_queue)) { + rbuf = (struct recvbuf *)dequeue(recv_queue); + (*rbuf->receiver)(rbuf); + free_node(rbuf); + } + + /* Arm the next timer interrupt. */ + enqueue(event_queue, + event(simulation.sim_time + (1 << EVENT_TIMEOUT), TIMER)); } -/* - * Pop the first event from the event queue + +/* Define a function to simulate a server. + * This function processes the sent packet according to the server script, + * creates a reply packet and pushes the reply packet onto the event queue */ -Event -pop( - Queue *qp - ) +int simulate_server( + sockaddr_u *serv_addr, /* Address of the server */ + endpt * inter, /* Interface on which the reply should + be inserted */ + struct pkt *rpkt /* Packet sent to the server that + needs to be processed. */ + ) { - Event ret; - Queue tmp; - - tmp = *qp; - if (tmp == NULL) - abortsim("pop - empty queue"); - ret = tmp->event; - *qp = tmp->next; - free(tmp); - return (ret); + struct pkt xpkt; /* Packet to be transmitted back + to the client */ + struct recvbuf rbuf; /* Buffer for the received packet */ + Event *e; /* Packet receive event */ + server_info *server; /* Pointer to the server being simulated */ + script_info *curr_script; /* Current script being processed */ + int i; + double d1, d2, d3; /* Delays while the packet is enroute */ + double t1, t2, t3, t4; /* The four timestamps in the packet */ + l_fp lfp_host; /* host-order l_fp */ + + ZERO(xpkt); + ZERO(rbuf); + + /* Search for the server with the desired address */ + server = NULL; + for (i = 0; i < simulation.num_of_servers; ++i) { + if (memcmp(simulation.servers[i].addr, serv_addr, + sizeof(*serv_addr)) == 0) { + server = &simulation.servers[i]; + break; + } + } + + fprintf(stderr, "Received packet from %s on %s\n", + stoa(serv_addr), latoa(inter)); + if (server == NULL) + abortsim("Server with specified address not found!!!"); + + /* Get the current script for the server */ + curr_script = server->curr_script; + + /* Create a server reply packet. + * Masquerade the reply as a stratum-1 server with a GPS clock + */ + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, + MODE_SERVER); + xpkt.stratum = STRATUM_TO_PKT(((u_char)1)); + memcpy(&xpkt.refid, "GPS", 4); + xpkt.ppoll = rpkt->ppoll; + xpkt.precision = rpkt->precision; + xpkt.rootdelay = 0; + xpkt.rootdisp = 0; + + /* TIMESTAMP CALCULATIONS + t1 t4 + \ / + d1 \ / d3 + \ / + t2 ----------------- t3 + d2 + */ + /* Compute the delays */ + d1 = poisson(curr_script->prop_delay, curr_script->jitter); + d2 = poisson(curr_script->proc_delay, 0); + d3 = poisson(curr_script->prop_delay, curr_script->jitter); + + /* Note: In the transmitted packet: + * 1. t1 and t4 are times in the client according to the local clock. + * 2. t2 and t3 are server times according to the simulated server. + * Compute t1, t2, t3 and t4 + * Note: This function is called at time t1. + */ + + NTOHL_FP(&rpkt->xmt, &lfp_host); + LFPTOD(&lfp_host, t1); + t2 = server->server_time + d1; + t3 = server->server_time + d1 + d2; + t4 = t1 + d1 + d2 + d3; + + /* Save the timestamps */ + xpkt.org = rpkt->xmt; + DTOLFP(t2, &lfp_host); + HTONL_FP(&lfp_host, &xpkt.rec); + DTOLFP(t3, &lfp_host); + HTONL_FP(&lfp_host, &xpkt.xmt); + xpkt.reftime = xpkt.xmt; + + /* + * Ok, we are done with the packet. Now initialize the receive + * buffer for the packet. + */ + rbuf.used = 1; + rbuf.receiver = &receive; /* callback to process the packet */ + rbuf.recv_length = LEN_PKT_NOMAC; + rbuf.recv_pkt = xpkt; + rbuf.dstadr = inter; + rbuf.fd = inter->fd; + memcpy(&rbuf.srcadr, serv_addr, sizeof(rbuf.srcadr)); + memcpy(&rbuf.recv_srcadr, serv_addr, sizeof(rbuf.recv_srcadr)); + + /* + * Create a packet event and insert it onto the event_queue at the + * arrival time (t4) of the packet at the client + */ + e = event(t4, PACKET); + e->rcv_buf = rbuf; + enqueue(event_queue, e); + + /* + * Check if the time of the script has expired. If yes, delete it. + */ + if (curr_script->duration > simulation.sim_time && + NULL == HEAD_PFIFO(server->script)) { + printf("Hello\n"); + /* + * For some reason freeing up the curr_script memory kills the + * simulation. Further debugging is needed to determine why. + * free(curr_script); + */ + UNLINK_FIFO(curr_script, *server->script, link); + } + + return (0); } -/* - * Update clocks +/* Define a function to update all the clocks + * Most of the code is modified from the systime.c file by Prof. Mills */ -void -ndeclk( - Node *n, - Event e - ) + +void sim_update_clocks(Event *e) { - node_clock(n, e.time); + double time_gap; + double adj; + int i; + + /* Compute the time between the last update event and this update */ + time_gap = e->time - simulation.sim_time; + + if (time_gap < 0) + printf("WARNING: e->time %.6g comes before sim_time %.6g (gap %+.6g)\n", + e->time, simulation.sim_time, time_gap); + + /* Advance the client clock */ + if (e->time + time_gap < simclock.local_time) + printf("WARNING: e->time + gap %.6g comes before local_time %.6g\n", + e->time + time_gap, simclock.local_time); + simclock.local_time = e->time + time_gap; + + /* Advance the simulation time */ + simulation.sim_time = e->time; + + /* Advance the server clocks adjusted for systematic and random frequency + * errors. The random error is a random walk computed as the + * integral of samples from a Gaussian distribution. + */ + for (i = 0; i < simulation.num_of_servers; ++i) { + simulation.servers[i].curr_script->freq_offset += + gauss(0, time_gap * simulation.servers[i].curr_script->wander); + + simulation.servers[i].server_time += time_gap * + (1 + simulation.servers[i].curr_script->freq_offset); + } + + /* Perform the adjtime() function. If the adjustment completed + * in the previous interval, amortize the entire amount; if not, + * carry the leftover to the next interval. + */ + + adj = time_gap * simclock.slew; + if (adj < fabs(simclock.adj)) { + if (simclock.adj < 0) { + simclock.adj += adj; + simclock.local_time -= adj; + } else { + simclock.adj -= adj; + simclock.local_time += adj; + } + } else { + simclock.local_time += simclock.adj; + simclock.adj = 0; + } } -/* - * Timer interrupt. Eventually, this results in calling the - * srvr_rplyi() routine below. - */ -void -ntptmr( - Node *n, - Event e - ) +/* Define a function that processes a receive packet event. + * This function simply inserts the packet received onto the receive queue + */ + +void sim_event_recv_packet(Event *e) { - struct recvbuf *rbuf; + struct recvbuf *rbuf; - timer(); + /* Allocate a receive buffer and copy the packet to it */ + if ((rbuf = get_node(sizeof(*rbuf))) == NULL) + abortsim("get_node failed in sim_event_recv_packet"); + memcpy(rbuf, &e->rcv_buf, sizeof(*rbuf)); - /* - * Process buffers received. They had better be in order by - * receive timestamp. Note that there are no additional buffers - * in the current implementation of ntpsim. - */ - while (n->rbuflist != NULL) { - rbuf = n->rbuflist; - n->rbuflist = NULL; - (rbuf->receiver)(rbuf); - free(rbuf); - } + /* Store the local time in the received packet */ + DTOLFP(simclock.local_time, &rbuf->recv_time); - /* - * Arm the next timer interrupt. - */ - push(event(e.time + (1 << EVENT_TIMEOUT), TIMER), &n->events); + /* Insert the packet received onto the receive queue */ + enqueue(recv_queue, rbuf); } -/* - * srvr_rply() - send packet + +/* Define a function to output simulation statistics on a beep event */ -int srvr_rply( - Node *n, - struct sockaddr_storage *dest, - struct interface *inter, struct pkt *rpkt - ) + +/*** TODO: Need to decide on how to output for multiple servers ***/ +void sim_event_beep(Event *e) { - struct pkt xpkt; - struct recvbuf rbuf; - Event xvnt; - double dtemp, etemp; +#if 0 + static int first_time = 1; + char *dash = "-----------------"; +#endif + + fprintf(stderr, "BEEP!!!\n"); + enqueue(event_queue, event(e->time + simulation.beep_delay, BEEP)); +#if 0 + if(simulation.beep_delay > 0) { + if (first_time) { + printf("\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n", + ' ', ' ', ' ', ' ',' '); + printf("\t%s\t%s\t%s\n", dash, dash, dash); + first_time = 0; + + printf("\t%16.6f\t%16.6f\t%16.6f\n", + n->time, n->clk_time, n->ntp_time); + return; + } + printf("\t%16.6f\t%16.6f\t%16.6f\n", + simclock.local_time, + n->time, n->clk_time, n->ntp_time); +#endif - /* - * Insert packet header values. We make this look like a - * stratum-1 server with a GPS clock, but nobody will ever - * notice that. - */ - xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, - MODE_SERVER); - xpkt.stratum = STRATUM_TO_PKT(((u_char)1)); - memcpy(&xpkt.refid, "GPS", 4); - xpkt.ppoll = rpkt->ppoll; - xpkt.precision = rpkt->precision; - xpkt.rootdelay = 0; - xpkt.rootdispersion = 0; +} - /* - * Insert the timestamps. - */ - xpkt.org = rpkt->xmt; - dtemp = poisson(n->ndly, n->snse); /* client->server delay */ - DTOLFP(dtemp + n->clk_time, &xpkt.rec); - dtemp += poisson(n->pdly, 0); /* server delay */ - DTOLFP(dtemp + n->clk_time, &xpkt.xmt); - xpkt.reftime = xpkt.xmt; - dtemp += poisson(n->ndly, n->snse); /* server->client delay */ - /* - * Insert the I/O stuff. - */ - rbuf.receiver = receive; - get_systime(&rbuf.recv_time); - rbuf.recv_length = LEN_PKT_NOMAC; - rbuf.recv_pkt = xpkt; - memcpy(&rbuf.srcadr, dest, sizeof(struct sockaddr_storage)); - memcpy(&rbuf.recv_srcadr, dest, - sizeof(struct sockaddr_storage)); - if ((rbuf.dstadr = malloc(sizeof(struct interface))) == NULL) - abortsim("server-malloc"); - memcpy(rbuf.dstadr, inter, sizeof(struct interface)); +/* Define a function to abort the simulation on an error and spit out an + * error message + */ - /* - * Very carefully predict the time of arrival for the received - * packet. - */ - LFPTOD(&xpkt.org, etemp); - etemp += dtemp; - xvnt = event(etemp, PACKET); - xvnt.rcv_buf = rbuf; - push(xvnt, &n->events); - return (0); +void abortsim(char *errmsg) +{ + perror(errmsg); + exit(1); } + +/* CODE ORIGINALLY IN libntp/systime.c + * ----------------------------------- + * This code was a part of the original NTP simulator and originally + * had its home in the libntp/systime.c file. + * + * It has been shamelessly moved to here and has been modified for the + * purposes of the current simulator. + */ + + /* - * netpkt() - receive packet + * get_systime - return the system time in NTP timestamp format */ void -netpkt( - Node *n, - Event e - ) +get_systime( + l_fp *now /* current system time in l_fp */ ) { - struct recvbuf *rbuf; - struct recvbuf *obuf; - - /* - * Insert the packet on the receive queue and record the arrival - * time. - */ - if ((rbuf = malloc(sizeof(struct recvbuf))) == NULL) - abortsim("ntprcv-malloc"); - memcpy(rbuf, &e.rcv_buf, sizeof(struct recvbuf)); - rbuf->receiver = receive; - DTOLFP(n->ntp_time, &rbuf->recv_time); - obuf = n->rbuflist; - - /* - * In the present incarnation, no more than one buffer can be on - * the queue; - */ - if (obuf == NULL) { - n->rbuflist = rbuf; - } + /* + * To fool the code that determines the local clock precision, + * we advance the clock a minimum of 200 nanoseconds on every + * clock read. This is appropriate for a typical modern machine + * with nanosecond clocks. Note we make no attempt here to + * simulate reading error, since the error is so small. This may + * change when the need comes to implement picosecond clocks. + */ + if (simclock.local_time == simclock.last_read_time) + simclock.local_time += 200e-9; + + simclock.last_read_time = simclock.local_time; + DTOLFP(simclock.local_time, now); +/* OLD Code + if (ntp_node.ntp_time == ntp_node.last_time) + ntp_node.ntp_time += 200e-9; + ntp_node.last_time = ntp_node.ntp_time; + DTOLFP(ntp_node.ntp_time, now); +*/ } - - + + /* - * ndbeep() - progress indicator + * adj_systime - advance or retard the system clock exactly like the + * real thng. */ -void -ndbeep( - Node *n, - Event e - ) +int /* always succeeds */ +adj_systime( + double now /* time adjustment (s) */ + ) { - static int first_time = 1; - char *dash = "-----------------"; - - if(n->bdly > 0) { - if (first_time) { - printf( - "\t%4c T %4c\t%4c T+ERR %3c\t%5cT+ERR+NTP\n", ' ', ' ', ' ', ' ',' '); - printf("\t%s\t%s\t%s\n", dash, dash, dash); - first_time = 0; - push(event(n->bdly, BEEP), &n->events); - push(event(n->sim_time, BEEP), &n->events); - printf("\t%16.6f\t%16.6f\t%16.6f\n", - n->time, n->clk_time, n->ntp_time); - return; - } - printf("\t%16.6f\t%16.6f\t%16.6f\n", - n->time, n->clk_time, n->ntp_time); - push(event(e.time + n->bdly, BEEP), &n->events); - } + struct timeval adjtv; /* new adjustment */ + double dtemp; + long ticks; + int isneg = 0; + + /* + * Most Unix adjtime() implementations adjust the system clock + * in microsecond quanta, but some adjust in 10-ms quanta. We + * carefully round the adjustment to the nearest quantum, then + * adjust in quanta and keep the residue for later. + */ + dtemp = now + sys_residual; + if (dtemp < 0) { + isneg = 1; + dtemp = -dtemp; + } + adjtv.tv_sec = (long)dtemp; + dtemp -= adjtv.tv_sec; + ticks = (long)(dtemp / sys_tick + .5); + adjtv.tv_usec = (long)(ticks * sys_tick * 1e6); + dtemp -= adjtv.tv_usec / 1e6; + sys_residual = dtemp; + + /* + * Convert to signed seconds and microseconds for the Unix + * adjtime() system call. Note we purposely lose the adjtime() + * leftover. + */ + if (isneg) { + adjtv.tv_sec = -adjtv.tv_sec; + adjtv.tv_usec = -adjtv.tv_usec; + sys_residual = -sys_residual; + } + simclock.adj = now; +/* ntp_node.adj = now; */ + return (1); +} + + +/* + * step_systime - step the system clock. We are religious here. + */ +int /* always succeeds */ +step_systime( + double now /* step adjustment (s) */ + ) +{ +#ifdef DEBUG + if (debug) + printf("step_systime: time %.6f adj %.6f\n", + simclock.local_time, now); +#endif + simclock.local_time += now; + return (1); +} + +/* + * gauss() - returns samples from a gaussion distribution + */ +double /* Gaussian sample */ +gauss( + double m, /* sample mean */ + double s /* sample standard deviation (sigma) */ + ) +{ + double q1, q2; + + /* + * Roll a sample from a Gaussian distribution with mean m and + * standard deviation s. For m = 0, s = 1, mean(y) = 0, + * std(y) = 1. + */ + if (s == 0) + return (m); + while ((q1 = drand48()) == 0) + /* empty statement */; + q2 = drand48(); + return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2)); } - + /* - * Abort simulation + * poisson() - returns samples from a network delay distribution */ -void -abortsim( - char *errmsg - ) +double /* delay sample (s) */ +poisson( + double m, /* fixed propagation delay (s) */ + double s /* exponential parameter (mu) */ + ) { - perror(errmsg); - exit(1); + double q1; + + /* + * Roll a sample from a composite distribution with propagation + * delay m and exponential distribution time with parameter s. + * For m = 0, s = 1, mean(y) = std(y) = 1. + */ + if (s == 0) + return (m); + while ((q1 = drand48()) == 0) + /* empty statement */; + return (m - s * log(q1 * s)); } + +#endif |