home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xntp3.zip / xntpd / ntp_peer.c < prev    next >
C/C++ Source or Header  |  1992-08-02  |  14KB  |  647 lines

  1. /*
  2.  * ntp_peer.c - management of data maintained for peer associations
  3.  */
  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8.  
  9. #include "ntp_syslog.h"
  10. #include "ntp_fp.h"
  11. #include "ntp.h"
  12.  
  13. /*
  14.  * These routines manage the allocation of memory to peer structures
  15.  * and the maintenance of the peer hash table.  The two main entry
  16.  * points are findpeer(), which looks for corresponding peer data
  17.  * in the peer list, newpeer(), which allocates a new peer structure
  18.  * and adds it to the list, and unpeer(), which demobilizes the association
  19.  * and deallocates the structure.
  20.  */
  21.  
  22. /*
  23.  * The peer hash table (imported by the protocol module).
  24.  */
  25. struct peer *peer_hash[HASH_SIZE];
  26. int peer_hash_count[HASH_SIZE];        /* count of peers in each bucket */
  27.  
  28. /*
  29.  * The association ID hash table.  Used for lookups by association ID
  30.  */
  31. struct peer *assoc_hash[HASH_SIZE];
  32. int assoc_hash_count[HASH_SIZE];
  33.  
  34. /*
  35.  * The free list.  Clean structures only, please.
  36.  */
  37. struct peer *peer_free;
  38. int peer_free_count;
  39.  
  40. /*
  41.  * Association ID.  We initialize this value randomly, the assign a new
  42.  * value every time the peer structure is incremented.
  43.  */
  44. u_short current_association_ID;
  45.  
  46. /*
  47.  * Memory allocation watermarks.
  48.  */
  49. #define    INIT_PEER_ALLOC        15    /* initialize space for 15 peers */
  50. #define    INC_PEER_ALLOC        5    /* when we run out, add 5 more */
  51.  
  52. /*
  53.  * Miscellaneous statistic counters which may be queried.
  54.  */
  55. u_long peer_timereset;        /* time stat counters were zeroed */
  56. u_long findpeer_calls;        /* number of calls to findpeer */
  57. u_long assocpeer_calls;        /* number of calls to findpeerbyassoc */
  58. u_long peer_allocations;    /* number of allocations from the free list */
  59. u_long peer_demobilizations;    /* number of structs freed to free list */
  60. int total_peer_structs;        /* number of peer structs in circulation */
  61.  
  62. /*
  63.  * default interface.  Imported from the io module.
  64.  */
  65. extern struct interface *any_interface;
  66.  
  67. /*
  68.  * Timer queue and current time.  Imported from the timer module.
  69.  */
  70. extern u_long current_time;
  71. extern struct event timerqueue[];
  72.  
  73. /*
  74.  * Our initial allocation of peer space
  75.  */
  76. static struct peer init_peer_alloc[INIT_PEER_ALLOC];
  77.  
  78. /*
  79.  * Initialization data.  When configuring peers at initialization time,
  80.  * we try to get their poll update timers initialized to different values
  81.  * to prevent us from sending big clumps of data all at once.
  82.  */
  83. u_long init_peer_starttime;
  84. extern int initializing;
  85. extern int debug;
  86.  
  87.  
  88. /*
  89.  * init_peer - initialize peer data structures and counters
  90.  *
  91.  * N.B. We use the random number routine in here.  It had better be
  92.  *      initialized prior to getting here.
  93.  */
  94. void
  95. init_peer()
  96. {
  97.     register int i;
  98.     extern u_long ranp2();
  99.  
  100.     /*
  101.      * Clear hash table and counters.
  102.      */
  103.     for (i = 0; i < HASH_SIZE; i++) {
  104.         peer_hash[i] = 0;
  105.         peer_hash_count[i] = 0;
  106.         assoc_hash[i] = 0;
  107.         assoc_hash_count[i] = 0;
  108.     }
  109.  
  110.     /*
  111.      * Clear stat counters
  112.      */
  113.     findpeer_calls = peer_allocations = 0;
  114.     assocpeer_calls = peer_demobilizations = 0;
  115.  
  116.     /*
  117.      * Initialization counter.
  118.      */
  119.     init_peer_starttime = 0;
  120.  
  121.     /*
  122.      * Initialize peer memory.
  123.      */
  124.     peer_free = 0;
  125.     for (i = 0; i < INIT_PEER_ALLOC; i++) {
  126.         init_peer_alloc[i].next = peer_free;
  127.         peer_free = &init_peer_alloc[i];
  128.     }
  129.     total_peer_structs = INIT_PEER_ALLOC;
  130.     peer_free_count = INIT_PEER_ALLOC;
  131.  
  132.     /*
  133.      * Initialize our first association ID
  134.      */
  135.     current_association_ID = (u_short)ranp2(16);
  136.     if (current_association_ID == 0)
  137.         current_association_ID = 1;
  138. }
  139.  
  140.  
  141.  
  142. /*
  143.  * getmorepeermem - add more peer structures to the free list
  144.  */
  145. void
  146. getmorepeermem()
  147. {
  148.     register int i;
  149.     register struct peer *peer;
  150.     extern char *emalloc();
  151.  
  152.     peer = (struct peer *)emalloc(INC_PEER_ALLOC*sizeof(struct peer));
  153.     for (i = 0; i < INC_PEER_ALLOC; i++) {
  154.         peer->next = peer_free;
  155.         peer_free = peer;
  156.         peer++;
  157.     }
  158.  
  159.     total_peer_structs += INC_PEER_ALLOC;
  160.     peer_free_count += INC_PEER_ALLOC;
  161. }
  162.  
  163.  
  164.  
  165. /*
  166.  * findexistingpeer - return a pointer to a peer in the hash table
  167.  */
  168. struct peer *
  169. findexistingpeer(addr, start_peer)
  170.     struct sockaddr_in *addr;
  171.     struct peer *start_peer;
  172. {
  173.     register struct peer *peer;
  174.  
  175.     /*
  176.      * start_peer is included so we can locate instances of the
  177.      * same peer through different interfaces in the hash table.
  178.      */
  179.     if (start_peer == 0)
  180.         peer = peer_hash[HASH_ADDR(addr)];
  181.     else
  182.         peer = start_peer->next;
  183.     
  184.     while (peer != 0) {
  185.         if (NSRCADR(addr) == NSRCADR(&peer->srcadr)
  186.             && NSRCPORT(addr) == NSRCPORT(&peer->srcadr))
  187.             return peer;
  188.         peer = peer->next;
  189.     }
  190.  
  191.     return (struct peer *)0;
  192. }
  193.  
  194.  
  195. /*
  196.  * findpeer - find and return a peer in the hash table.
  197.  */
  198. struct peer *
  199. findpeer(srcadr, dstadr)
  200.     struct sockaddr_in *srcadr;
  201.     struct interface *dstadr;
  202. {
  203.     register struct peer *any_inter_peer;
  204.     register struct peer *peer;
  205.     int hash;
  206.     extern char *ntoa();
  207.  
  208.     findpeer_calls++;
  209.  
  210.     any_inter_peer = 0;
  211.     hash = HASH_ADDR(srcadr);
  212.     for (peer = peer_hash[hash]; peer != 0; peer = peer->next) {
  213.         if (NSRCADR(srcadr) == NSRCADR(&peer->srcadr)
  214.             && NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) {
  215.             if (peer->dstadr == dstadr)
  216.                 return peer;    /* got it! */
  217.             if (peer->dstadr == any_interface) {
  218.                 /*
  219.                  * We shouldn't have more than one
  220.                  * instance of the peer in the table,
  221.                  * but I don't trust this.  Save this
  222.                  * one for later and continue search.
  223.                  */
  224.                 if (any_inter_peer == 0)
  225.                     any_inter_peer = peer;
  226.                 else
  227.                     syslog(LOG_ERR,
  228.         "two instances of default interface for %s in hash table",
  229.                         ntoa(srcadr));
  230.             }
  231.         }
  232.     }
  233.  
  234.     /*
  235.      * If we didn't find the specific peer but found a wild card,
  236.      * modify the interface and return him.
  237.      */
  238.     if (any_inter_peer != 0) {
  239.         any_inter_peer->dstadr = dstadr;
  240.         return any_inter_peer;
  241.     }
  242.  
  243.     /*
  244.      * Out of luck.  Return 0.
  245.      */
  246.     return (struct peer *)0;
  247. }
  248.  
  249. /*
  250.  * findpeerbyassocid - find and return a peer using his association ID
  251.  */
  252. struct peer *
  253. findpeerbyassoc(assoc)
  254.     int assoc;
  255. {
  256.     register struct peer *peer;
  257.     int hash;
  258.     extern char *ntoa();
  259.  
  260.     assocpeer_calls++;
  261.  
  262.     hash = assoc & HASH_MASK;
  263.     for (peer = assoc_hash[hash]; peer != 0; peer = peer->ass_next) {
  264.         if ((u_short)assoc == peer->associd)
  265.             return peer;    /* got it! */
  266.     }
  267.  
  268.     /*
  269.      * Out of luck.  Return 0.
  270.      */
  271.     return (struct peer *)0;
  272. }
  273.  
  274. /*
  275.  * unpeer - remove peer structure from hash table and free structure
  276.  */
  277. void
  278. unpeer(peer_to_remove)
  279.     struct peer *peer_to_remove;
  280. {
  281.     int hash;
  282.     char *ntoa();
  283. #ifdef REFCLOCK
  284.     extern void refclock_unpeer();
  285. #endif
  286.  
  287.     hash = HASH_ADDR(&peer_to_remove->srcadr);
  288.     peer_hash_count[hash]--;
  289.     peer_demobilizations++;
  290.  
  291. #ifdef REFCLOCK
  292.     /*
  293.      * If this peer is actually a clock, shut it down first
  294.      */
  295.     if (peer_to_remove->flags & FLAG_REFCLOCK)
  296.         refclock_unpeer(peer_to_remove);
  297. #endif
  298.  
  299.     if (peer_hash[hash] == peer_to_remove)
  300.         peer_hash[hash] = peer_to_remove->next;
  301.     else {
  302.         register struct peer *peer;
  303.  
  304.         peer = peer_hash[hash];
  305.         while (peer != 0 && peer->next != peer_to_remove)
  306.             peer = peer->next;
  307.         
  308.         if (peer == 0) {
  309.             peer_hash_count[hash]++;
  310.             syslog(LOG_ERR, "peer struct for %s not in table!",
  311.                 ntoa(&peer->srcadr));
  312.         } else {
  313.             peer->next = peer_to_remove->next;
  314.         }
  315.     }
  316.  
  317.     /*
  318.      * Remove him from the association hash as well.
  319.      */
  320.     hash = peer_to_remove->associd & HASH_MASK;
  321.     assoc_hash_count[hash]--;
  322.     if (assoc_hash[hash] == peer_to_remove)
  323.         assoc_hash[hash] = peer_to_remove->ass_next;
  324.     else {
  325.         register struct peer *peer;
  326.  
  327.         peer = assoc_hash[hash];
  328.         while (peer != 0 && peer->ass_next != peer_to_remove)
  329.             peer = peer->ass_next;
  330.         
  331.         if (peer == 0) {
  332.             assoc_hash_count[hash]++;
  333.             syslog(LOG_ERR,
  334.                 "peer struct for %s not in association table!",
  335.                 ntoa(&peer->srcadr));
  336.         } else {
  337.             peer->ass_next = peer_to_remove->ass_next;
  338.         }
  339.     }
  340.  
  341.     TIMER_DEQUEUE(&peer_to_remove->event_timer);
  342.  
  343.     peer_to_remove->next = peer_free;
  344.     peer_free = peer_to_remove;
  345.     peer_free_count++;
  346. }
  347.  
  348.  
  349. /*
  350.  * peer_config - configure a new peer
  351.  */
  352. struct peer *
  353. peer_config(srcadr, dstadr, hmode, version, key, flags)
  354.     struct sockaddr_in *srcadr;
  355.     struct interface *dstadr;
  356.     int hmode;
  357.     int version;
  358.     u_long key;
  359.     int flags;
  360. {
  361.     register struct peer *peer;
  362.     struct peer *findexistingpeer();
  363.     struct peer *newpeer();
  364.     extern char *ntoa();
  365.  
  366. #ifdef DEBUG
  367.     if (debug)
  368.         printf("peer_config: addr %s mode %d version %d key %u\n",
  369.             ntoa(srcadr), hmode, version, key);
  370. #endif
  371.     /*
  372.      * See if we have this guy in the tables already.  If
  373.      * so just mark him configured.
  374.      */
  375.     peer = findexistingpeer(srcadr, (struct peer *)0);
  376.     if (dstadr != 0) {
  377.         while (peer != 0) {
  378.             if (peer->dstadr == dstadr)
  379.                 break;
  380.             peer = findexistingpeer(srcadr, peer);
  381.         }
  382.     }
  383.  
  384.     /*
  385.      * Torque the flags to make sure they're valid
  386.      */
  387.     flags &= (FLAG_AUTHENABLE|FLAG_MINPOLL|FLAG_PREFER);
  388.  
  389.     /*
  390.      * If we found one, just change his mode and mark him configured.
  391.      */
  392.     if (peer != 0) {
  393.         peer->hmode = hmode;
  394.         peer->flags = ((u_char)(flags|FLAG_CONFIG))
  395.             |(peer->flags & (FLAG_REFCLOCK|FLAG_DEFBDELAY));
  396.         peer->keyid = key;
  397.         return peer;
  398.     }
  399.  
  400.     /*
  401.      * If we're here this guy is unknown to us.  Make a new peer
  402.      * structure for him.
  403.      */
  404.     peer = newpeer(srcadr, dstadr, hmode, version, key);
  405.     if (peer != 0)
  406.         peer->flags |= (u_char)(flags|FLAG_CONFIG);
  407.     return peer;
  408. }
  409.  
  410.  
  411. /*
  412.  * newpeer - initialize a new peer association
  413.  */
  414. struct peer *
  415. newpeer(srcadr, dstadr, hmode, version, key)
  416.     struct sockaddr_in *srcadr;
  417.     struct interface *dstadr;
  418.     int hmode;
  419.     int version;
  420.     u_long key;
  421. {
  422.     register struct peer *peer;
  423.     register int i;
  424.     extern struct interface *findbcastinter();
  425.     extern void transmit();
  426. #ifdef REFCLOCK
  427.     extern int refclock_newpeer();
  428. #endif
  429.  
  430.     /*
  431.      * Some dirt here.  Some of the initialization requires
  432.      * knowlege of our system state.
  433.      */
  434.     extern u_long sys_bdelay;
  435.     extern long sys_clock;
  436.     
  437.     if (peer_free_count == 0)
  438.         getmorepeermem();
  439.  
  440.     peer = peer_free;
  441.     peer_free = peer->next;
  442.     peer_free_count--;
  443.  
  444.     /*
  445.      * Initialize the structure.  This stuff is sort of part of
  446.      * the receive procedure and part of the clear procedure rolled
  447.      * into one.
  448.      *
  449.      * Zero the whole thing for now.  We might be pickier later.
  450.      */
  451.     bzero((char *)peer, sizeof(struct peer));
  452.  
  453.     peer->srcadr = *srcadr;
  454.     if (dstadr != 0)
  455.         peer->dstadr = dstadr;
  456.     else if (hmode == MODE_BROADCAST)
  457.         peer->dstadr = findbcastinter(srcadr);
  458.     else
  459.         peer->dstadr = any_interface;
  460.     peer->hmode = (u_char)hmode;
  461.     peer->keyid = key;
  462.  
  463.     if (hmode == MODE_BCLIENT) {
  464.         peer->estbdelay = sys_bdelay;
  465.         peer->flags |= FLAG_DEFBDELAY;
  466.     }
  467.  
  468.     peer->leap = LEAP_NOTINSYNC;
  469.     peer->hpoll = NTP_MINPOLL;
  470.     peer->precision = DEFPRECISION;
  471.     peer->version = (u_char)version;
  472.     peer->dispersion = NTP_MAXDISPERSE;
  473.     peer->stratum = STRATUM_UNSPEC;
  474.     peer->update = sys_clock;
  475.  
  476.     for (i = 0; i < NTP_SHIFT; i++) {
  477.         peer->filter_order[i] = i;
  478.         peer->filter_error[i] = NTP_MAXDISPERSE;
  479.     }
  480.  
  481.     /*
  482.      * Assign him an association ID and increment the system variable
  483.      */
  484.     peer->associd = current_association_ID;
  485.     if (++current_association_ID == 0)
  486.         ++current_association_ID;
  487.  
  488.     /*
  489.      * Note time on statistics timers.
  490.      */
  491.     peer->timereset = current_time;
  492.     peer->timereachable = current_time;
  493.     peer->timereceived = current_time;
  494.  
  495. #ifdef REFCLOCK
  496.     if (ISREFCLOCKADR(&peer->srcadr)) {
  497.         /*
  498.          * We let the reference clock support do clock
  499.          * dependent initialization.  This includes setting
  500.          * the peer timer, since the clock may have requirements
  501.          * for this.
  502.          */
  503.         if (!refclock_newpeer(peer)) {
  504.             /*
  505.              * Dump it, something screwed up
  506.              */
  507.             peer->next = peer_free;
  508.             peer_free = peer;
  509.             peer_free_count++;
  510.             return 0;
  511.         }
  512.     } else {
  513. #endif
  514.     /*
  515.      * Set up timer.  If initializing, just make sure we start polling
  516.      * in different 4 second intervals.
  517.      */
  518.     peer->event_timer.peer = peer;
  519.     peer->event_timer.event_handler = transmit;
  520.  
  521.     if (initializing) {
  522.         init_peer_starttime += (1<<EVENT_TIMEOUT);
  523.         if (init_peer_starttime >= (1<<NTP_MINPOLL))
  524.             init_peer_starttime = (1<<EVENT_TIMEOUT);
  525.         peer->event_timer.event_time = init_peer_starttime;
  526.     } else {
  527.         /*
  528.          * First expiry is set to 32 seconds from now.
  529.          */
  530.         peer->event_timer.event_time
  531.             = (1 << (NTP_MINPOLL-1)) + current_time;
  532.     }
  533.     TIMER_ENQUEUE(timerqueue, &peer->event_timer);
  534. #ifdef REFCLOCK
  535.     }
  536. #endif
  537.  
  538.     /*
  539.      * Put him in the hash tables.
  540.      */
  541.     i = HASH_ADDR(&peer->srcadr);
  542.     peer->next = peer_hash[i];
  543.     peer_hash[i] = peer;
  544.     peer_hash_count[i]++;
  545.  
  546.     i = peer->associd & HASH_MASK;
  547.     peer->ass_next = assoc_hash[i];
  548.     assoc_hash[i] = peer;
  549.     assoc_hash_count[i]++;
  550.  
  551.     return peer;
  552. }
  553.  
  554.  
  555. /*
  556.  * peer_unconfig - remove the configuration bit from a peer
  557.  */
  558. int
  559. peer_unconfig(srcadr, dstadr)
  560.     struct sockaddr_in *srcadr;
  561.     struct interface *dstadr;
  562. {
  563.     register struct peer *peer;
  564.     int num_found;
  565.     struct peer *findexistingpeer();
  566.  
  567.     num_found = 0;
  568.     peer = findexistingpeer(srcadr, (struct peer *)0);
  569.     while (peer != 0) {
  570.         if (peer->flags & FLAG_CONFIG
  571.             && (dstadr == 0 || peer->dstadr == dstadr)) {
  572.             num_found++;
  573.             /*
  574.              * Tricky stuff here.  If the peer is polling us
  575.              * in active mode, turn off the configuration bit
  576.              * and make the mode passive.  This allows us to
  577.              * avoid dumping a lot of history for peers we
  578.              * might choose to keep track of in passive mode.
  579.              * The protocol will eventually terminate undesirables
  580.              * on its own.
  581.              */
  582.             if (peer->hmode == MODE_ACTIVE
  583.                 && peer->pmode == MODE_ACTIVE) {
  584.                 peer->hmode = MODE_PASSIVE;
  585.                 peer->flags &= ~FLAG_CONFIG;
  586.             } else {
  587.                 unpeer(peer);
  588.                 peer = 0;
  589.             }
  590.         }
  591.         peer = findexistingpeer(srcadr, peer);
  592.     }
  593.     return num_found;
  594. }
  595.  
  596.  
  597. /*
  598.  * peer_clr_stats - clear peer module stat counters
  599.  */
  600. void
  601. peer_clr_stats()
  602. {
  603.     findpeer_calls = 0;
  604.     assocpeer_calls = 0;
  605.     peer_allocations = 0;
  606.     peer_demobilizations = 0;
  607.     peer_timereset = current_time;
  608. }
  609.  
  610. /*
  611.  * peer_reset - reset stat counters in a peer structure
  612.  */
  613. void
  614. peer_reset(peer)
  615.     struct peer *peer;
  616. {
  617.     if (peer == 0)
  618.         return;
  619.     peer->sent = 0;
  620.     peer->received = 0;
  621.     peer->processed = 0;
  622.     peer->badauth = 0;
  623.     peer->bogusorg = 0;
  624.     peer->bogusrec = 0;
  625.     peer->bogusdelay = 0;
  626.     peer->oldpkt = 0;
  627.     peer->seldisptoolarge = 0;
  628.     peer->selbroken = 0;
  629.     peer->seltooold = 0;
  630.     peer->timereset = current_time;
  631. }
  632.  
  633.  
  634. /*
  635.  * peer_all_reset - reset all peer stat counters
  636.  */
  637. void
  638. peer_all_reset()
  639. {
  640.     struct peer *peer;
  641.     int hash;
  642.  
  643.     for (hash = 0; hash < HASH_SIZE; hash++)
  644.         for (peer = peer_hash[hash]; peer != 0; peer = peer->next)
  645.             peer_reset(peer);
  646. }
  647.