Browse Source

[trac494] initial abstraction for runningquery results

Added a abstract placeholder for callbacks in asio (for now); which has
two subclasses; one takes a DNSServer* and calls resume() on it when the
runningquery finished its lookup (or fails), the other one is provided a
callback as defined in isc::nsas::ResolverInterface.

These are more objects that are newed while running and delete
themselves, and they may not even be necessary, but for now this makes
it work while doing the least amount of changes in other parts.

RunnigQuery now takes one of these objects instead of a DNSServer*, and
the objects decide what should be done once it is ready.

Things to do:
- remove the temporary MyCallback class from resolver (perhaps move it
  to a unittest)
- move ResolverInterface out of nsas, as well as its Callback thingy,
  and merge it with the new callback holders
- general cleanup and tests (although, as with current resolver tests,
  need framework to fake outside query handling)
Jelte Jansen 14 years ago
parent
commit
8a175757cd

+ 1 - 1
src/bin/msgq/msgq.py.in

@@ -190,7 +190,7 @@ class MsgQ:
         # TODO: When we have logging, we might want
         # to add a debug message here that a new connection
         # was made
-        self.register_socket(self, newsocket)
+        self.register_socket(newsocket)
 
     def register_socket(self, newsocket):
         """

+ 51 - 0
src/bin/resolver/resolver.cc

@@ -126,6 +126,9 @@ public:
         }
     }
 
+    void resolve(const isc::dns::QuestionPtr& question,
+                 const isc::nsas::ResolverInterface::CallbackPtr& callback);
+
     void processNormalQuery(const Question& question,
                             MessagePtr answer_message,
                             OutputBufferPtr buffer,
@@ -341,6 +344,36 @@ Resolver::getConfigSession() const {
     return (impl_->config_session_);
 }
 
+/* tmp for in-dev testing */
+class MyCallback : public nsas::ResolverInterface::Callback {
+public:
+    virtual void success(
+        const boost::shared_ptr<isc::dns::AbstractRRset>&
+        response) {
+        std::cout << "[XX] CALLBACK FOR LOOKUP!" << std::endl;
+        std::cout << "[XX] GOT: " << *response << std::endl;
+        std::cout << "[XX] END" << std::endl;
+    };
+
+    virtual void failure() {
+        std::cout << "[XX] internal lookup failed" << std::endl;
+    }
+
+    ~MyCallback() {
+        std::cout << "[XX] MyCallback deleted!" << std::endl;
+    }
+};
+
+void
+Resolver::resolve(const isc::dns::QuestionPtr& question,
+                  const isc::nsas::ResolverInterface::CallbackPtr& callback)
+{
+    std::cout << "[XX] asked to resolve: " << *question << std::endl;
+    impl_->resolve(question, callback);
+    std::cout << "[XX] done?" << std::endl;
+}
+
+
 void
 Resolver::processMessage(const IOMessage& io_message,
                          MessagePtr query_message,
@@ -348,6 +381,17 @@ Resolver::processMessage(const IOMessage& io_message,
                          OutputBufferPtr buffer,
                          DNSServer* server)
 {
+    std::cout << "[XX] remove this :p" << std::endl;
+    QuestionPtr q(new Question(Name("www.tjeb.nl"), RRClass::IN(), RRType::A()));
+    boost::shared_ptr<MyCallback> callback(new MyCallback());
+
+    std::cout << "[XX] CREATED CALLBACK AT " << callback << std::endl;
+
+    resolve(q, callback);
+    //resolve(q, callback);
+    std::cout << "[XX] up to here" << std::endl;
+
+
     dlog("Got a DNS message");
     InputBuffer request_buffer(io_message.getData(), io_message.getDataSize());
     // First, check the header part.  If we fail even for the base header,
@@ -425,6 +469,13 @@ Resolver::processMessage(const IOMessage& io_message,
 }
 
 void
+ResolverImpl::resolve(const QuestionPtr& question,
+                      const isc::nsas::ResolverInterface::CallbackPtr& callback)
+{
+    rec_query_->sendQuery(question, callback);
+}
+
+void
 ResolverImpl::processNormalQuery(const Question& question,
                                  MessagePtr answer_message,
                                  OutputBufferPtr buffer,

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

@@ -24,6 +24,8 @@
 
 #include <asiolink/asiolink.h>
 
+#include <nsas/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::nsas::ResolverInterface {
     ///
     /// \name Constructors, Assignment Operator and Destructor.
     ///
@@ -51,6 +53,9 @@ public:
     ~Resolver();
     //@}
 
+    virtual void resolve(const isc::dns::QuestionPtr& question,
+                         const isc::nsas::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

+ 61 - 8
src/lib/asiolink/asiolink.cc

@@ -31,6 +31,7 @@
 #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>
@@ -38,7 +39,6 @@
 
 #include <log/dummylog.h>
 
-
 using namespace asio;
 using asio::ip::udp;
 using asio::ip::tcp;
@@ -354,7 +354,8 @@ private:
     OutputBufferPtr buffer_;
 
     // Server to notify when we succeed or fail
-    shared_ptr<DNSServer> server_;
+    //shared_ptr<DNSServer> server_;
+    AbstractResolverCallback* resolvercallback_;
 
     /*
      * TODO Do something more clever with timeouts. In the long term, some
@@ -475,7 +476,10 @@ 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, int timeout,
+        OutputBufferPtr buffer,
+        //DNSServer* server,
+        AbstractResolverCallback* cb,
+        int timeout,
         unsigned retries) :
         io_(io),
         question_(question),
@@ -483,7 +487,8 @@ public:
         upstream_(upstream),
         upstream_root_(upstream_root),
         buffer_(buffer),
-        server_(server->clone()),
+        //server_(server->clone()),
+        resolvercallback_(cb),
         timeout_(timeout),
         retries_(retries),
         zone_servers_()
@@ -533,7 +538,8 @@ public:
             }
             
             if (done) {
-                server_->resume(result == UDPQuery::SUCCESS);
+                resolvercallback_->callback(result == UDPQuery::SUCCESS);
+                //server_->resume(result == UDPQuery::SUCCESS);
                 delete this;
             }
         } else if (retries_--) {
@@ -542,7 +548,8 @@ public:
             send();
         } else {
             // out of retries, give up for now
-            server_->resume(false);
+            resolvercallback_->callback(false);
+            //server_->resume(false);
             delete this;
         }
     }
@@ -551,6 +558,23 @@ public:
 }
 
 void
+RecursiveQuery::sendQuery(const isc::dns::QuestionPtr& question,
+    const isc::nsas::ResolverInterface::CallbackPtr callback)
+{
+    asio::io_service& io = dns_service_.get_io_service();
+
+    MessagePtr answer_message(new Message(Message::RENDER));
+    answer_message->setOpcode(isc::dns::Opcode::QUERY());
+    OutputBufferPtr buffer(new OutputBuffer(0));
+    ResolverCallbackDirect* rcd = new ResolverCallbackDirect(callback,
+                                                             answer_message);
+    
+    // It will delete itself when it is done
+    new RunningQuery(io, *question, answer_message, upstream_,
+                     upstream_root_, buffer, rcd, timeout_, retries_);
+}
+
+void
 RecursiveQuery::sendQuery(const Question& question,
                           MessagePtr answer_message,
                           OutputBufferPtr buffer,
@@ -561,11 +585,40 @@ RecursiveQuery::sendQuery(const Question& question,
     // 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();
+
+    ResolverCallbackServer* crs = new ResolverCallbackServer(server);
+    
     // It will delete itself when it is done
-    new RunningQuery(io, question, answer_message, upstream_, upstream_root_,
-                         buffer, server, timeout_, retries_);
+    new RunningQuery(io, question, answer_message, upstream_,
+                     upstream_root_, buffer, crs, timeout_, retries_);
+}
+
+void
+ResolverCallbackServer::callback(bool result) {
+    server_->resume(result);
+    delete server_;
+    delete this;
+}
+
+void
+ResolverCallbackDirect::callback(bool result)
+{
+    // simply return with the first rrset from answer right now
+    if (result &&
+        answer_message_->getRcode() == isc::dns::Rcode::NOERROR() &&
+        answer_message_->getRRCount(isc::dns::Message::SECTION_ANSWER) > 0) {
+        std::cout << *answer_message_ << std::endl;
+        isc::dns::RRsetIterator rrsi = answer_message_->beginSection(isc::dns::Message::SECTION_ANSWER);
+        const isc::dns::RRsetPtr result = *rrsi;
+        callback_->success(result);
+    } else {
+        callback_->failure();
+    }
+    // once called back we don't need ourselves anymore
+    delete this;
 }
 
+
 class IntervalTimerImpl {
 private:
     // prohibit copy

+ 45 - 0
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 <nsas/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.
@@ -367,6 +371,43 @@ private:
     DNSServer* self_;
 };
 
+// We define two types of callbackholders for processing recursive
+// queries; one calls back the original DNSServer to resume()
+// the other uses direct callbacks (for instance when we need to
+// resolve something ourselves)
+// Caller warning: only callback once! The objects will delete
+// themselves on callback (after they have done they callback)
+class AbstractResolverCallback {
+public:
+    ~AbstractResolverCallback() {};
+    virtual void callback(bool result) = 0;
+};
+
+class ResolverCallbackServer : public AbstractResolverCallback {
+public:
+    ResolverCallbackServer(DNSServer* server) :
+        server_(server->clone()) {}
+    void callback(bool result);
+
+private:
+    DNSServer* server_;
+};
+
+class ResolverCallbackDirect : public AbstractResolverCallback {
+public:
+    ResolverCallbackDirect(
+        const isc::nsas::ResolverInterface::CallbackPtr callback,
+        isc::dns::MessagePtr answer_message) :
+            callback_(callback),
+            answer_message_(answer_message) {}
+    void callback(bool result);
+
+private:
+    const isc::nsas::ResolverInterface::CallbackPtr callback_;
+    isc::dns::MessagePtr answer_message_;
+};
+        
+
 /// \brief The \c DNSLookup class is an abstract base class for a DNS
 /// Lookup provider function.
 ///
@@ -553,6 +594,10 @@ public:
                    int timeout = -1, unsigned retries = 0);
     //@}
 
+    void sendQuery(const isc::dns::QuestionPtr& question,
+                   const isc::nsas::ResolverInterface::CallbackPtr callback);
+
+
     /// \brief Initiates an upstream query in the \c RecursiveQuery object.
     ///
     /// When sendQuery() is called, a message is sent asynchronously to