reSIProcate/rutil  9694
Public Types | Public Member Functions | Private Attributes | Static Private Attributes
resip::DnsStub::Query Class Reference
Inheritance diagram for resip::DnsStub::Query:
Inheritance graph
[legend]
Collaboration diagram for resip::DnsStub::Query:
Collaboration graph
[legend]

List of all members.

Public Types

enum  { MAX_REQUERIES = 5 }

Public Member Functions

 Query (DnsStub &stub, ResultTransform *transform, ResultConverter *resultConv, const Data &target, int rrType, bool followCname, int proto, DnsResultSink *s)
virtual ~Query ()
void go ()
void process (int status, const unsigned char *abuf, const int alen)
void onDnsRaw (int status, const unsigned char *abuf, int alen)
void followCname (const unsigned char *aptr, const unsigned char *abuf, const int alen, bool &bGotAnswers, bool &bDeleteThis, Data &targetToQuery)

Private Attributes

int mRRType
DnsStubmStub
ResultTransformmTransform
ResultConvertermResultConverter
Data mTarget
int mProto
int mReQuery
DnsResultSinkmSink
bool mFollowCname

Static Private Attributes

static DnsResourceRecordsByPtr Empty

Detailed Description

Definition at line 233 of file DnsStub.hxx.


Member Enumeration Documentation

anonymous enum
Enumerator:
MAX_REQUERIES 

Definition at line 240 of file DnsStub.hxx.


Constructor & Destructor Documentation

DnsStub::Query::Query ( DnsStub stub,
ResultTransform transform,
ResultConverter resultConv,
const Data target,
int  rrType,
bool  followCname,
int  proto,
DnsResultSink s 
)

Definition at line 398 of file DnsStub.cxx.

   : mRRType(rrType),
     mStub(stub),
     mTransform(transform),
     mResultConverter(resultConv),
     mTarget(target),
     mProto(proto),
     mReQuery(0),
     mSink(s),
     mFollowCname(followCname)
{
   assert(s);
}
DnsStub::Query::~Query ( ) [virtual]

Definition at line 414 of file DnsStub.cxx.

{
   delete mResultConverter; //.dcm. flyweight?
}

Member Function Documentation

void DnsStub::Query::followCname ( const unsigned char *  aptr,
const unsigned char *  abuf,
const int  alen,
bool &  bGotAnswers,
bool &  bDeleteThis,
Data targetToQuery 
)

Definition at line 684 of file DnsStub.cxx.

References ErrLog, and resip::BaseException::getMessage().

{
   bGotAnswers = true;
   bDeleteThis = true;

   char* name = 0;
   long len = 0;

   if (ARES_SUCCESS != ares_expand_name(aptr, abuf, alen, &name, &len))
   {
      ErrLog(<< "Failed DNS preparse for " << targetToQuery);
      mResultConverter->notifyUser(mTarget, ARES_EFORMERR, "Failed DNS preparse", Empty, mSink);
      bGotAnswers = false;
      return;
   }

   targetToQuery = name;
   aptr += len;

   try
   {
      mStub.cache(name, abuf, alen);
   }
   catch (BaseException& e)
   {
      ErrLog(<< "Failed to cache result for " << targetToQuery << ": " << e.getMessage());
      mResultConverter->notifyUser(mTarget, ARES_EFORMERR, e.getMessage(), Empty, mSink);
      bGotAnswers = false;
      return;
   }

   if (mRRType != T_CNAME)
   {
      if (DNS_RR_TYPE(aptr) == T_CNAME)
      {
         if (mFollowCname && mReQuery < MAX_REQUERIES)
         {
            ++mReQuery;
            int status = 0;
            bool cached = false;

            do
            {
               DnsResourceRecordsByPtr cnames;
               cached = mStub.mRRCache.lookup(targetToQuery, T_CNAME, mProto, cnames, status);
               if (cached)
               {
                  ++mReQuery;
                  targetToQuery = (dynamic_cast<DnsCnameRecord*>(cnames[0]))->cname();
               }
            } while(mReQuery < MAX_REQUERIES && cached);

            DnsResourceRecordsByPtr result;
            if (!mStub.mRRCache.lookup(targetToQuery, mRRType, mProto, result, status))
            {
               mStub.lookupRecords(targetToQuery, mRRType, this);
               bDeleteThis = false;
               bGotAnswers = false;
            }
         }
         else
         {
            mReQuery = 0;
            mResultConverter->notifyUser(mTarget, 1, mStub.errorMessage(1), Empty, mSink);
            bGotAnswers = false;
         }
      }
   }

   free(name);
}

