Annotation of embedaddon/ntp/ntpd/ntpsim.c, revision 1.1

1.1     ! misho       1: /* ntpdsim.c
        !             2:  *
        !             3:  * The source code for the ntp discrete event simulator. 
        !             4:  *
        !             5:  * Written By: Sachin Kamboj
        !             6:  *             University of Delaware
        !             7:  *             Newark, DE 19711
        !             8:  * Copyright (c) 2006
        !             9:  * (Some code shamelessly based on the original NTP discrete event simulator)
        !            10:  */
        !            11: 
        !            12: #ifdef SIM
        !            13: #include "ntpd.h"
        !            14: #include "ntpsim.h"
        !            15: #include "ntp_data_structures.h"
        !            16: 
        !            17: 
        !            18: /* Global Variable Definitions */
        !            19: 
        !            20: sim_info simulation;           /* Simulation Control Variables */
        !            21: local_clock_info simclock;     /* Local Clock Variables */
        !            22: queue *event_queue;            /* Event Queue */
        !            23: queue *recv_queue;             /* Receive Queue */
        !            24: static double sys_residual = 0;        /* adjustment residue (s) */
        !            25: 
        !            26: void (*event_ptr[]) (Event *) = {
        !            27:     sim_event_beep, sim_update_clocks, sim_event_timer, sim_event_recv_packet
        !            28: };                     /* Function pointer to the events */
        !            29: 
        !            30: 
        !            31: /* Define a function to compare two events to determine which one occurs first
        !            32:  */
        !            33: 
        !            34: int determine_event_ordering(Event *e1, Event *e2);
        !            35: 
        !            36: int determine_event_ordering(Event *e1, Event *e2)
        !            37: {
        !            38:     return (e1->time - e2->time);
        !            39: }
        !            40: 
        !            41: /* Define a function to compare two received packets to determine which one
        !            42:  * is received first
        !            43:  */
        !            44: int determine_recv_buf_ordering(struct recvbuf *b1, struct recvbuf *b2);
        !            45: 
        !            46: int determine_recv_buf_ordering(struct recvbuf *b1, struct recvbuf *b2)
        !            47: {
        !            48:     double recv_time1, recv_time2;
        !            49: 
        !            50:     /* Simply convert the time received to double and subtract */
        !            51:     LFPTOD(&b1->recv_time, recv_time1);
        !            52:     LFPTOD(&b2->recv_time, recv_time2);
        !            53:     return ((int)(recv_time1 - recv_time2));
        !            54: }
        !            55: 
        !            56: /* Define a function to create the server associations */
        !            57: void create_server_associations()
        !            58: {
        !            59:     int i;
        !            60:     for (i = 0;i < simulation.num_of_servers;++i) {
        !            61:        printf("%s\n", stoa(simulation.servers[i].addr));
        !            62:        if (peer_config(simulation.servers[i].addr,
        !            63:                        ANY_INTERFACE_CHOOSE(simulation.servers[i].addr),
        !            64:                        MODE_CLIENT,
        !            65:                        NTP_VERSION,
        !            66:                        NTP_MINDPOLL,
        !            67:                        NTP_MAXDPOLL,
        !            68:                        0, /* peerflags */
        !            69:                        0, /* ttl */
        !            70:                        0, /* peerkey */
        !            71:                        (u_char *)"*" /* peerkeystr */) == 0) {
        !            72:            fprintf(stderr, "ERROR!! Could not create association for: %s",
        !            73:                    stoa(simulation.servers[i].addr));
        !            74:        }
        !            75:     }
        !            76: }
        !            77: 
        !            78: 
        !            79: /* Main Simulator Code */
        !            80: 
        !            81: int ntpsim(int argc, char *argv[])
        !            82: {
        !            83:     Event *curr_event;
        !            84:     struct timeval seed;
        !            85: 
        !            86:     /* Initialize the local Clock 
        !            87:      */
        !            88:     simclock.local_time = 0;
        !            89:     simclock.adj = 0;
        !            90:     simclock.slew = 0;
        !            91: 
        !            92:     /* Initialize the simulation 
        !            93:      */
        !            94:     simulation.num_of_servers = 0;
        !            95:     simulation.beep_delay = BEEP_DLY;
        !            96:     simulation.sim_time = 0;
        !            97:     simulation.end_time = SIM_TIME;
        !            98: 
        !            99:     /*
        !           100:      * Initialize ntp variables
        !           101:      */
        !           102:     initializing = 1;
        !           103:     init_auth();
        !           104:     init_util();
        !           105:     init_restrict();
        !           106:     init_mon();
        !           107:     init_timer();
        !           108:     init_lib();
        !           109:     init_request();
        !           110:     init_control();
        !           111:     init_peer();
        !           112:     init_proto();
        !           113:     init_io();
        !           114:     init_loopfilter();
        !           115:     mon_start(MON_OFF);    
        !           116: 
        !           117:     /* Call getconfig to parse the configuration file */
        !           118:     getconfig(argc, argv);
        !           119:     initializing = 0;
        !           120:     loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
        !           121: 
        !           122:     /*
        !           123:      * Watch out here, we want the real time, not the silly stuff.
        !           124:      */
        !           125:     gettimeofday(&seed, NULL);
        !           126:     ntp_srandom(seed.tv_usec);
        !           127: 
        !           128: 
        !           129:     /* Initialize the event queue */
        !           130:     event_queue = create_priority_queue((int(*)(void *, void*)) 
        !           131:                                        determine_event_ordering);
        !           132: 
        !           133:     /* Initialize the receive queue */
        !           134:     recv_queue = create_priority_queue((int(*)(void *, void*))
        !           135:                                       determine_recv_buf_ordering);
        !           136: 
        !           137:     /* Push a beep and a timer on the event queue */
        !           138:     enqueue(event_queue, event(0, BEEP));
        !           139:     enqueue(event_queue, event(simulation.sim_time + 1.0, TIMER));
        !           140:     /* 
        !           141:      * Pop the queue until nothing is left or time is exceeded
        !           142:      */
        !           143:     /* maxtime = simulation.sim_time + simulation.end_time;*/
        !           144:     while (simulation.sim_time <= simulation.end_time &&
        !           145:           (!empty(event_queue))) {
        !           146:        curr_event = dequeue(event_queue);
        !           147:        /* Update all the clocks to the time on the event */
        !           148:        sim_update_clocks(curr_event);
        !           149: 
        !           150:        /* Execute the function associated with the event */
        !           151:        event_ptr[curr_event->function](curr_event);
        !           152:        free_node(curr_event);
        !           153:     }
        !           154:     return (0);
        !           155: }
        !           156: 
        !           157: 
        !           158: 
        !           159: /* Define a function to create an return an Event  */
        !           160: 
        !           161: Event *event(double t, funcTkn f)
        !           162: {
        !           163:     Event *e;
        !           164: 
        !           165:     if ((e = get_node(sizeof(*e))) == NULL)
        !           166:        abortsim("get_node failed in event");
        !           167:     e->time = t;
        !           168:     e->function = f;
        !           169:     return (e);
        !           170: }
        !           171: 
        !           172: /* NTP SIMULATION FUNCTIONS */
        !           173: 
        !           174: /* Define a function for processing a timer interrupt.
        !           175:  * On every timer interrupt, call the NTP timer to send packets and process
        !           176:  * the clock and then call the receive function to receive packets.
        !           177:  */
        !           178: void sim_event_timer(Event *e)
        !           179: {
        !           180:     struct recvbuf *rbuf;
        !           181: 
        !           182:     /* Call the NTP timer.
        !           183:      * This will be responsible for actually "sending the packets."
        !           184:      * Since this is a simulation, the packets sent over the network
        !           185:      * will be processed by the simulate_server routine below.
        !           186:      */
        !           187:     timer();
        !           188: 
        !           189:     /* Process received buffers */
        !           190:     while (!empty(recv_queue)) {
        !           191:        rbuf = (struct recvbuf *)dequeue(recv_queue);
        !           192:        (rbuf->receiver)(rbuf);
        !           193:        free_node(rbuf);
        !           194:     }
        !           195: 
        !           196:     /* Arm the next timer interrupt. */
        !           197:     enqueue(event_queue, 
        !           198:            event(simulation.sim_time + (1 << EVENT_TIMEOUT), TIMER));
        !           199: }
        !           200: 
        !           201: 
        !           202: 
        !           203: /* Define a function to simulate a server.
        !           204:  * This function processes the sent packet according to the server script,
        !           205:  * creates a reply packet and pushes the reply packet onto the event queue
        !           206:  */
        !           207: int simulate_server(
        !           208:     sockaddr_u *serv_addr,             /* Address of the server */
        !           209:     struct interface *inter,           /* Interface on which the reply should
        !           210:                                           be inserted */
        !           211:     struct pkt *rpkt                   /* Packet sent to the server that
        !           212:                                           needs to be processed. */
        !           213: )
        !           214: {
        !           215:     struct pkt xpkt;          /* Packet to be transmitted back
        !           216:                                  to the client */
        !           217:     struct recvbuf rbuf;       /* Buffer for the received packet */
        !           218:     Event *e;                 /* Packet receive event */
        !           219:     server_info *server;       /* Pointer to the server being simulated */
        !           220:     script_info *curr_script;  /* Current script being processed */
        !           221:     int i;
        !           222:     double d1, d2, d3;        /* Delays while the packet is enroute */
        !           223:     double t1, t2, t3, t4;     /* The four timestamps in the packet */
        !           224: 
        !           225:     memset(&xpkt, 0, sizeof(xpkt));
        !           226:     memset(&rbuf, 0, sizeof(rbuf));
        !           227: 
        !           228:     /* Search for the server with the desired address */
        !           229:     server = NULL;
        !           230:     for (i = 0; i < simulation.num_of_servers; ++i) {
        !           231:        fprintf(stderr,"Checking address: %s\n", stoa(simulation.servers[i].addr));
        !           232:        if (memcmp(simulation.servers[i].addr, serv_addr, 
        !           233:                   sizeof(*serv_addr)) == 0) { 
        !           234:            server = &simulation.servers[i];
        !           235:            break;
        !           236:        }
        !           237:     }
        !           238: 
        !           239:     fprintf(stderr, "Received packet for: %s\n", stoa(serv_addr));
        !           240:     if (server == NULL)
        !           241:        abortsim("Server with specified address not found!!!");
        !           242:     
        !           243:     /* Get the current script for the server */
        !           244:     curr_script = server->curr_script;
        !           245: 
        !           246:     /* Create a server reply packet. 
        !           247:      * Masquerade the reply as a stratum-1 server with a GPS clock
        !           248:      */
        !           249:     xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION,
        !           250:                                      MODE_SERVER);
        !           251:     xpkt.stratum = STRATUM_TO_PKT(((u_char)1));
        !           252:     memcpy(&xpkt.refid, "GPS", 4);
        !           253:     xpkt.ppoll = rpkt->ppoll;
        !           254:     xpkt.precision = rpkt->precision;
        !           255:     xpkt.rootdelay = 0;
        !           256:     xpkt.rootdisp = 0;
        !           257: 
        !           258:     /* TIMESTAMP CALCULATIONS
        !           259:            t1                           t4
        !           260:             \                          /
        !           261:          d1  \                        / d3
        !           262:               \                      /
        !           263:               t2 ----------------- t3
        !           264:                         d2
        !           265:     */
        !           266:     /* Compute the delays */
        !           267:     d1 = poisson(curr_script->prop_delay, curr_script->jitter);
        !           268:     d2 = poisson(curr_script->proc_delay, 0);
        !           269:     d3 = poisson(curr_script->prop_delay, curr_script->jitter);
        !           270: 
        !           271:     /* Note: In the transmitted packet: 
        !           272:      * 1. t1 and t4 are times in the client according to the local clock.
        !           273:      * 2. t2 and t3 are server times according to the simulated server.
        !           274:      * Compute t1, t2, t3 and t4
        !           275:      * Note: This function is called at time t1. 
        !           276:      */
        !           277: 
        !           278:     LFPTOD(&rpkt->xmt, t1);
        !           279:     t2 = server->server_time + d1;
        !           280:     t3 = server->server_time + d1 + d2;
        !           281:     t4 = t1 + d1 + d2 + d3;
        !           282: 
        !           283:     /* Save the timestamps */
        !           284:     xpkt.org = rpkt->xmt;     
        !           285:     DTOLFP(t2, &xpkt.rec);
        !           286:     DTOLFP(t3, &xpkt.xmt);
        !           287:     xpkt.reftime = xpkt.xmt;
        !           288: 
        !           289: 
        !           290: 
        !           291:     /* Ok, we are done with the packet. Now initialize the receive buffer for
        !           292:      * the packet.
        !           293:      */
        !           294:     rbuf.receiver = receive;   /* Function to call to process the packet */
        !           295:     rbuf.recv_length = LEN_PKT_NOMAC;
        !           296:     rbuf.recv_pkt = xpkt;
        !           297:     rbuf.used = 1;
        !           298: 
        !           299:     memcpy(&rbuf.srcadr, serv_addr, sizeof(rbuf.srcadr));
        !           300:     memcpy(&rbuf.recv_srcadr, serv_addr, sizeof(rbuf.recv_srcadr));
        !           301:     if ((rbuf.dstadr = malloc(sizeof(*rbuf.dstadr))) == NULL)
        !           302:        abortsim("malloc failed in simulate_server");
        !           303:     memcpy(rbuf.dstadr, inter, sizeof(*rbuf.dstadr));
        !           304:     /* rbuf.link = NULL; */
        !           305: 
        !           306:     /* Create a packet event and insert it onto the event_queue at the 
        !           307:      * arrival time (t4) of the packet at the client 
        !           308:      */
        !           309:     e = event(t4, PACKET);
        !           310:     e->rcv_buf = rbuf;
        !           311:     enqueue(event_queue, e);
        !           312:     
        !           313: 
        !           314:     /* Check if the time of the script has expired. If yes, delete the script.
        !           315:      * If not, re-enqueue the script onto the server script queue 
        !           316:      */
        !           317:     if (curr_script->duration > simulation.sim_time && 
        !           318:        !empty(server->script)) {
        !           319:        printf("Hello\n");
        !           320:        /* 
        !           321:         * For some reason freeing up the curr_script memory kills the
        !           322:         * simulation. Further debugging is needed to determine why.
        !           323:         * free_node(curr_script);
        !           324:         */
        !           325:        curr_script = dequeue(server->script);
        !           326:     }
        !           327: 
        !           328:     return (0);
        !           329: }
        !           330: 
        !           331: 
        !           332: /* Define a function to update all the clocks 
        !           333:  * Most of the code is modified from the systime.c file by Prof. Mills
        !           334:  */
        !           335: 
        !           336: void sim_update_clocks (Event *e)
        !           337: {
        !           338:     double time_gap;
        !           339:     double adj;
        !           340:     int i;
        !           341: 
        !           342:     /* Compute the time between the last update event and this update */
        !           343:     time_gap = e->time - simulation.sim_time;
        !           344: 
        !           345:     /* Advance the client clock */
        !           346:     simclock.local_time = e->time + time_gap;
        !           347: 
        !           348:     /* Advance the simulation time */
        !           349:     simulation.sim_time = e->time;
        !           350: 
        !           351:     /* Advance the server clocks adjusted for systematic and random frequency
        !           352:      * errors. The random error is a random walk computed as the
        !           353:      * integral of samples from a Gaussian distribution.
        !           354:      */
        !           355:     for (i = 0;i < simulation.num_of_servers; ++i) {
        !           356:        simulation.servers[i].curr_script->freq_offset +=
        !           357:            gauss(0, time_gap * simulation.servers[i].curr_script->wander);
        !           358: 
        !           359:        simulation.servers[i].server_time += time_gap * 
        !           360:            (1 + simulation.servers[i].curr_script->freq_offset);
        !           361:     }
        !           362: 
        !           363: 
        !           364:     /* Perform the adjtime() function. If the adjustment completed
        !           365:      * in the previous interval, amortize the entire amount; if not,
        !           366:      * carry the leftover to the next interval.
        !           367:      */
        !           368: 
        !           369:     adj = time_gap * simclock.slew;
        !           370:     if (adj < fabs(simclock.adj)) {
        !           371:        if (simclock.adj < 0) {
        !           372:            simclock.adj += adj;
        !           373:            simclock.local_time -= adj;
        !           374:        } 
        !           375:        else {
        !           376:            simclock.adj -= adj;
        !           377:            simclock.local_time += adj;
        !           378:        }    
        !           379:     } 
        !           380:     else {
        !           381:        simclock.local_time += simclock.adj;
        !           382:        simclock.adj = 0;
        !           383:     }
        !           384: }
        !           385: 
        !           386: 
        !           387: /* Define a function that processes a receive packet event. 
        !           388:  * This function simply inserts the packet received onto the receive queue
        !           389:  */   
        !           390: 
        !           391: void sim_event_recv_packet(Event *e)
        !           392: {
        !           393:     struct recvbuf *rbuf;
        !           394: 
        !           395:     /* Allocate a receive buffer and copy the packet to it */
        !           396:     if ((rbuf = get_node(sizeof(*rbuf))) == NULL)
        !           397:        abortsim("get_node failed in sim_event_recv_packet");
        !           398:     memcpy(rbuf, &e->rcv_buf, sizeof(*rbuf));
        !           399: 
        !           400:     /* Store the local time in the received packet */
        !           401:     DTOLFP(simclock.local_time, &rbuf->recv_time);
        !           402: 
        !           403:     /* Insert the packet received onto the receive queue */
        !           404:     enqueue(recv_queue, rbuf);
        !           405: }
        !           406: 
        !           407: 
        !           408: 
        !           409: /* Define a function to output simulation statistics on a beep event
        !           410:  */
        !           411: 
        !           412: /*** TODO: Need to decide on how to output for multiple servers ***/
        !           413: void sim_event_beep(Event *e)
        !           414: {
        !           415: #if 0
        !           416:     static int first_time = 1;
        !           417:     char *dash = "-----------------";
        !           418: #endif
        !           419: 
        !           420:     fprintf(stderr, "BEEP!!!\n");
        !           421:     enqueue(event_queue, event(e->time + simulation.beep_delay, BEEP));
        !           422: #if 0
        !           423:     if(simulation.beep_delay > 0) {
        !           424:        if (first_time) {
        !           425:            printf("\t%4c    T    %4c\t%4c  T+ERR  %3c\t%5cT+ERR+NTP\n", 
        !           426:                   ' ', ' ', ' ', ' ',' ');
        !           427:            printf("\t%s\t%s\t%s\n", dash, dash, dash);
        !           428:            first_time = 0;
        !           429: 
        !           430:            printf("\t%16.6f\t%16.6f\t%16.6f\n",
        !           431:                   n->time, n->clk_time, n->ntp_time);
        !           432:            return;
        !           433:        }
        !           434:        printf("\t%16.6f\t%16.6f\t%16.6f\n",
        !           435:               simclock.local_time, 
        !           436:               n->time, n->clk_time, n->ntp_time);
        !           437: #endif
        !           438: 
        !           439: }
        !           440: 
        !           441: 
        !           442: /* Define a function to abort the simulation on an error and spit out an
        !           443:  * error message
        !           444:  */
        !           445: 
        !           446: void abortsim(char *errmsg)
        !           447: {
        !           448:     perror(errmsg);
        !           449:     exit(1);
        !           450: }
        !           451: 
        !           452: 
        !           453: 
        !           454: /* CODE ORIGINALLY IN libntp/systime.c 
        !           455:  * -----------------------------------
        !           456:  * This code was a part of the original NTP simulator and originally 
        !           457:  * had its home in the libntp/systime.c file. 
        !           458:  *
        !           459:  * It has been shamelessly moved to here and has been modified for the
        !           460:  * purposes of the current simulator.
        !           461:  */
        !           462: 
        !           463: 
        !           464: /*
        !           465:  * get_systime - return the system time in NTP timestamp format 
        !           466:  */
        !           467: void
        !           468: get_systime(
        !           469:     l_fp *now          /* current system time in l_fp */        )
        !           470: {
        !           471:     /*
        !           472:      * To fool the code that determines the local clock precision,
        !           473:      * we advance the clock a minimum of 200 nanoseconds on every
        !           474:      * clock read. This is appropriate for a typical modern machine
        !           475:      * with nanosecond clocks. Note we make no attempt here to
        !           476:      * simulate reading error, since the error is so small. This may
        !           477:      * change when the need comes to implement picosecond clocks.
        !           478:      */
        !           479:     if (simclock.local_time == simclock.last_read_time)
        !           480:         simclock.local_time += 200e-9;
        !           481: 
        !           482:     simclock.last_read_time = simclock.local_time;
        !           483:     DTOLFP(simclock.local_time, now);
        !           484: /* OLD Code
        !           485:    if (ntp_node.ntp_time == ntp_node.last_time)
        !           486:    ntp_node.ntp_time += 200e-9;
        !           487:    ntp_node.last_time = ntp_node.ntp_time;
        !           488:    DTOLFP(ntp_node.ntp_time, now);
        !           489: */
        !           490: }
        !           491:  
        !           492:  
        !           493: /*
        !           494:  * adj_systime - advance or retard the system clock exactly like the
        !           495:  * real thng.
        !           496:  */
        !           497: int                            /* always succeeds */
        !           498: adj_systime(
        !           499:     double now         /* time adjustment (s) */
        !           500:     )
        !           501: {
        !           502:     struct timeval adjtv;      /* new adjustment */
        !           503:     double     dtemp;
        !           504:     long       ticks;
        !           505:     int        isneg = 0;
        !           506: 
        !           507:     /*
        !           508:      * Most Unix adjtime() implementations adjust the system clock
        !           509:      * in microsecond quanta, but some adjust in 10-ms quanta. We
        !           510:      * carefully round the adjustment to the nearest quantum, then
        !           511:      * adjust in quanta and keep the residue for later.
        !           512:      */
        !           513:     dtemp = now + sys_residual;
        !           514:     if (dtemp < 0) {
        !           515:        isneg = 1;
        !           516:        dtemp = -dtemp;
        !           517:     }
        !           518:     adjtv.tv_sec = (long)dtemp;
        !           519:     dtemp -= adjtv.tv_sec;
        !           520:     ticks = (long)(dtemp / sys_tick + .5);
        !           521:     adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
        !           522:     dtemp -= adjtv.tv_usec / 1e6;
        !           523:     sys_residual = dtemp;
        !           524: 
        !           525:     /*
        !           526:      * Convert to signed seconds and microseconds for the Unix
        !           527:      * adjtime() system call. Note we purposely lose the adjtime()
        !           528:      * leftover.
        !           529:      */
        !           530:     if (isneg) {
        !           531:        adjtv.tv_sec = -adjtv.tv_sec;
        !           532:        adjtv.tv_usec = -adjtv.tv_usec;
        !           533:        sys_residual = -sys_residual;
        !           534:     }
        !           535:     simclock.adj = now;
        !           536: /*     ntp_node.adj = now; */
        !           537:     return (1);
        !           538: }
        !           539:  
        !           540:  
        !           541: /*
        !           542:  * step_systime - step the system clock. We are religious here.
        !           543:  */
        !           544: int                            /* always succeeds */
        !           545: step_systime(
        !           546:     double now         /* step adjustment (s) */
        !           547:     )
        !           548: {
        !           549: #ifdef DEBUG
        !           550:     if (debug)
        !           551:        printf("step_systime: time %.6f adj %.6f\n",
        !           552:               simclock.local_time, now);
        !           553: #endif
        !           554:     simclock.local_time += now;
        !           555:     return (1);
        !           556: }
        !           557:  
        !           558: /*
        !           559:  * gauss() - returns samples from a gaussion distribution
        !           560:  */
        !           561: double                         /* Gaussian sample */
        !           562: gauss(
        !           563:     double m,          /* sample mean */
        !           564:     double s           /* sample standard deviation (sigma) */
        !           565:     )
        !           566: {
        !           567:     double q1, q2;
        !           568: 
        !           569:     /*
        !           570:      * Roll a sample from a Gaussian distribution with mean m and
        !           571:      * standard deviation s. For m = 0, s = 1, mean(y) = 0,
        !           572:      * std(y) = 1.
        !           573:      */
        !           574:     if (s == 0)
        !           575:         return (m);
        !           576:     while ((q1 = drand48()) == 0);
        !           577:     q2 = drand48();
        !           578:     return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2));
        !           579: }
        !           580: 
        !           581:  
        !           582: /*
        !           583:  * poisson() - returns samples from a network delay distribution
        !           584:  */
        !           585: double                         /* delay sample (s) */
        !           586: poisson(
        !           587:     double m,          /* fixed propagation delay (s) */
        !           588:     double s           /* exponential parameter (mu) */
        !           589:     )
        !           590: {
        !           591:     double q1;
        !           592: 
        !           593:     /*
        !           594:      * Roll a sample from a composite distribution with propagation
        !           595:      * delay m and exponential distribution time with parameter s.
        !           596:      * For m = 0, s = 1, mean(y) = std(y) = 1.
        !           597:      */
        !           598:     if (s == 0)
        !           599:         return (m);
        !           600:     while ((q1 = drand48()) == 0);
        !           601:     return (m - s * log(q1 * s));
        !           602: }
        !           603: 
        !           604: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>