DnsResolver.cxx
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:23k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

  1. /* ====================================================================
  2.  * The Vovida Software License, Version 1.0 
  3.  * 
  4.  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
  5.  * 
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in
  15.  *    the documentation and/or other materials provided with the
  16.  *    distribution.
  17.  * 
  18.  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
  19.  *    and "Vovida Open Communication Application Library (VOCAL)" must
  20.  *    not be used to endorse or promote products derived from this
  21.  *    software without prior written permission. For written
  22.  *    permission, please contact vocal@vovida.org.
  23.  *
  24.  * 4. Products derived from this software may not be called "VOCAL", nor
  25.  *    may "VOCAL" appear in their name, without prior written
  26.  *    permission of Vovida Networks, Inc.
  27.  * 
  28.  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  29.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
  31.  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
  32.  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
  33.  * IN EXCESS OF ,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
  34.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  35.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  36.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  37.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  38.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  39.  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  40.  * DAMAGE.
  41.  * 
  42.  * ====================================================================
  43.  * 
  44.  * This software consists of voluntary contributions made by Vovida
  45.  * Networks, Inc. and many individuals on behalf of Vovida Networks,
  46.  * Inc.  For more information on Vovida Networks, Inc., please see
  47.  * <http://www.vovida.org/>.
  48.  *
  49.  */
  50. static const char* const DnsResolver_cxx_Version =
  51.     "$Id: DnsResolver.cxx,v 1.4 2001/05/17 22:09:20 wbreu Exp $";
  52. #include "vtypes.h"
  53. #include "NetworkAddress.h"
  54. #include "DnsResolver.hxx"
  55.   
  56. const int MY_PACKETSZ = 64*1024;     // space to hold tcp answers
  57. const int DEFAULT_PRIO= 10;          
  58. const int DEFAULT_WT  = 10;
  59. // constructor for testing: default myQType to SRV lookup
  60. DnsResolver::DnsResolver(const char * target) :
  61.                          myReady(0), myNumDns(0), myCurIdx(0),
  62.                          myQType(ns_t_srv)
  63.     assert( target != 0 );
  64.     myTarget.assign(target);
  65.     myQName.assign(target);
  66.     (void) res_init();   // init resolve package
  67. }
  68. DnsResolver::DnsResolver(const char * target, int qType, 
  69.                          const char * serviceType, const char* protocol):
  70.                          myReady(false), myNumDns(0), myCurIdx(0),
  71.                          myQType(qType)
  72. {
  73.     assert( target != 0);
  74.     myTarget.assign(target);
  75.     if (qType == ns_t_a)      // A record type
  76.     {
  77.         myQName.assign(target);
  78.     }
  79.     else                     // assume SRV record type
  80.     {
  81.         string s = "";
  82.         string p = "";
  83.         if (serviceType)
  84.         {
  85.             cpLog(LOG_DEBUG, "serviceType = %s", serviceType);
  86.             s = serviceType;
  87.             s+= ".";
  88.         }
  89.         if (protocol)
  90.         {
  91.             cpLog(LOG_DEBUG, "protocol = %s", protocol);
  92.             p = protocol;
  93.             p+= ".";
  94.         }
  95.         s += p;
  96.         cpLog(LOG_DEBUG, "s+p = %s", s.c_str());
  97.         s += target;
  98.         cpLog(LOG_DEBUG, "s+p+target = %s", s.c_str());
  99.         myQName.assign( s );
  100.     }
  101.     cpLog(LOG_DEBUG, "myQName = %s", myQName.c_str());
  102.     (void) res_init();   // init resolve package
  103. dnsLookUp(); 
  104. }  // DnsResolver
  105. ///
  106. DnsResolver::~DnsResolver()
  107. {
  108.     //  deallocate memory
  109.     cpLog( LOG_DEBUG, "entered DnsResolver destructor");
  110.     clear();
  111. }
  112. // This method is called on object instantiation and whenever the
  113. // user wants to refresh the local dns cache.
  114. void DnsResolver::dnsLookUp()
  115. {
  116.     if (myReady)
  117.     {
  118.         clear();    // clean up local cache
  119.     }
  120. findRecords();         // do the dns lookup
  121.     int num = myVDns.size();
  122.     if ((num == 0) && (myQType == ns_t_srv))
  123.     {
  124.         cpLog( LOG_DEBUG, "no srv records, try finding A records:");
  125.         // reset type to A record, and use domain name instead
  126.         myQType = ns_t_a;
  127.         myQName.assign(myTarget);
  128.         findRecords();
  129.         
  130.     }
  131.     int numRec = myVDns.size();
  132. if ((isReady()) && (numRec > 1))
  133.     {
  134.         loadBalance();   
  135.     }
  136.     else if (numRec == 1)
  137.     {
  138.         cpLog( LOG_DEBUG, 
  139.                "dnsLookUp() - no loadbalancing done");
  140.     }
  141.     else
  142.     {
  143.         cpLog(LOG_ERR,
  144.               "dnsLookUp() not complete: DnsResolver obj malformed!");
  145.     }
  146.   
  147. }  // dnsLookUp
  148. // shuffle the ordering of the list of Dns records based on priorities
  149. // and weights.  Note that if this object contains a list of A records,
  150. // then all entries have the same default priority (10) and weight (10).
  151. void DnsResolver::reOrder()
  152. {
  153.     myCurIdx = 0;   // reset the index pointer
  154. if (myReady)
  155.     {
  156.         loadBalance();
  157.     }
  158. else
  159.     {
  160.         cpLog( LOG_DEBUG, 
  161.                "DnsResolver object is not well formed, reOrder not done!");
  162.     }
  163. }  // reOrder
  164. // 
  165. Sptr<DnsRecord> *  /* VECTOR_DNS::iterator */ DnsResolver::getRecord( int idx )
  166. {
  167.     if ((idx < 0) || (idx >= myNumDns))
  168.     {
  169.        cpLog(LOG_DEBUG, "getRecord() fails: bad index %d", idx);
  170.        return myVDns.end();
  171.     }
  172.     return(&(myVDns[idx]));
  173. }
  174. // get the record (SRV or A) indexed by myCurIdx:
  175. bool DnsResolver::getNextRecord( DnsRecord& rec )
  176. {
  177.     if (myReady == false)
  178.     {
  179.         cpLog( LOG_DEBUG, 
  180.                "cannot get next Dns record: DnsResolver obj not well formed!");
  181.         return false;
  182.     }
  183.     if (myCurIdx >= myNumDns)
  184. {
  185.         cpLog( LOG_DEBUG,
  186.                "list of Dns records exhausts");
  187. // user may want to call reOrder() to generate a different
  188. // ordered list and call getNextRecord() again
  189.         return false;
  190. }
  191. // return a reference of myVDns[myCurIdx], and advance myCurIdx
  192. rec = *(myVDns[myCurIdx++]);
  193. return true;
  194. }  // getNextRecord()
  195. // 
  196. bool DnsResolver::selectRecord( const string& callId, DnsRecord& rec )
  197. {
  198.     return false;
  199. }
  200. int DnsResolver::getHostByRecord( const DnsRecord& rec, 
  201.                  struct hostent* hEnt, char* buf, int buflen )
  202. {
  203.     int rtn = 0;
  204. int nsErr = 0;
  205. const char * host = rec.getTarget();
  206.     // pre-conditions checks:
  207. assert( hEnt ); 
  208. assert( buf );
  209. assert( buflen );
  210.     rtn = NetworkAddress::getHostByName( host,
  211. hEnt, buf, buflen, &nsErr );
  212. if (rtn != 0)
  213.     {
  214.         nsError( nsErr, host );
  215.         return rtn;
  216.     }
  217. return rtn;
  218. }  // getHostByRecord
  219. ///
  220. void
  221. DnsResolver::clear()
  222. {
  223.     if (myReady == true)
  224. {
  225.         // leave myQName and myQType as is
  226.         myVDns.clear();
  227.         myNumDns = 0;
  228. myCurIdx = 0;
  229.         myReady  = false;
  230. }
  231.     
  232. }   // clear()
  233. /**
  234.  * 
  235.  */
  236. void
  237. DnsResolver::nsError( int error, const char* domain )
  238. {
  239.     switch(error){
  240.         case HOST_NOT_FOUND:
  241.             cpLog(LOG_DEBUG, "Unknown domain: %sn", domain);
  242.         break;   
  243.         case NO_DATA:    // same as NO_ADDRESS
  244.             cpLog(LOG_DEBUG, "No DNS records for %sn", domain);
  245.         break;
  246. case NO_RECOVERY:
  247.     cpLog(LOG_DEBUG, 
  248. "non-recoverable error occurs during nameserver lookup for %sn", 
  249. domain);
  250. break;
  251.         case TRY_AGAIN:
  252.             cpLog(LOG_DEBUG, "No response for DNS queryn");
  253.         break;
  254.         default:
  255.             cpLog(LOG_DEBUG, "Unexpected error=%d, domain=%sn",
  256.                            error, domain);
  257.         break;
  258.     }
  259. }   // end of nsError()
  260. /**
  261.  * locate the DNS records
  262.  */
  263. bool
  264. DnsResolver::findRecords()
  265. {
  266.     union {
  267.        HEADER hdr;              /* defined in resolv.h */
  268.                                 /* next line changed NS_PACKETSZ to PACKETSZ */
  269.        u_char buf[PACKETSZ];    /* defined in arpa/nameser.h */
  270.     } response;                 /* response buffers */
  271.     int responseLen;            /* buffer length */
  272.     ns_msg handle;              /* handle for response packet */
  273.     char* domain = (char*)myQName.c_str();
  274.     // seed the random number generator
  275.     // **************** TBD: don't use srand
  276.     struct timeval t;
  277.     gettimeofday(&t, 0);
  278.     srand( (unsigned int)(t.tv_usec ^ t.tv_sec) );
  279.     // Ref: "DNS and BIND" book
  280.     // Look up the SRV records for the given domain name.    
  281.     cpLog(LOG_DEBUG, "Domain is %sn",domain);
  282.     if((responseLen =
  283.         res_search(domain,  /* the domain we care about */
  284.         ns_c_in,                   /* Internet class records   */
  285.         myQType,                   /* ns_t_srv or ns_t_a       */
  286.         (u_char *)&response,       /* response buffer          */
  287.         sizeof(response)))         /* buffer size              */
  288.                            < 0)    /* If negative              */
  289.     {
  290.         nsError(h_errno, domain);      /* report the error         */
  291.         return false;                  /* and quit                 */
  292.     }
  293.  
  294.     /* Initialize a handle to this response.  The handle will
  295.      * be used to extract information from the response.  */
  296.     if (ns_initparse(response.buf, responseLen, &handle) < 0)
  297.     {
  298.         cpLog(LOG_INFO, "ns_initparse: %sn",strerror(errno));
  299.         return false;
  300.     };
  301.     // place records found in a vector, myVSrv: 
  302. // search result from the answer section
  303.     buildRecords(handle, ns_s_an, responseLen);
  304.     // sort records based on the priority of the srv records
  305.     // records having the same priority:
  306. if (myVDns.size() > 1)
  307.     {
  308.        sortByPreference();
  309.     }
  310.  
  311.     return myReady;
  312.     
  313. }   // findRecords()
  314. /**
  315.  * Load balancing algorithm based on the weight.
  316.   assume a list of SRV records in myVDns having the same
  317.   priority, find that range:
  318.   1) add up all weights within the range = s
  319.   2) pick a random number between 0..1 = r
  320.   3) calculate the random weight, rw = r*s
  321.   4) the weight of records partitions sumOfWeights: what part
  322.      does the random weight fall into? (find that record, rrd)
  323.      Let current sum of weight so far, cs = 0
  324.      Loop all records w/i the priority range:
  325.         given weight of current record, cw: cs +=cw;
  326.         if rw <= cw
  327.            swap out current record with rrd;
  328.            break from loop
  329.         else
  330.            continue to loop
  331.  */
  332. void 
  333. DnsResolver::loadBalance( )
  334. {
  335.  
  336.     cpLog( LOG_DEBUG, "nloadBalance(): n" );
  337. if (myVDns.size() <= 1)   // don't bother for single record
  338. {
  339.        return;
  340. }
  341.     VECTOR_DNS::iterator i = myVDns.begin();
  342.     int prio;
  343.     int startIdx, endIdx;
  344.     endIdx = -1;    // end of previous range
  345.     while (i != myVDns.end())
  346.     {
  347.         prio = (*i)->getPriority();
  348.         startIdx = endIdx+1;     // start of current range
  349.         endIdx = findPriorityRange( startIdx); 
  350.         // let's find all srv records of same priority
  351.         if (startIdx == endIdx) 
  352.         {
  353.             cpLog(LOG_DEBUG, "range of 1 found for priority=",  prio);
  354.             i++;
  355.         }
  356.         else
  357.         {
  358.             // sort same priority range by weight:
  359.             sortByWeight( startIdx, endIdx );
  360.             // advance iterator to first element after endIdx:
  361.             int n  = endIdx - startIdx + 1;
  362.             advance(i,n);
  363.         }
  364.     }
  365.     print( LOG_DEBUG ); 
  366. #if 0
  367.     // **************  debug only   **************
  368.     // applicable for testLoadBalance testcase #4 only:
  369.     myVDns[0]->incrTimesSelected(1);
  370.     myVDns[1]->incrTimesSelected(2);
  371.     myVDns[2]->incrTimesSelected(3);
  372. #endif
  373. }   // loadBalance()
  374. /**
  375.  *  print elements in the myVDns vector
  376.  */
  377. void
  378. DnsResolver::print( int logLevel )
  379. {
  380.    VECTOR_DNS::iterator i;
  381.     if ((logLevel < 0) || (logLevel >= LAST_PRIORITY))
  382.     {
  383.         logLevel = LOG_DEBUG;
  384.     }
  385.     cpLog(logLevel,      "nprio   weight   target:port addressn");
  386.     for (i=myVDns.begin(); i != myVDns.end(); i++)
  387.     {
  388.          cpLog(logLevel, "n%d   %5d  %s:%d  %sn",
  389.                 (*i)->getPriority(), (*i)->getWeight(),
  390.                 (*i)->getTarget(), (*i)->getPort(),
  391. (*i)->getAddress());
  392.     }
  393.  
  394. }   // print()
  395. /**
  396.  *  print myVDns vector including times selected to be 1st, 2nd & 3rd:
  397.  *  ************** use for DEBUG ONLY ***************
  398.  */
  399. void
  400. DnsResolver::printTally(  )
  401. {
  402.    VECTOR_DNS::iterator i;
  403.     cpLog(LOG_DEBUG, "n****** Final tally ******n");
  404.     for (i=myVDns.begin(); i != myVDns.end(); i++)
  405.     {
  406.          (*i)->printTally();
  407.     }
  408.  
  409.         findRecords();
  410. }   // printTally()
  411. /// Build a list and print the DNS response records found 
  412. //
  413. void DnsResolver::buildRecords(ns_msg handle, ns_sect section, int responseLen)
  414. {
  415.     int numRecords = ns_msg_count(handle, section);
  416.     cpLog(LOG_DEBUG, "Response Length is: %dn"
  417.                      "Number of records found: %dn",
  418.                      responseLen, numRecords);
  419.     // for efficiency, reserve capacity of myVDns vector to
  420.     // avoid dynamic reallocation of vector, actual size
  421.     // will be <= capacity (because not all records found
  422.     // will match the Record Class we are looking for: e.g.
  423.     // code will ignore CNAME record
  424.     myVDns.reserve( numRecords );  
  425.     if (myQType == ns_t_srv)
  426. {
  427.         cpLog( LOG_DEBUG, "building SRV records" );
  428.         buildSRVRecords( handle, section, responseLen, numRecords );
  429.     }
  430. else if (myQType == ns_t_a)
  431.     {
  432.         cpLog( LOG_DEBUG, "building A records");
  433.         buildARecords( handle, section, responseLen, numRecords );
  434.     }
  435. else
  436. {
  437.         cpLog( LOG_DEBUG, "don't know how to build record type=%d", myQType );
  438. }
  439. }  // buildRecords
  440. void DnsResolver::buildSRVRecords(ns_msg handle, ns_sect section,
  441.                                   int responseLen, int numRecords)
  442. {
  443.     int rrnum;              /* resource record number */
  444. int rrt;                /* resource record type */
  445.     ns_rr rr;               /* expanded resource record */
  446.     u_char *cp;             /* character point to results (rdata in ns_rr) */
  447.     char name[NS_MAXDNAME]; /* expanded response hostname */
  448.     /* Loop through each record found  */
  449.     for(rrnum = 0; rrnum < numRecords; rrnum++)
  450.     {
  451.         /* Expand the resource record number rrnum into rr.  */
  452.         if (ns_parserr(&handle, section, rrnum, &rr))
  453.         {
  454.             cpLog(LOG_DEBUG, "ns_parserr: %s, skip rr #%dn", 
  455. strerror(errno), rrnum);
  456.             continue;
  457.         }
  458.         rrt = ns_rr_type(rr);
  459. if (rrt != ns_t_srv)
  460.         {
  461.             cpLog(LOG_DEBUG, "skipping record number: %d, type: %d", 
  462. rrnum, rrt);
  463.             continue;
  464.         }
  465.         DnsRecord *rec = new DnsRecord;
  466.         /* Check to see if answer is authoritive */
  467.         if(!ns_msg_getflag(handle,ns_f_aa))
  468.         {
  469.             cpLog(LOG_DEBUG,"Warning: Nameserver is not authoritative.n");
  470.         }
  471.         /* Set cp to point the SRV record.  */
  472.         cp = (u_char *)ns_rr_rdata(rr);
  473.         rec->setPriority( ns_get16(cp) );
  474.         cp += sizeof(u_short);
  475.         rec->setWeight( ns_get16(cp) );
  476.         cp += sizeof(u_short);
  477.         rec->setPort( ns_get16(cp) );
  478.         cp += sizeof(u_short);
  479.         cp = (u_char *)expandName(cp, ns_msg_base(handle), name, sizeof(name));
  480.         rec->setTarget( name );
  481.         struct hostent hEnt;
  482.         char buf[2048];
  483.         if (getHostByRecord( *rec, &hEnt, buf, sizeof(buf))==0)
  484.         {
  485.             unsigned char* addr = (unsigned char*)(hEnt.h_addr_list[0]);
  486.             char addrBuf[1000];
  487.             sprintf(addrBuf, "%d.%d.%d.%d",
  488.                     int(*(addr + 0)),
  489.                     int(*(addr + 1)),
  490.                     int(*(addr + 2)),
  491.                     int(*(addr + 3)) );
  492.             rec->setAddress(addrBuf);
  493.         }
  494.         else
  495.         {
  496.             rec->setAddress("0.0.0.0");
  497.         }
  498.         cpLog(LOG_DEBUG, "Target/address = %s/%s", name,
  499.               rec->getAddress());
  500.         // put record in a multimap
  501.         // mmSrv.insert( make_pair( rec->getPriority, rec ) );  
  502.         // insert record at end of vector
  503.         myVDns.push_back( rec );
  504.         // curious: what is the vector's capacity?
  505.         // cpLog(LOG_DEBUG, "Capacity of myVDns = %d", myVDns.capacity());
  506.         cpLog(LOG_DEBUG, "nSRV Priority field: %dn"
  507.                          "SRV Weight field: %dn"
  508.                          "SRV Port field: %dn"
  509.                          "SRV hostname field: %sn"
  510.                          "Resource Record Type: %dn"
  511.                          "Record Class: %dn"
  512.                          "Resource Record Time To Live (ttl): %dn",
  513.              rec->getPriority(), rec->getWeight(), rec->getPort(),
  514.  name, rrt, ns_rr_class(rr), ns_rr_ttl(rr));
  515.     }
  516.     myNumDns = myVDns.size();
  517.     myReady = true;
  518.     cpLog(LOG_DEBUG, "Number of DNS SRV records = %dn", myNumDns);
  519. }  // buildSRVRecords()
  520. // parse the result of A Record lookup and build a DnsRecord
  521. void DnsResolver::buildARecords(ns_msg handle, ns_sect section,
  522.                                int responseLen, int numRecords)
  523. {
  524.     int rrnum;              /* resource record number */
  525. int rrt;                /* resource record type */
  526.     ns_rr rr;               /* expanded resource record */
  527.     u_char *cp;             /* character point to results (rdata in ns_rr) */
  528.     // char name[NS_MAXDNAME]; /* expanded response hostname */
  529.     /* Loop through each record found  */
  530.     for(rrnum = 0; rrnum < numRecords; rrnum++)
  531.     {
  532.         /* Expand the resource record number rrnum into rr.  */
  533.         if (ns_parserr(&handle, section, rrnum, &rr))
  534.         {
  535.             cpLog(LOG_DEBUG, "ns_parserr: %s, skip rr #%dn", 
  536. strerror(errno), rrnum);
  537.             continue;
  538.         }
  539.         rrt = ns_rr_type(rr);
  540. if (rrt != ns_t_a)
  541.         {
  542.             cpLog(LOG_DEBUG, "skipping record num: %d, type: %d", 
  543. rrnum, rrt);
  544.             continue;
  545.         }
  546.         DnsRecord *rec = new DnsRecord;
  547.         /* Expand the resource record number rrnum into rr.  */
  548.         if (ns_parserr(&handle, section, rrnum, &rr))
  549.         {
  550.             cpLog(LOG_INFO, "ns_parserr: %sn", strerror(errno));
  551.         }
  552.         /* Check to see if answer is authoritive */
  553.         if(!ns_msg_getflag(handle,ns_f_aa))
  554.             cpLog(LOG_INFO,"Warning: Nameserver is not authoritative.n");
  555.         /* Set cp to point the A record.  */
  556.         cp = (u_char *)ns_rr_rdata(rr);
  557. u_int32_t ip4Addr = ns_get32(cp);
  558.         struct in_addr  addr;
  559. // convert ip4 @ to network byte ordering
  560. addr.s_addr = htonl(ip4Addr);
  561. string strAddr = inet_ntoa( addr );
  562. rec->setAddress( strAddr ); 
  563. rec->setPriority( DEFAULT_PRIO );
  564.         rec->setWeight( DEFAULT_WT );
  565. rec->setTarget( myQName );
  566.         cpLog(LOG_DEBUG, "nA Record host: %s, IP4 @: %d(%s), prio: %d, wt: %dn" 
  567. "Resource Record Type: %dn"
  568. "Record Class: %dn"
  569. "Resource Record Time To Live (ttl): %dn",
  570.               myQName.c_str(), ip4Addr, strAddr.c_str(), rec->getPriority(),
  571.   rec->getWeight(), ns_rr_type(rr), ns_rr_class(rr), 
  572.   ns_rr_ttl(rr));
  573.         // insert record at end of vector
  574.         myVDns.push_back( rec );
  575.         // curious: what is the vector's capacity?
  576.         // cpLog(LOG_DEBUG, "Capacity of myVDns = %d", myVDns.capacity());
  577.     }
  578.     myNumDns = myVDns.size();
  579. myReady = true;
  580.     cpLog(LOG_DEBUG, "Number of A records found = %dn", myNumDns);
  581. }  // buildARecords()
  582. /// compare function used to sort the DNS SRV records:
  583. //
  584. struct comp_srv : public binary_function< Sptr <DnsRecord>,
  585.                                           Sptr <DnsRecord>, bool >
  586. {
  587.     bool operator() (Sptr <DnsRecord> iRec1, Sptr <DnsRecord> iRec2)
  588.     {      
  589.          return iRec1->getPriority() < iRec2->getPriority();
  590.     }
  591. };   // comp_srv()
  592. /**
  593.  */
  594. void 
  595. DnsResolver::sortByPreference( )
  596. {
  597.     cpLog( LOG_DEBUG, "nsortByPreference():n(orig order)");
  598. if (myVDns.size() <= 1)
  599.     {
  600.        // no need to sort
  601.        return;
  602. }
  603.     print(LOG_DEBUG_STACK);   
  604.     sort(myVDns.begin(), myVDns.end(), comp_srv());
  605. cpLog( LOG_DEBUG_STACK, "n(new order):" );
  606.     print(LOG_DEBUG_STACK);
  607. }
  608. /**
  609. /// given the start and end indices of the svr vector, sort
  610. // the elements with that range by their weights in a 
  611. // random process
  612.  */
  613. void 
  614. DnsResolver::sortByWeight( int startIdx, int endIdx )
  615. {
  616.     Sptr <DnsRecord> tRec;   // temporary
  617.     cpLog( LOG_DEBUG, "sortByWeight(): startIdx=%d, endIdx=%d", 
  618.            startIdx,endIdx );
  619. if (myVDns.size() <= 1)
  620.     {
  621.        // no need to sort
  622.        return;
  623. }
  624.    int sumOfWeights = addWeights( startIdx,  endIdx );
  625.    if (sumOfWeights == 0)
  626.    {
  627.        cpLog( LOG_DEBUG,  "sum of weights is 0" );         
  628.        return;    // nothing to sort
  629.    }
  630.    int j;
  631.    // calculate the sum of weights
  632.    for (int i = startIdx; i < endIdx; i++)
  633.    {
  634.        sumOfWeights = addWeights( i, endIdx );
  635.        // generate a random weight:
  636.        double randWeight = (double (rand() )/RAND_MAX) * sumOfWeights;
  637.        int curWeight  = 0;    // sum of weights so far
  638.        // traverse each element till the one before the last (endIdx),
  639.        // (if j == endIdx, no need to swap)
  640.        for (j = i; j <= endIdx; j++)
  641.        {
  642.            curWeight += myVDns[j]->getWeight();
  643.            if ( randWeight < curWeight )
  644.            {
  645.                // found element matching the random weight         
  646.                // if randWeight falls on the current start range, skip
  647.            cpLog(LOG_DEBUG_STACK, "randWeight=%d, curWeight=%d, i=%d, j=%d",
  648.                      randWeight, curWeight, i, j );
  649.                break;
  650.            }
  651.        }
  652.        if (j > endIdx)
  653.        {
  654.            j = endIdx;   // make sure j is w/i range
  655.        }
  656.        // swap the selected element w/ the i-th element, this
  657.        // sorts the range
  658.        if (i != j)
  659.        {
  660.            tRec = myVDns[i];
  661.            myVDns[i] = myVDns[j];
  662.            myVDns[j] = tRec;
  663.        }
  664.        // compute sumOfWeights for i+1 through endIdx:
  665.        sumOfWeights -= myVDns[i]->getWeight();  // i th element will not be con-
  666.                                               // sidered in the next iteration
  667.    }
  668. }   // sortByWeight
  669. /**
  670.  *
  671.  */
  672. const u_char*
  673. DnsResolver::expandName(const u_char *cp, const u_char *msg,
  674.             char *name, int namelen)
  675. {
  676.     cpLog( LOG_DEBUG, "expandName()" );
  677.     int n=dn_expand(msg, msg + MY_PACKETSZ, cp, name, namelen - 2);
  678.     if (n < 0)
  679.     {
  680.         return (0);
  681.     }
  682.     if (name[0] == '')
  683.     {
  684.         name[0] = '.';
  685.         name[1] = '';
  686.     }
  687.     return (cp + n);
  688. }   // expandName()
  689. /**
  690.  *  find the range of srv records that shares the same priority:
  691.  *  for A records, we fake the priority, default to 10
  692.  */
  693. int
  694. DnsResolver::findPriorityRange( int startIdx)
  695. {
  696.     cpLog( LOG_INFO, "findPriorityRange()" );
  697.     int length = myVDns.size();
  698.     assert( startIdx < length );
  699.     int endIdx = startIdx+1;
  700.     int prio = myVDns[startIdx]->getPriority();
  701.     cpLog( LOG_DEBUG, "findPriorityRange(): prio=%d, startIdx=%d",
  702.            prio, startIdx );
  703.     while ((endIdx < length) &&(prio == myVDns[endIdx]->getPriority()))
  704.     {
  705.         endIdx++;
  706.     }
  707.     return endIdx-1;
  708. }   // findPriorityRange()
  709. /** calculate the total sum of the weights
  710.  */
  711. int 
  712. DnsResolver::addWeights( int startIdx, int endIdx )
  713. {
  714.     
  715.     int sumOfWeights = 0;
  716.     for (int x = startIdx; x <= endIdx; x++)
  717.     {
  718.         sumOfWeights += myVDns[x]->getWeight();
  719.     }
  720.     return sumOfWeights;
  721. }   // addWeights()