Here is the call graph for this function:

void DnsStub::Query::go ( )

Definition at line 452 of file DnsStub.cxx.

References resip::Data::c_str(), resip::DnsStub::mTransform, StackLog, T_A, resip::DnsStub::ResultTransform::transform(), and typeToData().

Referenced by resip::DnsStub::query().

{
   StackLog(<< "DNS query of:" << mTarget << " " << typeToData(mRRType));

   DnsResourceRecordsByPtr records;
   int status = 0;
   bool cached = false;
   Data targetToQuery = mTarget;
   cached = mStub.mRRCache.lookup(mTarget, mRRType, mProto, records, status);

   if (!cached)
   {
      if (mRRType != T_CNAME)
      {
         do
         {
            DnsResourceRecordsByPtr cnames;
            cached = mStub.mRRCache.lookup(targetToQuery, T_CNAME, mProto, cnames, status);
            if (cached)
            {
               targetToQuery = (dynamic_cast<DnsCnameRecord*>(cnames[0]))->cname();
            }
         } while(cached);
      }
   }

   if (targetToQuery != mTarget)
   {
      StackLog(<< mTarget << " mapped to CNAME " << targetToQuery);
      cached = mStub.mRRCache.lookup(targetToQuery, mRRType, mProto, records, status);
   }

   if (!cached)
   {
      if(mStub.mDnsProvider && mStub.mDnsProvider->hostFileLookupLookupOnlyMode())
      {
         assert(mRRType == T_A);
         StackLog (<< targetToQuery << " not cached. Doing hostfile lookup");
         in_addr address;
         if (mStub.mDnsProvider->hostFileLookup(targetToQuery.c_str(), address))
         {
            mStub.cache(mTarget, address);
            DnsResourceRecordsByPtr result;
            int queryStatus = 0;

            mStub.mRRCache.lookup(mTarget, mRRType, mProto, result, queryStatus);
            if (mTransform)
            {
                mTransform->transform(mTarget, mRRType, result);
            }
            mResultConverter->notifyUser(mTarget, queryStatus, mStub.errorMessage(queryStatus), result, mSink);
         }
         else
         {
            // Not in hosts file - return error - or.. we could fallback to doing the lookupRecords call on the local named
            mResultConverter->notifyUser(mTarget, ARES_ENOTFOUND, mStub.errorMessage(ARES_ENOTFOUND), Empty, mSink);
         }
         mReQuery = 0;
         mStub.removeQuery(this);
         delete this;
         return;
      }
      else
      {
         StackLog (<< targetToQuery << " not cached. Doing external dns lookup");
         mStub.lookupRecords(targetToQuery, mRRType, this);
      }
   }
   else // is cached
   {
      if (mTransform && !records.empty())
      {
         mTransform->transform(mTarget, mRRType, records);
      }
      mResultConverter->notifyUser(mTarget, status, mStub.errorMessage(status), records, mSink);

      mStub.removeQuery(this);
      delete this;
   }
}

Here is the call graph for this function:

void DnsStub::Query::onDnsRaw ( int  status,
const unsigned char *  abuf,
int  alen 
) [virtual]

Implements resip::DnsRawSink.

Definition at line 678 of file DnsStub.cxx.

References resip::DnsStub::process().

{
   process(status, abuf, alen);
}

Here is the call graph for this function:

void DnsStub::Query::process ( int  status,
const unsigned char *  abuf,
const int  alen 
)

Definition at line 534 of file DnsStub.cxx.

References DebugLog, ErrLog, resip::BaseException::getMessage(), InfoLog, resip::DnsStub::mTransform, T_A, and resip::DnsStub::ResultTransform::transform().

