Annotation of embedaddon/ntp/ntpd/ntpsim.c, revision 1.1.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>