reSIProcate/rutil  9694
DnsStub.hxx
Go to the documentation of this file.
00001 #ifndef RESIP_DNS_STUB_HXX
00002 #define RESIP_DNS_STUB_HXX
00003 
00004 #ifdef HAVE_CONFIG_H
00005 #include "config.h"
00006 #endif
00007 
00008 
00009 #include <vector>
00010 #include <list>
00011 #include <map>
00012 #include <set>
00013 
00014 #include "rutil/FdPoll.hxx"
00015 #include "rutil/Fifo.hxx"
00016 #include "rutil/GenericIPAddress.hxx"
00017 #include "rutil/SelectInterruptor.hxx"
00018 #include "rutil/Socket.hxx"
00019 #include "rutil/dns/DnsResourceRecord.hxx"
00020 #include "rutil/dns/DnsAAAARecord.hxx"
00021 #include "rutil/dns/DnsCnameRecord.hxx"
00022 #include "rutil/dns/DnsHostRecord.hxx"
00023 #include "rutil/dns/DnsNaptrRecord.hxx"
00024 #include "rutil/dns/DnsSrvRecord.hxx"
00025 #include "rutil/dns/RRCache.hxx"
00026 #include "rutil/dns/RROverlay.hxx"
00027 #include "rutil/dns/ExternalDns.hxx"
00028 #include "rutil/AsyncProcessHandler.hxx"
00029 
00030 
00031 namespace resip
00032 {
00033 class FdPollGrp;
00034 
00035 class GetDnsCacheDumpHandler
00036 {
00037    public:
00038       GetDnsCacheDumpHandler() {}
00039       virtual ~GetDnsCacheDumpHandler() {}
00040       virtual void onDnsCacheDumpRetrieved(std::pair<unsigned long, unsigned long> key, const Data& dnsCache) = 0;
00041 };
00042 
00043 template<typename T>
00044 class DNSResult
00045 {
00046    public:
00047       Data domain;
00048       int status;
00049       Data msg;
00050       std::vector<T> records;
00051       EncodeStream& dump(EncodeStream& strm) const
00052       {
00053          if (status == 0)
00054          {
00055             for (typename std::vector<T>::const_iterator i=records.begin(); i != records.end(); ++i)
00056             {
00057                i->dump(strm);
00058             }
00059          }
00060          else
00061          {
00062             strm << domain << " lookup failed: " << msg;
00063          }
00064 
00065          return strm;
00066       }
00067 };
00068 
00069 template<class T>
00070 EncodeStream& operator<<(EncodeStream& strm, const DNSResult<T>& r)
00071 {
00072    r.dump(strm);
00073    return strm;
00074 }
00075 
00076 class DnsResultSink
00077 {
00078    public:
00079       virtual ~DnsResultSink() {}
00080       virtual void onDnsResult(const DNSResult<DnsHostRecord>&) = 0;
00081       virtual void onLogDnsResult(const DNSResult<DnsHostRecord>&);
00082 
00083 // DnsAAAARecord will basically be non-functional if USE_IPV6 wasn't set in the
00084 // build.
00085       virtual void onDnsResult(const DNSResult<DnsAAAARecord>&) = 0;
00086       virtual void onLogDnsResult(const DNSResult<DnsAAAARecord>&);
00087 
00088       virtual void onDnsResult(const DNSResult<DnsSrvRecord>&) = 0;
00089       virtual void onLogDnsResult(const DNSResult<DnsSrvRecord>&);
00090 
00091       virtual void onDnsResult(const DNSResult<DnsNaptrRecord>&) = 0;
00092       virtual void onLogDnsResult(const DNSResult<DnsNaptrRecord>&);
00093 
00094       virtual void onDnsResult(const DNSResult<DnsCnameRecord>&) = 0;
00095       virtual void onLogDnsResult(const DNSResult<DnsCnameRecord>&);
00096 };
00097 
00098 class DnsRawSink
00099 {
00100    public:
00101       virtual ~DnsRawSink() {}
00102       virtual void onDnsRaw(int statuts, const unsigned char* abuf, int len) = 0;
00103 };
00104 
00105 class DnsStub : public ExternalDnsHandler
00106 {
00107    public:
00108       typedef RRCache::Protocol Protocol;
00109       typedef std::vector<Data> DataArr;
00110       typedef std::vector<DnsResourceRecord*> DnsResourceRecordsByPtr;
00111       typedef std::vector<GenericIPAddress> NameserverList;
00112 
00113       static NameserverList EmptyNameserverList;
00114             
00115       class ResultTransform
00116       {
00117          public:
00118             virtual ~ResultTransform() {}
00119             virtual void transform(const Data& target, int rrType, DnsResourceRecordsByPtr& src) = 0;
00120       };
00121 
00122       class DnsStubException : public BaseException
00123       {
00124          public:
00125             DnsStubException(const Data& msg, const Data& file, const int line)
00126                : BaseException(msg, file, line) 
00127             {
00128             }
00129             
00130             const char* name() const { return "DnsStubException"; }
00131       };
00132 
00133       DnsStub(const NameserverList& additional = EmptyNameserverList,
00134               AfterSocketCreationFuncPtr socketFunc = 0,
00135               AsyncProcessHandler* asyncProcessHandler = 0,
00136               FdPollGrp *pollGrp = 0);
00137       ~DnsStub();
00138 
00139       // call this method before you create SipStack if you'd like to change the
00140       // default DNS lookup timeout and number of retries.
00141       static void setDnsTimeoutAndTries(int timeoutInSec, int tries)
00142       {
00143          mDnsTimeout = timeoutInSec;
00144          mDnsTries = tries;
00145       }
00146       static void enableDnsFeatures(unsigned int features)  {mDnsFeatures |= features;} // bit mask of ExternalDns::Features
00147 
00148       void setResultTransform(ResultTransform*);
00149       void removeResultTransform();
00150       void setEnumSuffixes(const std::vector<Data>& suffixes);
00151       const std::vector<Data>& getEnumSuffixes() const;
00152       void clearDnsCache();
00153       void logDnsCache();
00154       void getDnsCacheDump(std::pair<unsigned long, unsigned long> key, GetDnsCacheDumpHandler* handler);
00155       void setDnsCacheTTL(int ttl);
00156       void setDnsCacheSize(int size);
00157       bool checkDnsChange();
00158       bool supportedType(int);
00159 
00160       template<class QueryType> void lookup(const Data& target, DnsResultSink* sink)
00161       {
00162          lookup<QueryType>(target, Protocol::Reserved, sink);
00163       }
00164 
00165       // There are three pre-defined protocols (see RRList.hxx). Zero(0) is
00166       // reserved for internal use, so do not use 0. If you'd like to blacklist
00167       // for different types of protocols, just pass in any integer other than
00168       // those used for pre-defined protocols.
00169       //
00170       template<class QueryType> void lookup(const Data& target, int protocol, DnsResultSink* sink)
00171       {
00172          QueryCommand<QueryType>* command = new QueryCommand<QueryType>(target, protocol, sink, *this);
00173          mCommandFifo.add(command);
00174 
00175          if (mAsyncProcessHandler)
00176          {
00177             mAsyncProcessHandler->handleProcessNotification();
00178          }
00179       }
00180 
00181       virtual void handleDnsRaw(ExternalDnsRawResult);
00182 
00183       virtual void process(FdSet& fdset);
00184       virtual unsigned int getTimeTillNextProcessMS();
00185       virtual void buildFdSet(FdSet& fdset);
00186       void setPollGrp(FdPollGrp* pollGrp);
00187 
00188       void processTimers();
00189   private:
00190       void processFifo();
00191 
00192    protected:
00193       void cache(const Data& key, in_addr addr);
00194       void cache(const Data& key, const unsigned char* abuf, int alen);
00195       void cacheTTL(const Data& key, int rrType, int status, const unsigned char* abuf, int alen);
00196 
00197    private:
00198       class ResultConverter //.dcm. -- flyweight?
00199       {
00200          public:
00201             virtual void notifyUser(const Data& target, 
00202                                     int status, 
00203                                     const Data& msg,
00204                                     const DnsResourceRecordsByPtr& src,
00205                                     DnsResultSink* sink) = 0;
00206             virtual ~ResultConverter() {}
00207       };
00208       
00209       template<class QueryType>  
00210       class ResultConverterImpl : public ResultConverter
00211       {
00212          public:
00213             virtual void notifyUser(const Data& target, 
00214                                     int status, 
00215                                     const Data& msg,
00216                                     const DnsResourceRecordsByPtr& src,
00217                                     DnsResultSink* sink)
00218             {
00219                assert(sink);
00220                DNSResult<typename QueryType::Type>  result;
00221                for (unsigned int i = 0; i < src.size(); ++i)
00222                {
00223                   result.records.push_back(*(dynamic_cast<typename QueryType::Type*>(src[i])));
00224                }
00225                result.domain = target;
00226                result.status = status;
00227                result.msg = msg;
00228                sink->onLogDnsResult(result);
00229                sink->onDnsResult(result);
00230             }
00231       };
00232 
00233       class Query : public DnsRawSink
00234       {
00235          public:
00236             Query(DnsStub& stub, ResultTransform* transform, ResultConverter* resultConv, 
00237                   const Data& target, int rrType, bool followCname, int proto, DnsResultSink* s);
00238             virtual ~Query();
00239 
00240             enum {MAX_REQUERIES = 5};
00241 
00242             void go();
00243             void process(int status, const unsigned char* abuf, const int alen);
00244             void onDnsRaw(int status, const unsigned char* abuf, int alen);
00245             void followCname(const unsigned char* aptr, const unsigned char*abuf, const int alen, bool& bGotAnswers, bool& bDeleteThis, Data& targetToQuery);
00246 
00247          private:
00248             static DnsResourceRecordsByPtr Empty;
00249             int mRRType;
00250             DnsStub& mStub;
00251             ResultTransform* mTransform;
00252             ResultConverter* mResultConverter;
00253             Data mTarget;
00254             int mProto;
00255             int mReQuery;
00256             DnsResultSink* mSink;
00257             bool mFollowCname;
00258       };
00259 
00260    private:
00261       DnsStub(const DnsStub&);   // disable copy ctor.
00262       DnsStub& operator=(const DnsStub&);
00263 
00264    public:
00265       // sailesh - due to a bug in CodeWarrior,
00266       // QueryCommand::execute() can only access this method
00267       // if it's public. Even using "friend" doesn't work.
00268       template<class QueryType>
00269       void query(const Data& target, int proto, DnsResultSink* sink)
00270       {
00271          Query* query = new Query(*this, mTransform, 
00272                                   new ResultConverterImpl<QueryType>(), 
00273                                   target, QueryType::getRRType(),
00274                                   QueryType::SupportsCName, proto, sink);
00275          mQueries.insert(query);
00276          query->go();
00277       }
00278       
00279    private:
00280 
00281       class Command
00282       {
00283          public:
00284             virtual ~Command() {}
00285             virtual void execute() = 0;
00286       };
00287 
00288 
00289       template<class QueryType>
00290       class QueryCommand : public Command
00291       {
00292          public:
00293             QueryCommand(const Data& target, 
00294                          int proto,
00295                          DnsResultSink* sink,
00296                          DnsStub& stub)
00297                : mTarget(target),
00298                  mProto(proto),
00299                  mSink(sink),
00300                  mStub(stub)
00301             {}
00302 
00303             ~QueryCommand() {}
00304 
00305             void execute()
00306             {
00307                mStub.query<QueryType>(mTarget, mProto, mSink);
00308             }
00309 
00310          private:
00311             Data mTarget;
00312             int mProto;
00313             DnsResultSink* mSink;
00314             DnsStub& mStub;
00315       };
00316 
00317       void doSetEnumSuffixes(const std::vector<Data>& suffixes);
00318 
00319       class SetEnumSuffixesCommand : public Command
00320       {
00321          public:
00322             SetEnumSuffixesCommand(DnsStub& stub, 
00323                                    const std::vector<Data>& suffixes)
00324                : mStub(stub),
00325                  mEnumSuffixes(suffixes)
00326             {}             
00327             ~SetEnumSuffixesCommand() {}
00328             void execute()
00329             {
00330                mStub.doSetEnumSuffixes(mEnumSuffixes);
00331             }
00332 
00333          private:
00334             DnsStub& mStub;
00335             std::vector<Data> mEnumSuffixes;
00336       };
00337 
00338       void doClearDnsCache();
00339 
00340       class ClearDnsCacheCommand : public Command
00341       {
00342          public:
00343             ClearDnsCacheCommand(DnsStub& stub)
00344                : mStub(stub)
00345             {}             
00346             ~ClearDnsCacheCommand() {}
00347             void execute()
00348             {
00349                mStub.doClearDnsCache();
00350             }
00351 
00352          private:
00353             DnsStub& mStub;
00354       };
00355 
00356       void doLogDnsCache();
00357 
00358       class LogDnsCacheCommand : public Command
00359       {
00360          public:
00361             LogDnsCacheCommand(DnsStub& stub)
00362                : mStub(stub)
00363             {}             
00364             ~LogDnsCacheCommand() {}
00365             void execute()
00366             {
00367                mStub.doLogDnsCache();
00368             }
00369 
00370          private:
00371             DnsStub& mStub;
00372       };
00373 
00374       void doGetDnsCacheDump(std::pair<unsigned long, unsigned long> key, GetDnsCacheDumpHandler* handler);
00375 
00376       class GetDnsCacheDumpCommand : public Command
00377       {
00378          public:
00379             GetDnsCacheDumpCommand(DnsStub& stub, std::pair<unsigned long, unsigned long> key, GetDnsCacheDumpHandler* handler)
00380                : mStub(stub), mKey(key), mHandler(handler)
00381             {}             
00382             ~GetDnsCacheDumpCommand() {}
00383             void execute()
00384             {
00385                mStub.doGetDnsCacheDump(mKey, mHandler);
00386             }
00387 
00388          private:
00389             DnsStub& mStub;
00390             std::pair<unsigned long, unsigned long> mKey;
00391             GetDnsCacheDumpHandler* mHandler;
00392       };
00393 
00394       SelectInterruptor mSelectInterruptor;
00395       FdPollItemHandle mInterruptorHandle;
00396 
00397       resip::Fifo<Command> mCommandFifo;
00398 
00399       const unsigned char* skipDNSQuestion(const unsigned char *aptr,
00400                                            const unsigned char *abuf,
00401                                            int alen);
00402       const unsigned char* createOverlay(const unsigned char* abuf, 
00403                                          const int alen, 
00404                                          const unsigned char* aptr, 
00405                                          std::vector<RROverlay>&,
00406                                          bool discard=false);
00407       void removeQuery(Query*);
00408       void lookupRecords(const Data& target, unsigned short type, DnsRawSink* sink);
00409       Data errorMessage(int status);
00410 
00411       ResultTransform* mTransform;
00412       ExternalDns* mDnsProvider;
00413       FdPollGrp* mPollGrp;
00414       std::set<Query*> mQueries;
00415 
00416       std::vector<Data> mEnumSuffixes; // where to do enum lookups
00417 
00418       static int mDnsTimeout; // in seconds
00419       static int mDnsTries;
00420       static unsigned int mDnsFeatures;    // bit mask of ExternalDns::Features
00421 
00423       AsyncProcessHandler* mAsyncProcessHandler;
00424 
00426       RRCache mRRCache;
00427 };
00428 
00429 typedef DnsStub::Protocol Protocol;
00430 
00431 }
00432 
00433 #endif
00434  
00435 /* ====================================================================
00436  * The Vovida Software License, Version 1.0 
00437  * 
00438  * Copyright (c) 2000-2005 Vovida Networks, Inc.  All rights reserved.
00439  * 
00440  * Redistribution and use in source and binary forms, with or without
00441  * modification, are permitted provided that the following conditions
00442  * are met:
00443  * 
00444  * 1. Redistributions of source code must retain the above copyright
00445  *    notice, this list of conditions and the following disclaimer.
00446  * 
00447  * 2. Redistributions in binary form must reproduce the above copyright
00448  *    notice, this list of conditions and the following disclaimer in
00449  *    the documentation and/or other materials provided with the
00450  *    distribution.
00451  * 
00452  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00453  *    and "Vovida Open Communication Application Library (VOCAL)" must
00454  *    not be used to endorse or promote products derived from this
00455  *    software without prior written permission. For written
00456  *    permission, please contact vocal@vovida.org.
00457  *
00458  * 4. Products derived from this software may not be called "VOCAL", nor
00459  *    may "VOCAL" appear in their name, without prior written
00460  *    permission of Vovida Networks, Inc.
00461  * 
00462  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00463  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00464  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00465  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00466  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00467  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00468  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00469  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00470  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00471  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00472  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00473  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00474  * DAMAGE.
00475  * 
00476  * ====================================================================
00477  * 
00478  * This software consists of voluntary contributions made by Vovida
00479  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00480  * Inc.  For more information on Vovida Networks, Inc., please see
00481  * <http://www.vovida.org/>.
00482  *
00483  */
00484