reSIProcate/rutil  9694
DnsStub.cxx
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 //      WINCE -- stl headers have to be defined before standard c headers because of
00006 //      MS non-consistent declaration of time_t. we defined _USE_32BIT_TIME_T
00007 //      in all projects and that solved the issue with beta compiler, however
00008 //      release version messes time_t definition again
00009 #include <set>
00010 #include <vector>
00011 #include <cassert>
00012 
00013 #include "AresCompat.hxx"
00014 
00015 #ifndef WIN32
00016 #ifndef __CYGWIN__
00017 #include <arpa/nameser.h>
00018 #endif
00019 #endif
00020 
00021 #include "rutil/FdPoll.hxx"
00022 #include "rutil/Logger.hxx"
00023 #include "rutil/Socket.hxx"
00024 #include "rutil/compat.hxx"
00025 #include "rutil/BaseException.hxx"
00026 #include "rutil/Data.hxx"
00027 #include "rutil/Inserter.hxx"
00028 #include "rutil/dns/DnsStub.hxx"
00029 #include "rutil/dns/ExternalDns.hxx"
00030 #include "rutil/dns/ExternalDnsFactory.hxx"
00031 #include "rutil/dns/QueryTypes.hxx"
00032 #include "rutil/WinLeakCheck.hxx"
00033 
00034 using namespace resip;
00035 using namespace std;
00036 
00037 #define RESIPROCATE_SUBSYSTEM resip::Subsystem::DNS
00038 
00039 DnsStub::DnsResourceRecordsByPtr DnsStub::Query::Empty;
00040 
00041 DnsStub::NameserverList DnsStub::EmptyNameserverList;
00042 int DnsStub::mDnsTimeout = 0;
00043 int DnsStub::mDnsTries = 0;
00044 unsigned int DnsStub::mDnsFeatures = 0;
00045 
00046 void
00047 DnsResultSink::onLogDnsResult(const DNSResult<DnsHostRecord>& rr)
00048 {
00049    DebugLog (<< rr);
00050 }
00051 
00052 void
00053 DnsResultSink::onLogDnsResult(const DNSResult<DnsAAAARecord>& rr)
00054 {
00055 #if defined(USE_IPV6)
00056    DebugLog (<< rr);
00057 #else
00058    ErrLog(<< "Something called "
00059             "DnsResultSink::onLogDnsResult(const DNSResult<DnsAAAARecord>& rr)"
00060             " when ipv6 support was disabled.");
00061 #endif
00062 }
00063 
00064 void
00065 DnsResultSink::onLogDnsResult(const DNSResult<DnsSrvRecord>& rr)
00066 {
00067    DebugLog (<< rr);
00068 }
00069 
00070 void
00071 DnsResultSink::onLogDnsResult(const DNSResult<DnsNaptrRecord>& rr)
00072 {
00073    DebugLog (<< rr);
00074 }
00075 
00076 void
00077 DnsResultSink::onLogDnsResult(const DNSResult<DnsCnameRecord>& rr)
00078 {
00079    DebugLog (<< rr);
00080 }
00081 
00082 DnsStub::DnsStub(const NameserverList& additional,
00083                  AfterSocketCreationFuncPtr socketFunc,
00084                  AsyncProcessHandler* asyncProcessHandler,
00085                  FdPollGrp *pollGrp) :
00086    mInterruptorHandle(0),
00087    mCommandFifo(&mSelectInterruptor),
00088    mTransform(0),
00089    mDnsProvider(ExternalDnsFactory::createExternalDns()),
00090    mPollGrp(0),
00091    mAsyncProcessHandler(asyncProcessHandler)
00092 {
00093    setPollGrp(pollGrp);
00094 
00095    int retCode = mDnsProvider->init(additional, socketFunc, mDnsTimeout, mDnsTries, mDnsFeatures);
00096    if (retCode != ExternalDns::Success)
00097    {
00098       if (retCode == ExternalDns::BuildMismatch)
00099       {
00100          assert(0);
00101          throw DnsStubException("Library was not build w/ required capabilities(probably USE_IPV6 resip/ares mismatch",
00102                                 __FILE__,__LINE__);
00103       }
00104 
00105       Data err(Data::Take, mDnsProvider->errorMessage(retCode));
00106       ErrLog (<< "Failed to initialize async dns library: " << err);
00107 
00108       throw DnsStubException("Failed to initialize async dns library " + err, __FILE__,__LINE__);
00109    }
00110 }
00111 
00112 DnsStub::~DnsStub()
00113 {
00114    for (set<Query*>::iterator it = mQueries.begin(); it != mQueries.end(); ++it)
00115    {
00116       delete *it;
00117    }
00118 
00119    setPollGrp(0);
00120    delete mDnsProvider;
00121 }
00122 
00123 unsigned int
00124 DnsStub::getTimeTillNextProcessMS()
00125 {
00126     if(mCommandFifo.size() > 0) return 0;
00127     return mDnsProvider->getTimeTillNextProcessMS();
00128 }
00129 
00130 void
00131 DnsStub::buildFdSet(FdSet& fdset)
00132 {
00133    mDnsProvider->buildFdSet(fdset.read, fdset.write, fdset.size);
00134    mSelectInterruptor.buildFdSet(fdset);
00135 }
00136 
00137 void
00138 DnsStub::processFifo()
00139 {
00140    while (mCommandFifo.messageAvailable())
00141    {
00142       Command* command = mCommandFifo.getNext();
00143       command->execute();
00144       delete command;
00145    }
00146 }
00147 
00148 void
00149 DnsStub::process(FdSet& fdset)
00150 {
00151    mSelectInterruptor.process(fdset);
00152    processFifo();
00153    mDnsProvider->process(fdset.read, fdset.write);
00154 }
00155 
00156 void
00157 DnsStub::processTimers()
00158 {
00159    // the fifo is captures as a timer within getTimeTill... above
00160    processFifo();
00161    mDnsProvider->processTimers();
00162 }
00163 
00164 void
00165 DnsStub::cache(const Data& key,
00166                in_addr addr)
00167 {
00168    DnsHostRecord record(key, addr);
00169    mRRCache.updateCacheFromHostFile(record);
00170 }
00171 
00172 void
00173 DnsStub::cache(const Data& key,
00174                const unsigned char* abuf,
00175                int alen)
00176 {
00177 
00178    vector<RROverlay> overlays;
00179 
00180    // skip header
00181    const unsigned char* aptr = abuf + HFIXEDSZ;
00182 
00183    int qdcount = DNS_HEADER_QDCOUNT(abuf); // questions.
00184    for (int i = 0; i < qdcount && aptr; ++i)
00185    {
00186       aptr = skipDNSQuestion(aptr, abuf, alen);
00187    }
00188 
00189    // answers.
00190    int ancount = DNS_HEADER_ANCOUNT(abuf);
00191    for (int i = 0; i < ancount; i++)
00192    {
00193       aptr = createOverlay(abuf, alen, aptr, overlays);
00194    }
00195 
00196    // name server records.
00197    int nscount = DNS_HEADER_NSCOUNT(abuf);
00198    for (int i = 0; i < nscount; i++)
00199    {
00200       aptr = createOverlay(abuf, alen, aptr, overlays, true);
00201    }
00202 
00203    // additional records.
00204    int arcount = DNS_HEADER_ARCOUNT(abuf);
00205    for (int i = 0; i < arcount; i++)
00206    {
00207       aptr = createOverlay(abuf, alen, aptr, overlays);
00208    }
00209 
00210    // sort overlays by type.
00211    sort(overlays.begin(), overlays.end());
00212 
00213    vector<RROverlay>::iterator itLow = lower_bound(overlays.begin(), overlays.end(), *overlays.begin());
00214    vector<RROverlay>::iterator itHigh = upper_bound(overlays.begin(), overlays.end(), *overlays.begin());
00215    while (itLow != overlays.end())
00216    {
00217       mRRCache.updateCache(key, (*itLow).type(), itLow, itHigh);
00218       itLow = itHigh;
00219       if (itHigh != overlays.end())
00220       {
00221          itHigh = upper_bound(itLow, overlays.end(), *itLow);
00222       }
00223    }
00224 }
00225 
00226 void
00227 DnsStub::cacheTTL(const Data& key,
00228                   int rrType,
00229                   int status,
00230                   const unsigned char* abuf,
00231                   int alen)
00232 {
00233    // skip header
00234    const unsigned char* aptr = abuf + HFIXEDSZ;
00235 
00236    int qdcount = DNS_HEADER_QDCOUNT(abuf); // questions.
00237    for (int i = 0; i < qdcount && aptr; ++i)
00238    {
00239       aptr = skipDNSQuestion(aptr, abuf, alen);
00240    }
00241 
00242    vector<RROverlay> overlays;
00243 
00244    // answers.
00245    int ancount = DNS_HEADER_ANCOUNT(abuf);
00246    if (ancount != 0) return;
00247 
00248    // name server records.
00249    int nscount = DNS_HEADER_NSCOUNT(abuf);
00250    if (nscount == 0) return;
00251    vector<RROverlay> soa;
00252    aptr = createOverlay(abuf, alen, aptr, soa);
00253    if(soa.empty())
00254    {
00255       return;
00256    }
00257 
00258    mRRCache.cacheTTL(key, rrType, status, soa[0]);
00259 }
00260 
00261 const unsigned char*
00262 DnsStub::skipDNSQuestion(const unsigned char *aptr,
00263                          const unsigned char *abuf,
00264                          int alen)
00265 {
00266    char *name=0;
00267    int status=0;
00268    long len = 0;
00269 
00270    // Parse the question name.
00271    status = ares_expand_name(aptr, abuf, alen, &name, &len);
00272    if (status != ARES_SUCCESS)
00273    {
00274       throw DnsStubException("Failed DNS preparse", __FILE__, __LINE__);
00275    }
00276    aptr += len;
00277 
00278    // Make sure there's enough data after the name for the fixed part
00279    // of the question.
00280    if (aptr + QFIXEDSZ > abuf + alen)
00281    {
00282       free(name);
00283       throw DnsStubException("Failed DNS preparse", __FILE__, __LINE__);
00284    }
00285 
00286    aptr += QFIXEDSZ;
00287    free(name);
00288    return aptr;
00289 }
00290 
00291 bool
00292 DnsStub::checkDnsChange()
00293 {
00294         return mDnsProvider ? mDnsProvider->checkDnsChange() : false;
00295 }
00296 
00297 bool
00298 DnsStub::supportedType(int type)
00299 {
00300    if(mDnsProvider && mDnsProvider->hostFileLookupLookupOnlyMode())
00301    {
00302       return (T_A == type);
00303    }
00304 #ifdef USE_IPV6
00305    return (T_A == type ||
00306            T_AAAA == type ||
00307            T_NAPTR == type ||
00308            T_SRV == type ||
00309            T_CNAME == type ||
00310            T_SOA == type);
00311 #else
00312    return (T_A == type ||
00313            T_NAPTR == type ||
00314            T_SRV == type ||
00315            T_CNAME == type ||
00316            T_SOA == type);
00317 #endif
00318 }
00319 
00320 const unsigned char*
00321 DnsStub::createOverlay(const unsigned char* abuf,
00322                        const int alen,
00323                        const unsigned char* aptr,
00324                        vector<RROverlay>& overlays,
00325                        bool discard)
00326 {
00327    const unsigned char* rptr = aptr;
00328    char* name = 0;
00329    long len = 0;
00330 
00331    int status = ares_expand_name(aptr, abuf, alen, &name, &len);
00332    if (ARES_SUCCESS != status)
00333    {
00334       throw DnsStubException("Failed overlay creation", __FILE__, __LINE__);
00335    }
00336    free(name);
00337    aptr += len;
00338    int type = DNS_RR_TYPE(aptr);
00339    int dlen = DNS_RR_LEN(aptr);
00340    if (!supportedType(type))
00341    {
00342       aptr += RRFIXEDSZ;
00343       aptr += dlen;
00344       return aptr;
00345    }
00346    // rewind before handing it off to overlay.
00347    aptr -= len;
00348    if (!discard)
00349    {
00350       RROverlay overlay(aptr, abuf, alen);
00351       overlays.push_back(overlay);
00352    }
00353    return rptr + len + RRFIXEDSZ + dlen;
00354 }
00355 
00356 void
00357 DnsStub::removeQuery(Query* query)
00358 {
00359    set<Query*>::iterator it = mQueries.find(query);
00360    if (it != mQueries.end())
00361    {
00362       mQueries.erase(it);
00363    }
00364 }
00365 
00366 void
00367 DnsStub::setResultTransform(ResultTransform* transform)
00368 {
00369    mTransform = transform;
00370 }
00371 
00372 void
00373 DnsStub::removeResultTransform()
00374 {
00375    mTransform = 0;
00376 }
00377 
00378 void 
00379 DnsStub::setPollGrp(FdPollGrp* pollGrp)
00380 {
00381    if(mPollGrp)
00382    {
00383       // unregister our select interruptor
00384       mPollGrp->delPollItem(mInterruptorHandle);
00385       mInterruptorHandle=0;
00386    }
00387 
00388    mPollGrp=pollGrp;
00389 
00390    if (mPollGrp)
00391    {
00392       mInterruptorHandle = mPollGrp->addPollItem(mSelectInterruptor.getReadSocket(), FPEM_Read, &mSelectInterruptor);
00393    }
00394 
00395    mDnsProvider->setPollGrp(mPollGrp);
00396 }
00397 
00398 DnsStub::Query::Query(DnsStub& stub, ResultTransform* transform, ResultConverter* resultConv,
00399                       const Data& target, int rrType,
00400                       bool followCname, int proto, DnsResultSink* s)
00401    : mRRType(rrType),
00402      mStub(stub),
00403      mTransform(transform),
00404      mResultConverter(resultConv),
00405      mTarget(target),
00406      mProto(proto),
00407      mReQuery(0),
00408      mSink(s),
00409      mFollowCname(followCname)
00410 {
00411    assert(s);
00412 }
00413 
00414 DnsStub::Query::~Query()
00415 {
00416    delete mResultConverter; //.dcm. flyweight?
00417 }
00418 
00419 static Data
00420 typeToData(int rr)
00421 {
00422    // !dcm! fix this
00423    if (rr == RR_A::getRRType())
00424    {
00425       return RR_A::getRRTypeName();
00426    }
00427 #if defined(USE_IPV6)
00428    else if(rr == RR_AAAA::getRRType())
00429    {
00430       return RR_AAAA::getRRTypeName();
00431    }
00432 #endif
00433    else if (rr ==RR_NAPTR::getRRType())
00434    {
00435       return RR_NAPTR::getRRTypeName();
00436    }
00437    else if(rr == RR_SRV::getRRType())
00438    {
00439       return RR_SRV::getRRTypeName();
00440    }
00441    else if (RR_CNAME::getRRType())
00442    {
00443       return RR_CNAME::getRRTypeName();
00444    }
00445    else
00446    {
00447       return "Unknown";
00448    }
00449 }
00450 
00451 void
00452 DnsStub::Query::go()
00453 {
00454    StackLog(<< "DNS query of:" << mTarget << " " << typeToData(mRRType));
00455 
00456    DnsResourceRecordsByPtr records;
00457    int status = 0;
00458    bool cached = false;
00459    Data targetToQuery = mTarget;
00460    cached = mStub.mRRCache.lookup(mTarget, mRRType, mProto, records, status);
00461 
00462    if (!cached)
00463    {
00464       if (mRRType != T_CNAME)
00465       {
00466          do
00467          {
00468             DnsResourceRecordsByPtr cnames;
00469             cached = mStub.mRRCache.lookup(targetToQuery, T_CNAME, mProto, cnames, status);
00470             if (cached)
00471             {
00472                targetToQuery = (dynamic_cast<DnsCnameRecord*>(cnames[0]))->cname();
00473             }
00474          } while(cached);
00475       }
00476    }
00477 
00478    if (targetToQuery != mTarget)
00479    {
00480       StackLog(<< mTarget << " mapped to CNAME " << targetToQuery);
00481       cached = mStub.mRRCache.lookup(targetToQuery, mRRType, mProto, records, status);
00482    }
00483 
00484    if (!cached)
00485    {
00486       if(mStub.mDnsProvider && mStub.mDnsProvider->hostFileLookupLookupOnlyMode())
00487       {
00488          assert(mRRType == T_A);
00489          StackLog (<< targetToQuery << " not cached. Doing hostfile lookup");
00490          in_addr address;
00491          if (mStub.mDnsProvider->hostFileLookup(targetToQuery.c_str(), address))
00492          {
00493             mStub.cache(mTarget, address);
00494             DnsResourceRecordsByPtr result;
00495             int queryStatus = 0;
00496 
00497             mStub.mRRCache.lookup(mTarget, mRRType, mProto, result, queryStatus);
00498             if (mTransform)
00499             {
00500                 mTransform->transform(mTarget, mRRType, result);
00501             }
00502             mResultConverter->notifyUser(mTarget, queryStatus, mStub.errorMessage(queryStatus), result, mSink);
00503          }
00504          else
00505          {
00506             // Not in hosts file - return error - or.. we could fallback to doing the lookupRecords call on the local named
00507             mResultConverter->notifyUser(mTarget, ARES_ENOTFOUND, mStub.errorMessage(ARES_ENOTFOUND), Empty, mSink);
00508          }
00509          mReQuery = 0;
00510          mStub.removeQuery(this);
00511          delete this;
00512          return;
00513       }
00514       else
00515       {
00516          StackLog (<< targetToQuery << " not cached. Doing external dns lookup");
00517          mStub.lookupRecords(targetToQuery, mRRType, this);
00518       }
00519    }
00520    else // is cached
00521    {
00522       if (mTransform && !records.empty())
00523       {
00524          mTransform->transform(mTarget, mRRType, records);
00525       }
00526       mResultConverter->notifyUser(mTarget, status, mStub.errorMessage(status), records, mSink);
00527 
00528       mStub.removeQuery(this);
00529       delete this;
00530    }
00531 }
00532 
00533 void
00534 DnsStub::Query::process(int status, const unsigned char* abuf, const int alen)
00535 {
00536    if (status != 0)
00537    {
00538       switch (status)
00539       {
00540          case ARES_ENODATA:
00541          case ARES_EFORMERR:
00542          case ARES_ESERVFAIL:
00543          case ARES_ENOTFOUND:
00544          case ARES_ENOTIMP:
00545          case ARES_EREFUSED:
00546             if(mRRType == T_A)
00547             {
00548                in_addr address;
00549                if (mStub.mDnsProvider->hostFileLookup(mTarget.c_str(), address))
00550                {
00551                   mStub.cache(mTarget, address);
00552                   mReQuery = 0;
00553                   DnsResourceRecordsByPtr result;
00554                   int queryStatus = 0;
00555 
00556                   mStub.mRRCache.lookup(mTarget, mRRType, mProto, result, queryStatus);
00557                   if (mTransform)
00558                   {
00559                      mTransform->transform(mTarget, mRRType, result);
00560                   }
00561                   mResultConverter->notifyUser(mTarget, queryStatus, mStub.errorMessage(queryStatus), result, mSink);
00562                   mStub.removeQuery(this);
00563                   delete this;
00564                   return;
00565                }
00566             }
00567             try
00568             {
00569                mStub.cacheTTL(mTarget, mRRType, status, abuf, alen);
00570             }
00571             catch (BaseException& e)
00572             {
00573                // if the response isn't parsable, we might want to consider caching
00574                // TTL anyways to delay the query attempt for this record.
00575                ErrLog(<< "Couldn't parse failure response to lookup for " << mTarget);
00576                InfoLog(<< e.getMessage());
00577             }
00578             break;
00579 
00580          case ARES_ECONNREFUSED:
00581          case ARES_ETIMEOUT:
00582             ErrLog (<< "Connection error " << mStub.errorMessage(status) << " for " << mTarget);
00583             break;
00584          case ARES_EBADRESP:
00585             ErrLog (<< "Server response error " << mStub.errorMessage(status) << " for " << mTarget);
00586             break;
00587          case ARES_EOF:
00588          case ARES_EFILE:
00589          case ARES_ENOMEM:
00590          case ARES_EDESTRUCTION:
00591             ErrLog (<< "Error " << mStub.errorMessage(status) << " for " << mTarget);
00592             break;
00593          case ARES_EBADNAME:
00594             ErrLog(<< "Garbage hostname failed to resolve: " << mStub.errorMessage(status) << " for " << mTarget);
00595             break;
00596          case ARES_EBADQUERY:
00597             ErrLog(<< "Query was malformed (probably because hostname was "
00598                         "too long) " << mStub.errorMessage(status) << " for "
00599                         << mTarget);
00600             break;
00601          case ARES_EBADFAMILY:
00602             ErrLog (<< "Bad lookup type " << mStub.errorMessage(status) << " for " << mTarget);
00603             // .bwc. This should not happen. If it does, we have code to fix.
00604             assert(0);
00605             break;
00606          default:
00607             ErrLog (<< "Unknown error " << mStub.errorMessage(status) << " for " << mTarget);
00608             assert(0);
00609             break;
00610       }
00611 
00612       // For other error status values, we may also want to cacheTTL to delay
00613       // requeries. Especially if the server refuses.
00614       mResultConverter->notifyUser(mTarget, status, mStub.errorMessage(status), Empty, mSink);
00615       mReQuery = 0;
00616       mStub.removeQuery(this);
00617       delete this;
00618       return;
00619    }
00620 
00621    bool bDeleteThis = true;
00622 
00623    // skip header
00624    const unsigned char* aptr = abuf + HFIXEDSZ;
00625 
00626    int qdcount = DNS_HEADER_QDCOUNT(abuf); // questions.
00627    for (int i = 0; i < qdcount && aptr; ++i)
00628    {
00629       try
00630       {
00631          aptr = mStub.skipDNSQuestion(aptr, abuf, alen);
00632       }
00633       catch (BaseException& e)
00634       {
00635          ErrLog(<< "Error parsing DNS record for " << mTarget << ": " << e.getMessage());
00636          mResultConverter->notifyUser(mTarget, ARES_EFORMERR, e.getMessage(), Empty, mSink);
00637          mStub.removeQuery(this);
00638          delete this;
00639          return;
00640       }
00641    }
00642 
00643    int ancount = DNS_HEADER_ANCOUNT(abuf);
00644    if (ancount == 0)
00645    {
00646       mResultConverter->notifyUser(mTarget, 0, mStub.errorMessage(0), Empty, mSink);
00647    }
00648    else
00649    {
00650       bool bGotAnswers = true;
00651       Data targetToQuery;
00652       followCname(aptr, abuf, alen, bGotAnswers, bDeleteThis, targetToQuery);
00653 
00654       if (bGotAnswers)
00655       {
00656          mReQuery = 0;
00657          DnsResourceRecordsByPtr result;
00658          int queryStatus = 0;
00659 
00660          if (mTarget != targetToQuery) DebugLog (<< mTarget << " mapped to " << targetToQuery << " and returned result");
00661          mStub.mRRCache.lookup(targetToQuery, mRRType, mProto, result, queryStatus);
00662          if (mTransform)
00663          {
00664             mTransform->transform(mTarget, mRRType, result);
00665          }
00666          mResultConverter->notifyUser(mTarget, queryStatus, mStub.errorMessage(queryStatus), result, mSink);
00667       }
00668    }
00669 
00670    if (bDeleteThis)
00671    {
00672       mStub.removeQuery(this);
00673       delete this;
00674    }
00675 }
00676 
00677 void
00678 DnsStub::Query::onDnsRaw(int status, const unsigned char* abuf, int alen)
00679 {
00680    process(status, abuf, alen);
00681 }
00682 
00683 void
00684 DnsStub::Query::followCname(const unsigned char* aptr, const unsigned char*abuf, const int alen, bool& bGotAnswers, bool& bDeleteThis, Data& targetToQuery)
00685 {
00686    bGotAnswers = true;
00687    bDeleteThis = true;
00688 
00689    char* name = 0;
00690    long len = 0;
00691 
00692    if (ARES_SUCCESS != ares_expand_name(aptr, abuf, alen, &name, &len))
00693    {
00694       ErrLog(<< "Failed DNS preparse for " << targetToQuery);
00695       mResultConverter->notifyUser(mTarget, ARES_EFORMERR, "Failed DNS preparse", Empty, mSink);
00696       bGotAnswers = false;
00697       return;
00698    }
00699 
00700    targetToQuery = name;
00701    aptr += len;
00702 
00703    try
00704    {
00705       mStub.cache(name, abuf, alen);
00706    }
00707    catch (BaseException& e)
00708    {
00709       ErrLog(<< "Failed to cache result for " << targetToQuery << ": " << e.getMessage());
00710       mResultConverter->notifyUser(mTarget, ARES_EFORMERR, e.getMessage(), Empty, mSink);
00711       bGotAnswers = false;
00712       return;
00713    }
00714 
00715    if (mRRType != T_CNAME)
00716    {
00717       if (DNS_RR_TYPE(aptr) == T_CNAME)
00718       {
00719          if (mFollowCname && mReQuery < MAX_REQUERIES)
00720          {
00721             ++mReQuery;
00722             int status = 0;
00723             bool cached = false;
00724 
00725             do
00726             {
00727                DnsResourceRecordsByPtr cnames;
00728                cached = mStub.mRRCache.lookup(targetToQuery, T_CNAME, mProto, cnames, status);
00729                if (cached)
00730                {
00731                   ++mReQuery;
00732                   targetToQuery = (dynamic_cast<DnsCnameRecord*>(cnames[0]))->cname();
00733                }
00734             } while(mReQuery < MAX_REQUERIES && cached);
00735 
00736             DnsResourceRecordsByPtr result;
00737             if (!mStub.mRRCache.lookup(targetToQuery, mRRType, mProto, result, status))
00738             {
00739                mStub.lookupRecords(targetToQuery, mRRType, this);
00740                bDeleteThis = false;
00741                bGotAnswers = false;
00742             }
00743          }
00744          else
00745          {
00746             mReQuery = 0;
00747             mResultConverter->notifyUser(mTarget, 1, mStub.errorMessage(1), Empty, mSink);
00748             bGotAnswers = false;
00749          }
00750       }
00751    }
00752 
00753    free(name);
00754 }
00755 
00756 Data
00757 DnsStub::errorMessage(int status)
00758 {
00759    return Data(Data::Take, mDnsProvider->errorMessage(status));
00760 }
00761 
00762 void
00763 DnsStub::lookupRecords(const Data& target, unsigned short type, DnsRawSink* sink)
00764 {
00765    mDnsProvider->lookup(target.c_str(), type, this, sink);
00766 }
00767 
00768 void
00769 DnsStub::handleDnsRaw(ExternalDnsRawResult res)
00770 {
00771    reinterpret_cast<DnsRawSink*>(res.userData)->onDnsRaw(res.errorCode(), res.abuf, res.alen);
00772    mDnsProvider->freeResult(res);
00773 }
00774 
00775 void
00776 DnsStub::setEnumSuffixes(const std::vector<Data>& suffixes)
00777 {
00778    SetEnumSuffixesCommand* command = new SetEnumSuffixesCommand(*this, suffixes);
00779    mCommandFifo.add(command);
00780 
00781    if (mAsyncProcessHandler)
00782    {
00783       mAsyncProcessHandler->handleProcessNotification();
00784    }
00785 }
00786 
00787 const std::vector<Data>&
00788 DnsStub::getEnumSuffixes() const
00789 {
00790    return mEnumSuffixes;
00791 }
00792 
00793 void
00794 DnsStub::doSetEnumSuffixes(const std::vector<Data>& suffixes)
00795 {
00796    mEnumSuffixes = suffixes;
00797 }
00798 
00799 void
00800 DnsStub::clearDnsCache()
00801 {
00802    ClearDnsCacheCommand* command = new ClearDnsCacheCommand(*this);
00803    mCommandFifo.add(command);
00804 
00805    if (mAsyncProcessHandler)
00806    {
00807       mAsyncProcessHandler->handleProcessNotification();
00808    }
00809 }
00810 
00811 void
00812 DnsStub::doClearDnsCache()
00813 {
00814    mRRCache.clearCache();
00815 }
00816 
00817 void
00818 DnsStub::logDnsCache()
00819 {
00820    LogDnsCacheCommand* command = new LogDnsCacheCommand(*this);
00821    mCommandFifo.add(command);
00822 
00823    if (mAsyncProcessHandler)
00824    {
00825       mAsyncProcessHandler->handleProcessNotification();
00826    }
00827 }
00828 
00829 void
00830 DnsStub::doLogDnsCache()
00831 {
00832    mRRCache.logCache();
00833 }
00834 
00835 void 
00836 DnsStub::getDnsCacheDump(std::pair<unsigned long, unsigned long> key, GetDnsCacheDumpHandler* handler)
00837 {
00838    GetDnsCacheDumpCommand* command = new GetDnsCacheDumpCommand(*this, key, handler);
00839    mCommandFifo.add(command);
00840 
00841    if (mAsyncProcessHandler)
00842    {
00843       mAsyncProcessHandler->handleProcessNotification();
00844    }
00845 }
00846 
00847 void 
00848 DnsStub::doGetDnsCacheDump(std::pair<unsigned long, unsigned long> key, GetDnsCacheDumpHandler* handler)
00849 {
00850    assert(handler != 0);
00851    Data dnsCacheDump;
00852    mRRCache.getCacheDump(dnsCacheDump);
00853    handler->onDnsCacheDumpRetrieved(key, dnsCacheDump);
00854 }
00855 
00856 void
00857 DnsStub::setDnsCacheTTL(int ttl)
00858 {
00859    mRRCache.setTTL(ttl);
00860 }
00861 
00862 void
00863 DnsStub::setDnsCacheSize(int size)
00864 {
00865    mRRCache.setSize(size);
00866 }
00867 
00868 /* ====================================================================
00869  * The Vovida Software License, Version 1.0 
00870  * 
00871  * Copyright (c) 2000-2005 Vovida Networks, Inc.  All rights reserved.
00872  * 
00873  * Redistribution and use in source and binary forms, with or without
00874  * modification, are permitted provided that the following conditions
00875  * are met:
00876  * 
00877  * 1. Redistributions of source code must retain the above copyright
00878  *    notice, this list of conditions and the following disclaimer.
00879  * 
00880  * 2. Redistributions in binary form must reproduce the above copyright
00881  *    notice, this list of conditions and the following disclaimer in
00882  *    the documentation and/or other materials provided with the
00883  *    distribution.
00884  * 
00885  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00886  *    and "Vovida Open Communication Application Library (VOCAL)" must
00887  *    not be used to endorse or promote products derived from this
00888  *    software without prior written permission. For written
00889  *    permission, please contact vocal@vovida.org.
00890  *
00891  * 4. Products derived from this software may not be called "VOCAL", nor
00892  *    may "VOCAL" appear in their name, without prior written
00893  *    permission of Vovida Networks, Inc.
00894  * 
00895  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00896  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00897  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00898  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00899  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00900  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00901  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00902  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00903  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00904  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00905  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00906  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00907  * DAMAGE.
00908  * 
00909  * ====================================================================
00910  * 
00911  * This software consists of voluntary contributions made by Vovida
00912  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00913  * Inc.  For more information on Vovida Networks, Inc., please see
00914  * <http://www.vovida.org/>.
00915  *
00916  */
00917