{
   if (status != 0)
   {
      switch (status)
      {
         case ARES_ENODATA:
         case ARES_EFORMERR:
         case ARES_ESERVFAIL:
         case ARES_ENOTFOUND:
         case ARES_ENOTIMP:
         case ARES_EREFUSED:
            if(mRRType == T_A)
            {
               in_addr address;
               if (mStub.mDnsProvider->hostFileLookup(mTarget.c_str(), address))
               {
                  mStub.cache(mTarget, address);
                  mReQuery = 0;
                  DnsResourceRecordsByPtr result;
                  int queryStatus = 0;

                  mStub.mRRCache.lookup(mTarget, mRRType, mProto, result, queryStatus);
                  if (mTransform)
                  {
                     mTransform->transform(mTarget, mRRType, result);
                  }
                  mResultConverter->notifyUser(mTarget, queryStatus, mStub.errorMessage(queryStatus), result, mSink);
                  mStub.removeQuery(this);
                  delete this;
                  return;
               }
            }
            try
            {
               mStub.cacheTTL(mTarget, mRRType, status, abuf, alen);
            }
            catch (BaseException& e)
            {
               // if the response isn't parsable, we might want to consider caching
               // TTL anyways to delay the query attempt for this record.
               ErrLog(<< "Couldn't parse failure response to lookup for " << mTarget);
               InfoLog(<< e.getMessage());
            }
            break;

         case ARES_ECONNREFUSED:
         case ARES_ETIMEOUT:
            ErrLog (<< "Connection error " << mStub.errorMessage(status) << " for " << mTarget);
            break;
         case ARES_EBADRESP:
            ErrLog (<< "Server response error " << mStub.errorMessage(status) << " for " << mTarget);
            break;
         case ARES_EOF:
         case ARES_EFILE:
         case ARES_ENOMEM:
         case ARES_EDESTRUCTION:
            ErrLog (<< "Error " << mStub.errorMessage(status) << " for " << mTarget);
            break;
         case ARES_EBADNAME:
            ErrLog(<< "Garbage hostname failed to resolve: " << mStub.errorMessage(status) << " for " << mTarget);
            break;
         case ARES_EBADQUERY:
            ErrLog(<< "Query was malformed (probably because hostname was "
                        "too long) " << mStub.errorMessage(status) << " for "
                        << mTarget);
            break;
         case ARES_EBADFAMILY:
            ErrLog (<< "Bad lookup type " << mStub.errorMessage(status) << " for " << mTarget);
            // .bwc. This should not happen. If it does, we have code to fix.
            assert(0);
            break;
         default:
            ErrLog (<< "Unknown error " << mStub.errorMessage(status) << " for " << mTarget);
            assert(0);
            break;
      }

      // For other error status values, we may also want to cacheTTL to delay
      // requeries. Especially if the server refuses.
      mResultConverter->notifyUser(mTarget, status, mStub.errorMessage(status), Empty, mSink);
      mReQuery = 0;
      mStub.removeQuery(this);
      delete this;
      return;
   }

   bool bDeleteThis = true;

   // skip header
   const unsigned char* aptr = abuf + HFIXEDSZ;

   int qdcount = DNS_HEADER_QDCOUNT(abuf); // questions.
   for (int i = 0; i < qdcount && aptr; ++i)
   {
      try
      {
         aptr = mStub.skipDNSQuestion(aptr, abuf, alen);
      }
      catch (BaseException& e)
      {
         ErrLog(<< "Error parsing DNS record for " << mTarget << ": " << e.getMessage());
         mResultConverter->notifyUser(mTarget, ARES_EFORMERR, e.getMessage(), Empty, mSink);
         mStub.removeQuery(this);
         delete this;
         return;
      }
   }

   int ancount = DNS_HEADER_ANCOUNT(abuf);
   if (ancount == 0)
   {
      mResultConverter->notifyUser(mTarget, 0, mStub.errorMessage(0), Empty, mSink);
   }
   else
   {
      bool bGotAnswers = true;
      Data targetToQuery;
      followCname(aptr, abuf, alen, bGotAnswers, bDeleteThis, targetToQuery);

      if (bGotAnswers)
      {
         mReQuery = 0;
         DnsResourceRecordsByPtr result;
         int queryStatus = 0;

         if (mTarget != targetToQuery) DebugLog (<< mTarget << " mapped to " << targetToQuery << " and returned result");
         mStub.mRRCache.lookup(targetToQuery, mRRType, mProto, result, queryStatus);
         if (mTransform)
         {
            mTransform->transform(mTarget, mRRType, result);
         }
         mResultConverter->notifyUser(mTarget, queryStatus, mStub.errorMessage(queryStatus), result, mSink);
      }
   }

   if (bDeleteThis)
   {
      mStub.removeQuery(this);
      delete this;
   }
}

Here is the call graph for this function:


Member Data Documentation

Definition at line 248 of file DnsStub.hxx.

Definition at line 257 of file DnsStub.hxx.

Definition at line 254 of file DnsStub.hxx.

Definition at line 255 of file DnsStub.hxx.

Definition at line 252 of file DnsStub.hxx.

Definition at line 249 of file DnsStub.hxx.

Definition at line 256 of file DnsStub.hxx.

Definition at line 250 of file DnsStub.hxx.

Definition at line 253 of file DnsStub.hxx.

Definition at line 251 of file DnsStub.hxx.


The documentation for this class was generated from the following files: