Browse Source

Merge branch 'trac494'

Conflicts:
	src/lib/asiolink/asiolink.cc
Jelte Jansen 14 years ago
parent
commit
75692d6d89

+ 2 - 0
configure.ac

@@ -652,6 +652,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/datasrc/tests/Makefile
                  src/lib/xfr/Makefile
                  src/lib/log/Makefile
+                 src/lib/resolve/Makefile
+                 src/lib/resolve/tests/Makefile
                  src/lib/testutils/Makefile
                  src/lib/testutils/testdata/Makefile
                  src/lib/nsas/Makefile

+ 19 - 2
src/bin/resolver/resolver.cc

@@ -131,6 +131,9 @@ public:
         }
     }
 
+    void resolve(const isc::dns::QuestionPtr& question,
+        const isc::resolve::ResolverInterface::CallbackPtr& callback);
+
     void processNormalQuery(const Question& question,
                             MessagePtr answer_message,
                             OutputBufferPtr buffer,
@@ -333,7 +336,6 @@ Resolver::~Resolver() {
     delete checkin_;
     delete dns_lookup_;
     delete dns_answer_;
-    dlog("Deleting the Resolver",true);
 }
 
 void
@@ -352,6 +354,14 @@ Resolver::getConfigSession() const {
 }
 
 void
+Resolver::resolve(const isc::dns::QuestionPtr& question,
+    const isc::resolve::ResolverInterface::CallbackPtr& callback)
+{
+    impl_->resolve(question, callback);
+}
+
+
+void
 Resolver::processMessage(const IOMessage& io_message,
                          MessagePtr query_message,
                          MessagePtr answer_message,
@@ -435,13 +445,20 @@ Resolver::processMessage(const IOMessage& io_message,
 }
 
 void
+ResolverImpl::resolve(const QuestionPtr& question,
+    const isc::resolve::ResolverInterface::CallbackPtr& callback)
+{
+    rec_query_->resolve(question, callback);
+}
+
+void
 ResolverImpl::processNormalQuery(const Question& question,
                                  MessagePtr answer_message,
                                  OutputBufferPtr buffer,
                                  DNSServer* server)
 {
     dlog("Processing normal query");
-    rec_query_->sendQuery(question, answer_message, buffer, server);
+    rec_query_->resolve(question, answer_message, buffer, server);
 }
 
 namespace {

+ 7 - 1
src/bin/resolver/resolver.h

@@ -24,6 +24,8 @@
 
 #include <asiolink/asiolink.h>
 
+#include <resolve/resolver_interface.h>
+
 class ResolverImpl;
 
 /**
@@ -35,7 +37,7 @@ class ResolverImpl;
  * answer. It doesn't really know about chasing referrals and similar, it
  * simply plugs the parts that know into the network handling code.
  */
-class Resolver {
+class Resolver : public isc::resolve::ResolverInterface {
     ///
     /// \name Constructors, Assignment Operator and Destructor.
     ///
@@ -51,6 +53,10 @@ public:
     ~Resolver();
     //@}
 
+    virtual void resolve(
+        const isc::dns::QuestionPtr& question,
+        const isc::resolve::ResolverInterface::CallbackPtr& callback);
+
     /// \brief Process an incoming DNS message, then signal 'server' to resume 
     ///
     /// A DNS query (or other message) has been received by a \c DNSServer

+ 1 - 1
src/lib/Makefile.am

@@ -1,2 +1,2 @@
 SUBDIRS = exceptions dns cc config datasrc python xfr bench log asiolink \
-    testutils nsas
+    testutils nsas resolve

+ 1 - 0
src/lib/asiolink/Makefile.am

@@ -32,3 +32,4 @@ libasiolink_la_CXXFLAGS += -Wno-error
 endif
 libasiolink_la_CPPFLAGS = $(AM_CPPFLAGS)
 libasiolink_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la
+libasiolink_la_LIBADD += $(top_builddir)/src/lib/resolve/libresolve.la

+ 40 - 13
src/lib/asiolink/asiolink.cc

@@ -31,13 +31,15 @@
 #include <dns/buffer.h>
 #include <dns/message.h>
 #include <dns/rcode.h>
+#include <dns/opcode.h>
 
 #include <asiolink/asiolink.h>
 #include <asiolink/internal/tcpdns.h>
 #include <asiolink/internal/udpdns.h>
 
-#include <log/dummylog.h>
+#include <resolve/resolve.h>
 
+#include <log/dummylog.h>
 
 using namespace asio;
 using asio::ip::udp;
@@ -360,7 +362,8 @@ private:
     OutputBufferPtr buffer_;
 
     // Server to notify when we succeed or fail
-    shared_ptr<DNSServer> server_;
+    //shared_ptr<DNSServer> server_;
+    isc::resolve::ResolverInterface::CallbackPtr resolvercallback_;
 
     /*
      * TODO Do something more clever with timeouts. In the long term, some
@@ -487,7 +490,8 @@ public:
     RunningQuery(asio::io_service& io, const Question &question,
         MessagePtr answer_message, shared_ptr<AddressVector> upstream,
         shared_ptr<AddressVector> upstream_root,
-        OutputBufferPtr buffer, DNSServer* server,
+        OutputBufferPtr buffer,
+        isc::resolve::ResolverInterface::CallbackPtr cb,
         int query_timeout, int client_timeout, int lookup_timeout,
         unsigned retries) :
         io_(io),
@@ -496,7 +500,7 @@ public:
         upstream_(upstream),
         upstream_root_(upstream_root),
         buffer_(buffer),
-        server_(server->clone()),
+        resolvercallback_(cb),
         query_timeout_(query_timeout),
         retries_(retries),
         client_timer(io),
@@ -557,7 +561,7 @@ public:
         // same goes if we have an outstanding query (can't delete
         // until that one comes back to us)
         done_ = true;
-        server_->resume(resume);
+        resolvercallback_->success(answer_message_);
         if (lookup_timer.cancel() != 0) {
             return;
         }
@@ -589,15 +593,19 @@ public:
             }
             
             if (done_) {
-                stop(result == UDPQuery::SUCCESS);
+                resolvercallback_->success(answer_message_);
+                //server_->resume(result == UDPQuery::SUCCESS);
+                delete this;
             }
         } else if (!done_ && retries_--) {
             // We timed out, but we have some retries, so send again
             dlog("Timeout, resending query");
             send();
         } else {
-            // We are done
-            stop(false);
+            // out of retries, give up for now
+            resolvercallback_->failure();
+            //server_->resume(false);
+            delete this;
         }
     }
 };
@@ -605,19 +613,38 @@ public:
 }
 
 void
-RecursiveQuery::sendQuery(const Question& question,
-                          MessagePtr answer_message,
-                          OutputBufferPtr buffer,
-                          DNSServer* server)
+RecursiveQuery::resolve(const isc::dns::QuestionPtr& question,
+    const isc::resolve::ResolverInterface::CallbackPtr callback)
+{
+    asio::io_service& io = dns_service_.get_io_service();
+
+    MessagePtr answer_message(new Message(Message::RENDER));
+    OutputBufferPtr buffer(new OutputBuffer(0));
+    
+    // It will delete itself when it is done
+    new RunningQuery(io, *question, answer_message, upstream_,
+                     upstream_root_, buffer, callback, query_timeout_,
+                     client_timeout_, lookup_timeout_, retries_);
+}
+
+void
+RecursiveQuery::resolve(const Question& question,
+                        MessagePtr answer_message,
+                        OutputBufferPtr buffer,
+                        DNSServer* server)
 {
     // XXX: eventually we will need to be able to determine whether
     // the message should be sent via TCP or UDP, or sent initially via
     // UDP and then fall back to TCP on failure, but for the moment
     // we're only going to handle UDP.
     asio::io_service& io = dns_service_.get_io_service();
+
+    isc::resolve::ResolverInterface::CallbackPtr crs(
+        new isc::resolve::ResolverCallbackServer(server));
+    
     // It will delete itself when it is done
     new RunningQuery(io, question, answer_message, upstream_, upstream_root_,
-                         buffer, server, query_timeout_, client_timeout_,
+                         buffer, crs, query_timeout_, client_timeout_,
                          lookup_timeout_, retries_);
 }
 

+ 41 - 13
src/lib/asiolink/asiolink.h

@@ -31,6 +31,7 @@
 #include <dns/buffer.h>
 #include <dns/message.h>
 #include <dns/question.h>
+#include <dns/rcode.h>
 
 #include <exceptions/exceptions.h>
 
@@ -39,6 +40,8 @@
 #include <asiolink/iomessage.h>
 #include <asiolink/iosocket.h>
 
+#include <resolve/resolver_interface.h>
+
 namespace asio {
 // forward declaration for IOService::get_io_service() below
 class io_service;
@@ -99,6 +102,7 @@ class DNSServiceImpl;
 struct IOServiceImpl;
 struct IntervalTimerImpl;
 
+
 /// \brief An exception that is thrown if an error occurs within the IO
 /// module.  This is mainly intended to be a wrapper exception class for
 /// ASIO specific exceptions.
@@ -529,11 +533,13 @@ class RecursiveQuery {
     ///
     //@{
 public:
-    /// \brief Constructor for use when acting as a forwarder
+    /// \brief Constructor
     ///
     /// This is currently the only way to construct \c RecursiveQuery
-    /// object.  The addresses of the forward nameservers is specified,
-    /// and every upstream query will be sent to one random address.
+    /// object. If the addresses of the forward nameservers is specified,
+    /// and every upstream query will be sent to one random address, and
+    /// the result sent back directly. If not, it will do full resolving.
+    ///
     /// \param dns_service The DNS Service to perform the recursive
     ///        query on.
     /// \param upstream Addresses and ports of the upstream servers
@@ -556,20 +562,42 @@ public:
                    unsigned retries = 3);
     //@}
 
-    /// \brief Initiates an upstream query in the \c RecursiveQuery object.
+    /// \brief Initiate resolving
+    /// 
+    /// When sendQuery() is called, a (set of) message(s) is sent
+    /// asynchronously. If upstream servers are set, one is chosen
+    /// and the response (if any) from that server will be returned.
+    ///
+    /// If not upstream is set, a root server is chosen from the
+    /// root_servers, and the RunningQuery shall do a full resolve
+    /// (i.e. if the answer is a delegation, it will be followed, etc.)
+    /// until there is an answer or an error.
+    ///
+    /// When there is a response or an error and we give up, the given
+    /// CallbackPtr object shall be called (with either success() or
+    /// failure(). See ResolverInterface::Callback for more information.
+    ///
+    /// \param question The question being answered <qname/qclass/qtype>
+    /// \param callback Callback object. See
+    ///        \c ResolverInterface::Callback for more information
+    void resolve(const isc::dns::QuestionPtr& question,
+                 const isc::resolve::ResolverInterface::CallbackPtr callback);
+
+
+    /// \brief Initiates resolving for the given question.
     ///
-    /// When sendQuery() is called, a message is sent asynchronously to
-    /// the upstream name server.  When a reply arrives, 'server'
-    /// is placed on the ASIO service queue via io_service::post(), so
-    /// that the original \c DNSServer objct can resume processing.
+    /// This actually calls the previous sendQuery() with a default
+    /// callback object, which calls resume() on the given DNSServer
+    /// object.
     ///
     /// \param question The question being answered <qname/qclass/qtype>
-    /// \param buffer An output buffer into which the response can be copied
+    /// \param answer_message An output Message into which the final response will be copied
+    /// \param buffer An output buffer into which the intermediate responses will be copied
     /// \param server A pointer to the \c DNSServer object handling the client
-    void sendQuery(const isc::dns::Question& question,
-                   isc::dns::MessagePtr answer_message,
-                   isc::dns::OutputBufferPtr buffer,
-                   DNSServer* server);
+    void resolve(const isc::dns::Question& question,
+                 isc::dns::MessagePtr answer_message,
+                 isc::dns::OutputBufferPtr buffer,
+                 DNSServer* server);
 private:
     DNSService& dns_service_;
     boost::shared_ptr<std::vector<std::pair<std::string, uint16_t> > >

+ 6 - 6
src/lib/asiolink/tests/asiolink_unittest.cc

@@ -678,7 +678,7 @@ TEST_F(ASIOLinkTest, forwarderSend) {
     Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    rq.sendQuery(q, answer, buffer, &server);
+    rq.resolve(q, answer, buffer, &server);
 
     char data[4096];
     size_t size = sizeof(data);
@@ -765,7 +765,7 @@ TEST_F(ASIOLinkTest, forwardQueryTimeout) {
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    query.sendQuery(question, answer, buffer, &server);
+    query.resolve(question, answer, buffer, &server);
 
     // Run the test
     io_service_->run();
@@ -808,7 +808,7 @@ TEST_F(ASIOLinkTest, forwardClientTimeout) {
                          50, 120, 1000, 3);
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
-    query.sendQuery(question, answer, buffer, &server);
+    query.resolve(question, answer, buffer, &server);
 
     // Run the test
     io_service_->run();
@@ -854,7 +854,7 @@ TEST_F(ASIOLinkTest, forwardLookupTimeout) {
                          50, 4000, 120, 5);
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
-    query.sendQuery(question, answer, buffer, &server);
+    query.resolve(question, answer, buffer, &server);
 
     // Run the test
     io_service_->run();
@@ -888,7 +888,7 @@ TEST_F(ASIOLinkTest, DISABLED_recursiveSendOk) {
     Question q(Name("www.isc.org"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    rq.sendQuery(q, answer, buffer, &server);
+    rq.resolve(q, answer, buffer, &server);
     io_service_->run();
 
     // Check that the answer we got matches the one we wanted
@@ -913,7 +913,7 @@ TEST_F(ASIOLinkTest, DISABLED_recursiveSendNXDOMAIN) {
     Question q(Name("wwwdoesnotexist.isc.org"), RRClass::IN(), RRType::A());
     OutputBufferPtr buffer(new OutputBuffer(0));
     MessagePtr answer(new Message(Message::RENDER));
-    rq.sendQuery(q, answer, buffer, &server);
+    rq.resolve(q, answer, buffer, &server);
     io_service_->run();
 
     // Check that the answer we got matches the one we wanted

+ 0 - 1
src/lib/nsas/Makefile.am

@@ -35,7 +35,6 @@ libnsas_la_SOURCES += nsas_entry.h nsas_types.h
 libnsas_la_SOURCES += zone_entry.cc zone_entry.h
 libnsas_la_SOURCES += fetchable.h
 libnsas_la_SOURCES += address_request_callback.h
-libnsas_la_SOURCES += resolver_interface.h
 libnsas_la_SOURCES += random_number_generator.h
 
 CLEANFILES = *.gcno *.gcda

+ 5 - 4
src/lib/nsas/nameserver_address_store.cc

@@ -56,8 +56,8 @@ namespace nsas {
 // hash table, on the assumption that three elements is the longest linear
 // search we want to do when looking up names in the hash table.
 NameserverAddressStore::NameserverAddressStore(
-    boost::shared_ptr<ResolverInterface> resolver, uint32_t zonehashsize,
-    uint32_t nshashsize) :
+    boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
+    uint32_t zonehashsize, uint32_t nshashsize) :
     zone_hash_(new HashTable<ZoneEntry>(new NsasEntryCompare<ZoneEntry>,
         zonehashsize)),
     nameserver_hash_(new HashTable<NameserverEntry>(
@@ -78,8 +78,9 @@ namespace {
  * called at all to create the object, just call the function.
  */
 boost::shared_ptr<ZoneEntry>
-newZone(const boost::shared_ptr<ResolverInterface>* resolver, const string* zone,
-    const RRClass* class_code,
+newZone(
+    const boost::shared_ptr<isc::resolve::ResolverInterface>* resolver,
+    const string* zone, const RRClass* class_code,
     const boost::shared_ptr<HashTable<NameserverEntry> >* ns_hash,
     const boost::shared_ptr<LruList<NameserverEntry> >* ns_lru)
 {

+ 5 - 2
src/lib/nsas/nameserver_address_store.h

@@ -20,6 +20,8 @@
 
 #include <boost/shared_ptr.hpp>
 
+#include <resolve/resolver_interface.h>
+
 #include "nsas_types.h"
 
 namespace isc {
@@ -62,7 +64,8 @@ public:
     /// value of 3001 is the first prime number over 3000, and by implication,
     /// there is an assumption that there will be more nameservers than zones
     /// in the store.
-    NameserverAddressStore(boost::shared_ptr<ResolverInterface> resolver,
+    NameserverAddressStore(
+        boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
         uint32_t zonehashsize = 1009, uint32_t nshashsize = 3001);
 
     /// \brief Destructor
@@ -105,7 +108,7 @@ protected:
     boost::shared_ptr<LruList<NameserverEntry> > nameserver_lru_;
     // The resolver we use
 private:
-    boost::shared_ptr<ResolverInterface> resolver_;
+    boost::shared_ptr<isc::resolve::ResolverInterface> resolver_;
     //}@
 };
 

+ 21 - 5
src/lib/nsas/nameserver_entry.cc

@@ -30,12 +30,14 @@
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <dns/rrttl.h>
+#include <dns/rcode.h>
+#include <dns/opcode.h>
 #include <dns/question.h>
+#include <resolve/resolver_interface.h>
 
 #include "address_entry.h"
 #include "nameserver_address.h"
 #include "nameserver_entry.h"
-#include "resolver_interface.h"
 
 using namespace asiolink;
 using namespace isc::nsas;
@@ -199,7 +201,8 @@ NameserverEntry::setAddressUnreachable(const IOAddress& address) {
  * fed back trough this. It holds a shared pointer to the entry so it is not
  * destroyed too soon.
  */
-class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
+class NameserverEntry::ResolverCallback :
+        public isc::resolve::ResolverInterface::Callback {
     public:
         ResolverCallback(boost::shared_ptr<NameserverEntry> entry,
             AddressFamily family, const RRType& type) :
@@ -213,11 +216,22 @@ class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
          * This extracts the addresses out from the response and puts them
          * inside the entry. It tries to reuse the address entries from before (if there were any), to keep their RTTs.
          */
-        virtual void success(const boost::shared_ptr<AbstractRRset>& response) {
+        virtual void success(MessagePtr response_message) {
             time_t now = time(NULL);
 
             Lock lock(entry_->mutex_);
 
+            // TODO: find the correct RRset, not simply the first
+            if (!response_message ||
+                response_message->getRcode() != isc::dns::Rcode::NOERROR() ||
+                response_message->getRRCount(isc::dns::Message::SECTION_ANSWER) == 0) {
+                failureInternal(lock);
+            }
+                
+            isc::dns::RRsetIterator rrsi =
+                response_message->beginSection(isc::dns::Message::SECTION_ANSWER);
+            const isc::dns::RRsetPtr response = *rrsi;
+            
             vector<AddressEntry> entries;
 
             if (response->getType() != type_ ||
@@ -363,7 +377,8 @@ class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
 };
 
 void
-NameserverEntry::askIP(boost::shared_ptr<ResolverInterface> resolver,
+NameserverEntry::askIP(
+    boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
     const RRType& type, AddressFamily family)
 {
     QuestionPtr question(new Question(Name(getName()), RRClass(getClass()),
@@ -374,7 +389,8 @@ NameserverEntry::askIP(boost::shared_ptr<ResolverInterface> resolver,
 }
 
 void
-NameserverEntry::askIP(boost::shared_ptr<ResolverInterface> resolver,
+NameserverEntry::askIP(
+    boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
     boost::shared_ptr<Callback> callback, AddressFamily family)
 {
     Lock lock(mutex_);

+ 4 - 4
src/lib/nsas/nameserver_entry.h

@@ -36,13 +36,14 @@
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
 
+#include <resolve/resolver_interface.h>
+
 #include "address_entry.h"
 #include "asiolink.h"
 #include "nsas_types.h"
 #include "hash_key.h"
 #include "lru_list.h"
 #include "fetchable.h"
-#include "resolver_interface.h"
 #include "nsas_entry.h"
 #include "nameserver_address.h"
 
@@ -84,7 +85,6 @@ public:
 };
 
 class ZoneEntry;
-class ResolverInterface;
 
 /// \brief Nameserver Entry
 ///
@@ -247,7 +247,7 @@ public:
      *     even when there are addresses, if there are no addresses for this
      *     family.
      */
-    void askIP(boost::shared_ptr<ResolverInterface> resolver,
+    void askIP(boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
         boost::shared_ptr<Callback> callback, AddressFamily family);
     //@}
 
@@ -279,7 +279,7 @@ private:
     /// \short Private version that does the actual asking of one address type
     ///
     /// Call unlocked.
-    void askIP(boost::shared_ptr<ResolverInterface> resolver,
+    void askIP(boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
         const isc::dns::RRType&, AddressFamily);
 };
 

+ 0 - 78
src/lib/nsas/resolver_interface.h

@@ -1,78 +0,0 @@
-// Copyright (C) 2010  CZ NIC
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef __RESOLVER_INTERFACE_H
-#define __RESOLVER_INTERFACE_H
-
-#include <dns/message.h>
-#include <dns/rrset.h>
-
-/**
- * \file resolver_interface.h
- * \short Temporary interface to resolver.
- *
- * This file contains a dummy interface for the resolver, which does not yet
- * exist. When the resolver appears, this file should either wrap its
- * interface or, better, be removed completely.
- */
-
-namespace isc {
-namespace nsas {
-
-/**
- * \short Abstract interface to the resolver.
- *
- * Abstract interface to the resolver. The NameserverAddressStore uses this
- * to ask for addresses. It is here because resolver does not yet exist.
- *
- * It is abstract to allow tests pass dummy resolvers.
- */
-class ResolverInterface {
-    public:
-        /// \short An abstract callback when data from resolver are ready.
-        class Callback {
-            public:
-                /// \short Some data arrived.
-                virtual void success(
-                    const boost::shared_ptr<isc::dns::AbstractRRset>&
-                    response) = 0;
-                /**
-                 * \short No data available.
-                 *
-                 * \todo Pass some reason.
-                 */
-                virtual void failure() = 0;
-                /// \short Virtual destructor, so descendants are cleaned up
-                virtual ~ Callback() {};
-        };
-        typedef boost::shared_ptr<Callback> CallbackPtr;
-        /**
-         * \short Ask a question.
-         *
-         * Asks the resolver a question. Once the answer is ready
-         * the callback is called.
-         *
-         * \param question What to ask. The resolver will decide who.
-         * \param callback What should happen when the answer is ready.
-         */
-        virtual void resolve(const isc::dns::QuestionPtr& question,
-            const CallbackPtr& callback) = 0;
-        /// \short Virtual destructor, so descendants are properly cleaned up
-        virtual ~ ResolverInterface() {}
-};
-
-} // namespace nsas
-} // namespace isc
-
-#endif //__RESOLVER_INTERFACE_H

+ 1 - 1
src/lib/nsas/tests/nameserver_address_store_unittest.cc

@@ -86,7 +86,7 @@ public:
      * if it is asked for by the resolver.
      */
     void lookupAndAnswer(const string& name, const RRClass& class_code,
-        boost::shared_ptr<AbstractRRset> authority,
+        RRsetPtr authority,
         boost::shared_ptr<AddressRequestCallback> callback)
     {
         size_t size(resolver_->requests.size());

+ 3 - 3
src/lib/nsas/tests/nameserver_address_unittest.cc

@@ -39,7 +39,7 @@ class NameserverEntrySample {
 public:
     NameserverEntrySample():
         name_("example.org"),
-        rrv4_(new BasicRRset(name_, RRClass::IN(), RRType::A(), RRTTL(1200)))
+        rrv4_(new RRset(name_, RRClass::IN(), RRType::A(), RRTTL(1200)))
     {
         // Add some sample A records
         rrv4_->addRdata(ConstRdataPtr(new RdataTest<A>("1.2.3.4")));
@@ -50,7 +50,7 @@ public:
         boost::shared_ptr<TestResolver> resolver(new TestResolver);
         ns_->askIP(resolver, boost::shared_ptr<Callback>(new Callback), ANY_OK);
         resolver->asksIPs(name_, 0, 1);
-        resolver->requests[0].second->success(rrv4_);
+        resolver->requests[0].second->success(createResponseMessage(rrv4_));
     }
 
     // Return the sample NameserverEntry
@@ -73,7 +73,7 @@ public:
 
 private:
     Name name_;                             ///< Name of the sample
-    boost::shared_ptr<BasicRRset> rrv4_;           ///< Standard RRSet - IN, A, lowercase name
+    RRsetPtr rrv4_;           ///< Standard RRSet - IN, A, lowercase name
     boost::shared_ptr<NameserverEntry> ns_; ///< Shared_ptr that points to a NameserverEntry object
 
     class Callback : public NameserverEntry::Callback {

+ 8 - 8
src/lib/nsas/tests/nameserver_entry_unittest.cc

@@ -69,10 +69,10 @@ private:
      *     as a failure.
      */
     void fillSet(boost::shared_ptr<TestResolver> resolver, size_t index,
-        boost::shared_ptr<BasicRRset> set)
+        RRsetPtr set)
     {
         if (set) {
-            resolver->requests[index].second->success(set);
+            resolver->requests[index].second->success(createResponseMessage(set));
         } else {
             resolver->requests[index].second->failure();
         }
@@ -80,7 +80,7 @@ private:
 protected:
     /// Fills the nameserver entry with data trough ask IP
     void fillNSEntry(boost::shared_ptr<NameserverEntry> entry,
-        boost::shared_ptr<BasicRRset> rrv4, boost::shared_ptr<BasicRRset> rrv6)
+        RRsetPtr rrv4, RRsetPtr rrv6)
     {
         // Prepare data to run askIP
         boost::shared_ptr<TestResolver> resolver(new TestResolver);
@@ -212,13 +212,13 @@ TEST_F(NameserverEntryTest, ExpirationTime) {
     // Test where there is a single TTL
     boost::shared_ptr<NameserverEntry> alpha(new NameserverEntry(EXAMPLE_CO_UK,
         RRClass::IN()));
-    fillNSEntry(alpha, rrv4_, boost::shared_ptr<BasicRRset>());
+    fillNSEntry(alpha, rrv4_, RRsetPtr());
     expiration = alpha->getExpiration();
     EXPECT_EQ(expiration, curtime + rrv4_->getTTL().getValue());
 
     boost::shared_ptr<NameserverEntry> beta(new NameserverEntry(EXAMPLE_CO_UK,
         RRClass::IN()));
-    fillNSEntry(beta, boost::shared_ptr<BasicRRset>(), rrv6_);
+    fillNSEntry(beta, RRsetPtr(), rrv6_);
     expiration = beta->getExpiration();
     EXPECT_EQ(expiration, curtime + rrv6_->getTTL().getValue());
 
@@ -237,7 +237,7 @@ TEST_F(NameserverEntryTest, ExpirationTime) {
 
     boost::shared_ptr<NameserverEntry> delta(new NameserverEntry(EXAMPLE_CO_UK,
         RRClass::IN()));
-    fillNSEntry(delta, rrv4_, boost::shared_ptr<BasicRRset>());
+    fillNSEntry(delta, rrv4_, RRsetPtr());
     EXPECT_GT(delta->getExpiration(), rrv4_->getTTL().getValue());
 }
 
@@ -347,9 +347,9 @@ TEST_F(NameserverEntryTest, DirectAnswer) {
     resolver->addPresetAnswer(Question(Name(EXAMPLE_CO_UK), RRClass::IN(),
         RRType::AAAA()), rrv6_);
     resolver->addPresetAnswer(Question(Name(EXAMPLE_NET), RRClass::IN(),
-        RRType::A()), boost::shared_ptr<AbstractRRset>());
+        RRType::A()), RRsetPtr());
     resolver->addPresetAnswer(Question(Name(EXAMPLE_NET), RRClass::IN(),
-        RRType::AAAA()), boost::shared_ptr<AbstractRRset>());
+        RRType::AAAA()), RRsetPtr());
 
     // A successfull test first
     entry->askIP(resolver, callback, ANY_OK);

+ 23 - 8
src/lib/nsas/tests/nsas_test.h

@@ -25,18 +25,33 @@
 
 #include <config.h>
 
+#include <dns/message.h>
 #include <dns/buffer.h>
 #include <dns/rdata.h>
 #include <dns/rrtype.h>
 #include <dns/rrttl.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdataclass.h>
+#include <resolve/resolver_interface.h>
 #include "../nsas_entry.h"
-#include "../resolver_interface.h"
 
 using namespace isc::dns::rdata;
 using namespace isc::dns;
 
+namespace {
+    MessagePtr
+    createResponseMessage(RRsetPtr answer_rrset)
+    {
+        MessagePtr response(new Message(Message::RENDER));
+        response->setOpcode(Opcode::QUERY());
+        response->setRcode(Rcode::NOERROR());
+        response->addRRset(Message::SECTION_ANSWER, answer_rrset);
+        return response;
+    }
+}
+
 namespace isc {
 namespace dns {
 
@@ -217,13 +232,13 @@ using namespace std;
  * This pretends to be a resolver. It stores the queries and
  * they can be answered.
  */
-class TestResolver : public isc::nsas::ResolverInterface {
+class TestResolver : public isc::resolve::ResolverInterface {
     private:
         bool checkIndex(size_t index) {
             return (requests.size() > index);
         }
 
-        typedef std::map<isc::dns::Question, boost::shared_ptr<AbstractRRset> >
+        typedef std::map<isc::dns::Question, RRsetPtr >
             PresetAnswers;
         PresetAnswers answers_;
     public:
@@ -235,7 +250,7 @@ class TestResolver : public isc::nsas::ResolverInterface {
                 requests.push_back(Request(q, c));
             } else {
                 if (it->second) {
-                    c->success(it->second);
+                    c->success(createResponseMessage(it->second));
                 } else {
                     c->failure();
                 }
@@ -248,7 +263,7 @@ class TestResolver : public isc::nsas::ResolverInterface {
          * it goes to requests and you can answer later.
          */
         void addPresetAnswer(const isc::dns::Question& question,
-            boost::shared_ptr<AbstractRRset> answer)
+            RRsetPtr answer)
         {
             answers_[question] = answer;
         }
@@ -308,11 +323,11 @@ class TestResolver : public isc::nsas::ResolverInterface {
             RRsetPtr set(new RRset(name, RRClass::IN(),
                 type, RRTTL(TTL)));
             set->addRdata(rdata);
-            requests[index].second->success(set);
+            requests[index].second->success(createResponseMessage(set));
         }
 
         void provideNS(size_t index,
-            boost::shared_ptr<AbstractRRset> nameservers)
+            RRsetPtr nameservers)
         {
             if (index >= requests.size()) {
                 throw NoSuchRequest();
@@ -322,7 +337,7 @@ class TestResolver : public isc::nsas::ResolverInterface {
             {
                 throw DifferentRequest();
             }
-            requests[index].second->success(nameservers);
+            requests[index].second->success(createResponseMessage(nameservers));
         }
 };
 

+ 5 - 4
src/lib/nsas/tests/zone_entry_unittest.cc

@@ -42,7 +42,8 @@ namespace {
 /// \brief Inherited version with access into its internals for tests
 class InheritedZoneEntry : public ZoneEntry {
     public:
-        InheritedZoneEntry(boost::shared_ptr<ResolverInterface> resolver,
+        InheritedZoneEntry(
+            boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
             const std::string& name, const RRClass& class_code,
             boost::shared_ptr<HashTable<NameserverEntry> > nameserver_table,
             boost::shared_ptr<LruList<NameserverEntry> > nameserver_lru) :
@@ -459,7 +460,7 @@ TEST_F(ZoneEntryTest, DirectAnswer) {
 
     // One unsuccessfull attempt, nameservers fail
     resolver_->addPresetAnswer(Question(Name(EXAMPLE_CO_UK), RRClass::IN(),
-        RRType::NS()), boost::shared_ptr<AbstractRRset>());
+        RRType::NS()), RRsetPtr());
     zone->addCallback(callback_, ANY_OK);
     EXPECT_EQ(0, callback_->successes_.size());
     EXPECT_EQ(1, callback_->unreachable_count_);
@@ -493,9 +494,9 @@ TEST_F(ZoneEntryTest, DirectAnswer) {
     callback_->successes_.clear();
     // Now, pretend we do not have IP addresses
     resolver_->addPresetAnswer(Question(ns_name, RRClass::IN(), RRType::A()),
-        boost::shared_ptr<AbstractRRset>());
+        RRsetPtr());
     resolver_->addPresetAnswer(Question(ns_name, RRClass::IN(),
-        RRType::AAAA()), boost::shared_ptr<AbstractRRset>());
+        RRType::AAAA()), RRsetPtr());
     // Get another zone and ask it again. It should fail.
     // Clean the table first, though, so it does not find the old nameserver
     nameserver_table_->remove(HashKey(ns_name.toText(), RRClass::IN()));

+ 19 - 3
src/lib/nsas/zone_entry.cc

@@ -22,6 +22,7 @@
 #include <boost/foreach.hpp>
 #include <boost/bind.hpp>
 #include <dns/rrttl.h>
+#include <dns/rcode.h>
 #include <dns/rdataclass.h>
 
 using namespace std;
@@ -32,7 +33,8 @@ using namespace dns;
 
 namespace nsas {
 
-ZoneEntry::ZoneEntry(boost::shared_ptr<ResolverInterface> resolver,
+ZoneEntry::ZoneEntry(
+    boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
     const std::string& name, const isc::dns::RRClass& class_code,
     boost::shared_ptr<HashTable<NameserverEntry> > nameserver_table,
     boost::shared_ptr<LruList<NameserverEntry> > nameserver_lru) :
@@ -73,7 +75,8 @@ newNs(const std::string* name, const RRClass* class_code) {
  * code. It manipulates directly ZoneEntry's data members, locks it and like
  * that. Mostly eliminates C++ bad design of missing lambda functions.
  */
-class ZoneEntry::ResolverCallback : public ResolverInterface::Callback {
+class ZoneEntry::ResolverCallback :
+        public isc::resolve::ResolverInterface::Callback {
     public:
         /// \short Constructor. Pass "this" zone entry
         ResolverCallback(boost::shared_ptr<ZoneEntry> entry) :
@@ -90,8 +93,21 @@ class ZoneEntry::ResolverCallback : public ResolverInterface::Callback {
          * examining them and seeing if some addresses are already there
          * and to ask for the rest of them.
          */
-        virtual void success(const boost::shared_ptr<AbstractRRset>& answer) {
+        virtual void success(MessagePtr response_message) {
             Lock lock(entry_->mutex_);
+
+            // TODO: find the correct RRset, not simply the first
+            if (!response_message ||
+                response_message->getRcode() != isc::dns::Rcode::NOERROR() ||
+                response_message->getRRCount(isc::dns::Message::SECTION_ANSWER) == 0) {
+                // todo: define this
+                failureInternal(300);
+            }
+
+            isc::dns::RRsetIterator rrsi =
+                response_message->beginSection(isc::dns::Message::SECTION_ANSWER);
+            const isc::dns::RRsetPtr answer = *rrsi;
+
             RdataIteratorPtr iterator(answer->getRdataIterator());
             // If there are no data
             if (iterator->isLast()) {

+ 5 - 3
src/lib/nsas/zone_entry.h

@@ -36,11 +36,12 @@
 
 #include <dns/rrset.h>
 
+#include <resolve/resolver_interface.h>
+
 #include "hash_key.h"
 #include "nsas_entry.h"
 #include "asiolink.h"
 #include "fetchable.h"
-#include "resolver_interface.h"
 #include "nsas_types.h"
 #include "random_number_generator.h"
 
@@ -76,7 +77,8 @@ public:
      * \todo Move to cc file, include the lookup (if NSAS uses resolver for
      *     everything)
      */
-    ZoneEntry(boost::shared_ptr<ResolverInterface> resolver,
+    ZoneEntry(
+        boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
         const std::string& name, const isc::dns::RRClass& class_code,
         boost::shared_ptr<HashTable<NameserverEntry> > nameserver_table,
         boost::shared_ptr<LruList<NameserverEntry> > nameserver_lru);
@@ -151,7 +153,7 @@ private:
     void process(AddressFamily family,
         const boost::shared_ptr<NameserverEntry>& nameserver);
     // Resolver we use
-    boost::shared_ptr<ResolverInterface> resolver_;
+    boost::shared_ptr<isc::resolve::ResolverInterface> resolver_;
     // We store the nameserver table and lru, so we can look up when there's
     // update
     boost::shared_ptr<HashTable<NameserverEntry> > nameserver_table_;

+ 17 - 0
src/lib/resolve/Makefile.am

@@ -0,0 +1,17 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += $(SQLITE_CFLAGS)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda
+
+lib_LTLIBRARIES = libresolve.la
+libresolve_la_SOURCES = resolve.h
+libresolve_la_SOURCES += resolver_interface.h
+libresolve_la_SOURCES += resolver_callback.h resolver_callback.cc
+libresolve_la_LIBADD = $(top_builddir)/src/lib/dns/libdns++.la
+libresolve_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la

+ 20 - 0
src/lib/resolve/resolve.h

@@ -0,0 +1,20 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef _ISC_RESOLVE_H
+#define _ISC_RESOLVE_H 1
+
+#include <resolve/resolver_interface.h>
+#include <resolve/resolver_callback.h>
+#endif // ISC_RESOLVE_H_

+ 36 - 0
src/lib/resolve/resolver_callback.cc

@@ -0,0 +1,36 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <resolve/resolver_callback.h>
+
+namespace isc {
+namespace resolve {
+
+void
+ResolverCallbackServer::success(const isc::dns::MessagePtr response)
+{
+    // ignore our response here
+    (void)response;
+    
+    server_->resume(true);
+}
+
+void
+ResolverCallbackServer::failure()
+{
+    server_->resume(false);
+}
+
+} // namespace resolve
+} // namespace isc

+ 48 - 0
src/lib/resolve/resolver_callback.h

@@ -0,0 +1,48 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef _ISC_RESOLVER_CALLBACK_H
+#define _ISC_RESOLVER_CALLBACK_H 1
+
+#include <asiolink/asiolink.h>
+#include <dns/message.h>
+
+namespace isc {
+namespace resolve {
+
+/// \short Standard Callback for sendQuery for DNSServer instances
+///
+/// This is a standard ResolverInterface::Callback implementation
+/// that is used by Resolver; when RunningQuery finishes and has either
+/// some data or an error, DNSServer::resume() will be called.
+///
+/// This class will ignore the response MessagePtr in the callback,
+/// as the server itself should also have a reference.
+class ResolverCallbackServer : public ResolverInterface::Callback {
+public:
+    ResolverCallbackServer(asiolink::DNSServer* server) :
+        server_(server->clone()) {}
+    ~ResolverCallbackServer() { delete server_; };
+    
+    void success(const isc::dns::MessagePtr response);
+    void failure();
+
+private:
+    asiolink::DNSServer* server_;
+};
+
+} //namespace resolve
+} //namespace isc
+
+#endif // ISC_RESOLVER_CALLBACK_H_

+ 98 - 0
src/lib/resolve/resolver_interface.h

@@ -0,0 +1,98 @@
+// Copyright (C) 2010  CZ NIC
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __RESOLVER_INTERFACE_H
+#define __RESOLVER_INTERFACE_H
+
+#include <dns/message.h>
+
+///
+/// \file resolver_interface.h
+/// \short Interface to resolver.
+///
+/// This file contains an interface for the resolver. By subclassing
+/// this abstract interface, other parts of the system can ask the
+/// resolver to do some resolving too.
+///
+/// This is done by creating a subclass of ResolverInterface::Callback,
+/// which defines what to do with the result, and then calling resolve()
+/// on the ResolverInterface implementation.
+///
+/// One default Callback subclass is provided right now, in
+/// resolver_callback.[h|cc], which calls resumse() on a given DNSServer
+///
+
+namespace isc {
+namespace resolve {
+
+///
+/// \short Abstract interface to the resolver.
+///
+/// Abstract interface to the resolver. The NameserverAddressStore uses this
+/// to ask for addresses. It is here because resolver does not yet exist.
+///
+/// It is abstract to allow tests pass dummy resolvers.
+///
+class ResolverInterface {
+    public:
+        /// \short An abstract callback for when the resolver is done.
+        ///
+        /// You can pass an instance of a subclass of this (as a
+        /// CallbackPtr) to RecursiveQuery::sendQuery(), and when it
+        /// is done, it will either call success() if there is an
+        /// answer MessagePtr, or failure(), if the resolver was not
+        /// able to find anything.
+        ///
+        /// Note that a result Message does not necessarily contain
+        /// the actual answer (it could be a noerror/nodata response).
+        class Callback {
+            public:
+                /// \short Some data arrived.
+                virtual void success(const isc::dns::MessagePtr response) = 0;
+                
+                ///
+                ///\short No data available.
+                ///
+                ///\todo Provide error reason (result of the
+                ///      classification call, for instance? We'd also
+                ///      need some way to say 'everything times out')
+                ///
+                virtual void failure() = 0;
+
+                /// \short Virtual destructor, so descendants are cleaned up
+                virtual ~Callback() {};
+        };
+
+        typedef boost::shared_ptr<Callback> CallbackPtr;
+
+        ///
+        ///\short Ask a question.
+        ///
+        /// Asks the resolver a question. Once the answer is ready
+        /// the callback is called.
+        ///
+        /// \param question What to ask. The resolver will decide who.
+        /// \param callback What should happen when the answer is ready.
+        ///
+        virtual void resolve(const isc::dns::QuestionPtr& question,
+            const CallbackPtr& callback) = 0;
+
+        /// \short Virtual destructor, so descendants are properly cleaned up
+        virtual ~ ResolverInterface() {}
+};
+
+} // namespace nsas
+} // namespace isc
+
+#endif //__RESOLVER_INTERFACE_H

+ 24 - 0
src/lib/resolve/tests/Makefile.am

@@ -0,0 +1,24 @@
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += resolver_callback_unittest.cc
+
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD +=  $(top_builddir)/src/lib/resolve/libresolve.la
+
+endif
+
+noinst_PROGRAMS = $(TESTS)

+ 90 - 0
src/lib/resolve/tests/resolver_callback_unittest.cc

@@ -0,0 +1,90 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+#include <resolve/resolver_callback.h>
+#include <asiolink/asiolink.h>
+
+using namespace isc::resolve;
+
+// Dummy subclass for DNSServer*
+// We want to check if resume is called
+// Since the server will get cloned(), we want the clones to share
+// our bools for whether resume got called and with what value
+class DummyServer : public asiolink::DNSServer {
+public:
+    DummyServer(DummyServer* orig) {
+        resume_called_ = orig->getResumeCalled();
+        resume_value_ = orig->getResumeValue();
+    }
+    DummyServer(bool* resume_called, bool* resume_value) :
+        resume_called_(resume_called), resume_value_(resume_value)
+    {}
+    
+    bool* getResumeCalled() { return resume_called_; }
+    bool* getResumeValue() { return resume_value_; }
+    
+    DNSServer* clone() {
+        DummyServer* n = new DummyServer(this);
+        return n;
+    }
+
+    void resume(bool value) {
+        *resume_called_ = true;
+        *resume_value_ = value;
+    }
+
+private:
+    bool* resume_called_;
+    bool* resume_value_;
+};
+
+class ResolverCallbackServerTest : public ::testing::Test {
+public:
+    ResolverCallbackServerTest() : resume_called_(false),
+                                   resume_value_(false) {
+        server_ = new DummyServer(&resume_called_, &resume_value_);
+        callback_ = new ResolverCallbackServer(server_);
+    };
+
+    ~ResolverCallbackServerTest() {
+        delete callback_;
+        delete server_;
+    }
+
+    DummyServer* getServer() { return server_; }
+    ResolverCallbackServer* getCallback() { return callback_; }
+    bool getResumeCalled() { return resume_called_; }
+    bool getResumeValue() { return resume_value_; }
+
+private:
+    DummyServer* server_;
+    ResolverCallbackServer* callback_;
+    bool resume_called_;
+    bool resume_value_;
+};
+
+TEST_F(ResolverCallbackServerTest, testSuccess) {
+    EXPECT_FALSE(getResumeCalled());
+    getCallback()->success(isc::dns::MessagePtr());
+    EXPECT_TRUE(getResumeCalled());
+    EXPECT_TRUE(getResumeValue());
+}
+
+TEST_F(ResolverCallbackServerTest, testFailure) {
+    EXPECT_FALSE(getResumeCalled());
+    getCallback()->failure();
+    EXPECT_TRUE(getResumeCalled());
+    EXPECT_FALSE(getResumeValue());
+}

+ 24 - 0
src/lib/resolve/tests/run_unittests.cc

@@ -0,0 +1,24 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    return (RUN_ALL_TESTS());
+}

+ 1 - 0
src/lib/testutils/srv_test.cc

@@ -33,6 +33,7 @@ const char* const DEFAULT_REMOTE_ADDRESS = "192.0.2.1";
 
 SrvTestBase::SrvTestBase() : request_message(Message::RENDER),
                              parse_message(new Message(Message::PARSE)),
+                             response_message(new Message(Message::RENDER)),
                              default_qid(0x1035),
                              opcode(Opcode(Opcode::QUERY())),
                              qname("www.example.com"),

+ 1 - 1
src/lib/testutils/srv_test.h

@@ -89,8 +89,8 @@ protected:
     MockSession notify_session;
     MockServer dnsserv;
     isc::dns::Message request_message;
-    isc::dns::MessagePtr response_message;
     isc::dns::MessagePtr parse_message;
+    isc::dns::MessagePtr response_message;
     const isc::dns::qid_t default_qid;
     const isc::dns::Opcode opcode;
     const isc::dns::Name qname;