📄 dnsresolver.cxx
字号:
/* ==================================================================== * The Vovida Software License, Version 1.0 * * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names "VOCAL", "Vovida Open Communication Application Library", * and "Vovida Open Communication Application Library (VOCAL)" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor * may "VOCAL" appear in their name, without prior written * permission of Vovida Networks, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF ,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ==================================================================== * * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc. For more information on Vovida Networks, Inc., please see * <http://www.vovida.org/>. * */static const char* const DnsResolver_cxx_Version = "$Id: DnsResolver.cxx,v 1.4 2001/05/17 22:09:20 wbreu Exp $";#include "vtypes.h"#include "NetworkAddress.h"#include "DnsResolver.hxx" const int MY_PACKETSZ = 64*1024; // space to hold tcp answersconst int DEFAULT_PRIO= 10; const int DEFAULT_WT = 10;// constructor for testing: default myQType to SRV lookupDnsResolver::DnsResolver(const char * target) : myReady(0), myNumDns(0), myCurIdx(0), myQType(ns_t_srv){ assert( target != 0 ); myTarget.assign(target); myQName.assign(target); (void) res_init(); // init resolve package}DnsResolver::DnsResolver(const char * target, int qType, const char * serviceType, const char* protocol): myReady(false), myNumDns(0), myCurIdx(0), myQType(qType){ assert( target != 0); myTarget.assign(target); if (qType == ns_t_a) // A record type { myQName.assign(target); } else // assume SRV record type { string s = ""; string p = ""; if (serviceType) { cpLog(LOG_DEBUG, "serviceType = %s", serviceType); s = serviceType; s+= "."; } if (protocol) { cpLog(LOG_DEBUG, "protocol = %s", protocol); p = protocol; p+= "."; } s += p; cpLog(LOG_DEBUG, "s+p = %s", s.c_str()); s += target; cpLog(LOG_DEBUG, "s+p+target = %s", s.c_str()); myQName.assign( s ); } cpLog(LOG_DEBUG, "myQName = %s", myQName.c_str()); (void) res_init(); // init resolve package dnsLookUp(); } // DnsResolver///DnsResolver::~DnsResolver(){ // deallocate memory cpLog( LOG_DEBUG, "entered DnsResolver destructor"); clear();}// This method is called on object instantiation and whenever the// user wants to refresh the local dns cache.void DnsResolver::dnsLookUp(){ if (myReady) { clear(); // clean up local cache } findRecords(); // do the dns lookup int num = myVDns.size(); if ((num == 0) && (myQType == ns_t_srv)) { cpLog( LOG_DEBUG, "no srv records, try finding A records:"); // reset type to A record, and use domain name instead myQType = ns_t_a; myQName.assign(myTarget); findRecords(); } int numRec = myVDns.size(); if ((isReady()) && (numRec > 1)) { loadBalance(); } else if (numRec == 1) { cpLog( LOG_DEBUG, "dnsLookUp() - no loadbalancing done"); } else { cpLog(LOG_ERR, "dnsLookUp() not complete: DnsResolver obj malformed!"); } } // dnsLookUp// shuffle the ordering of the list of Dns records based on priorities// and weights. Note that if this object contains a list of A records,// then all entries have the same default priority (10) and weight (10).void DnsResolver::reOrder(){ myCurIdx = 0; // reset the index pointer if (myReady) { loadBalance(); } else { cpLog( LOG_DEBUG, "DnsResolver object is not well formed, reOrder not done!"); }} // reOrder// Sptr<DnsRecord> * /* VECTOR_DNS::iterator */ DnsResolver::getRecord( int idx ){ if ((idx < 0) || (idx >= myNumDns)) { cpLog(LOG_DEBUG, "getRecord() fails: bad index %d", idx); return myVDns.end(); } return(&(myVDns[idx]));}// get the record (SRV or A) indexed by myCurIdx:bool DnsResolver::getNextRecord( DnsRecord& rec ){ if (myReady == false) { cpLog( LOG_DEBUG, "cannot get next Dns record: DnsResolver obj not well formed!"); return false; } if (myCurIdx >= myNumDns) { cpLog( LOG_DEBUG, "list of Dns records exhausts"); // user may want to call reOrder() to generate a different // ordered list and call getNextRecord() again return false; } // return a reference of myVDns[myCurIdx], and advance myCurIdx rec = *(myVDns[myCurIdx++]); return true;} // getNextRecord()// bool DnsResolver::selectRecord( const string& callId, DnsRecord& rec ){ return false;}int DnsResolver::getHostByRecord( const DnsRecord& rec, struct hostent* hEnt, char* buf, int buflen ){ int rtn = 0; int nsErr = 0; const char * host = rec.getTarget(); // pre-conditions checks: assert( hEnt ); assert( buf ); assert( buflen ); rtn = NetworkAddress::getHostByName( host, hEnt, buf, buflen, &nsErr ); if (rtn != 0) { nsError( nsErr, host ); return rtn; } return rtn;} // getHostByRecord///voidDnsResolver::clear(){ if (myReady == true) { // leave myQName and myQType as is myVDns.clear(); myNumDns = 0; myCurIdx = 0; myReady = false; } } // clear()/** * */voidDnsResolver::nsError( int error, const char* domain ){ switch(error){ case HOST_NOT_FOUND: cpLog(LOG_DEBUG, "Unknown domain: %s\n", domain); break; case NO_DATA: // same as NO_ADDRESS cpLog(LOG_DEBUG, "No DNS records for %s\n", domain); break; case NO_RECOVERY: cpLog(LOG_DEBUG, "non-recoverable error occurs during nameserver lookup for %s\n", domain); break; case TRY_AGAIN: cpLog(LOG_DEBUG, "No response for DNS query\n"); break; default: cpLog(LOG_DEBUG, "Unexpected error=%d, domain=%s\n", error, domain); break; }} // end of nsError()/** * locate the DNS records */boolDnsResolver::findRecords(){ union { HEADER hdr; /* defined in resolv.h */ /* next line changed NS_PACKETSZ to PACKETSZ */ u_char buf[PACKETSZ]; /* defined in arpa/nameser.h */ } response; /* response buffers */ int responseLen; /* buffer length */ ns_msg handle; /* handle for response packet */ char* domain = (char*)myQName.c_str(); // seed the random number generator // **************** TBD: don't use srand struct timeval t; gettimeofday(&t, 0); srand( (unsigned int)(t.tv_usec ^ t.tv_sec) ); // Ref: "DNS and BIND" book // Look up the SRV records for the given domain name. cpLog(LOG_DEBUG, "Domain is %s\n",domain); if((responseLen = res_search(domain, /* the domain we care about */ ns_c_in, /* Internet class records */ myQType, /* ns_t_srv or ns_t_a */ (u_char *)&response, /* response buffer */ sizeof(response))) /* buffer size */ < 0) /* If negative */ { nsError(h_errno, domain); /* report the error */ return false; /* and quit */ } /* Initialize a handle to this response. The handle will * be used to extract information from the response. */ if (ns_initparse(response.buf, responseLen, &handle) < 0) { cpLog(LOG_INFO, "ns_initparse: %s\n",strerror(errno)); return false; }; // place records found in a vector, myVSrv: // search result from the answer section buildRecords(handle, ns_s_an, responseLen); // sort records based on the priority of the srv records // records having the same priority: if (myVDns.size() > 1) { sortByPreference(); } return myReady; } // findRecords()/** * Load balancing algorithm based on the weight. assume a list of SRV records in myVDns having the same priority, find that range: 1) add up all weights within the range = s 2) pick a random number between 0..1 = r 3) calculate the random weight, rw = r*s 4) the weight of records partitions sumOfWeights: what part does the random weight fall into? (find that record, rrd) Let current sum of weight so far, cs = 0 Loop all records w/i the priority range: given weight of current record, cw: cs +=cw; if rw <= cw swap out current record with rrd; break from loop else continue to loop */void DnsResolver::loadBalance( ){ cpLog( LOG_DEBUG, "\nloadBalance(): \n" ); if (myVDns.size() <= 1) // don't bother for single record { return; } VECTOR_DNS::iterator i = myVDns.begin(); int prio; int startIdx, endIdx; endIdx = -1; // end of previous range while (i != myVDns.end()) { prio = (*i)->getPriority(); startIdx = endIdx+1; // start of current range endIdx = findPriorityRange( startIdx); // let's find all srv records of same priority if (startIdx == endIdx) { cpLog(LOG_DEBUG, "range of 1 found for priority=", prio); i++; } else { // sort same priority range by weight: sortByWeight( startIdx, endIdx ); // advance iterator to first element after endIdx: int n = endIdx - startIdx + 1; advance(i,n); } } print( LOG_DEBUG );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -