Browse Source

Tests and interface for timeouts in RecursiveQuery

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/vorner-recursor-timeouts@3409 e5f2f494-b856-4b98-b285-d166d9295462
Michal Vaner 14 years ago
parent
commit
0e4b8f1461

+ 10 - 1
src/lib/asiolink/asiolink.cc

@@ -218,12 +218,21 @@ DNSService::DNSService(IOService& io_service,
     impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
     impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
 }
 }
 
 
+// TODO This should be removed upon merge with the configuration
+DNSService::DNSService(IOService& io_service, SimpleCallback *checkin,
+    DNSLookup* lookup, DNSAnswer* answer) :
+    impl_(NULL), io_service_(io_service)
+{
+    impl_ = new DNSServiceImpl(io_service, *"0", NULL, NULL, checkin, lookup,
+        answer);
+}
+
 DNSService::~DNSService() {
 DNSService::~DNSService() {
     delete impl_;
     delete impl_;
 }
 }
 
 
 RecursiveQuery::RecursiveQuery(DNSService& dns_service, const char& forward,
 RecursiveQuery::RecursiveQuery(DNSService& dns_service, const char& forward,
-                               uint16_t port) :
+    uint16_t port, int timeout, unsigned retries) :
     dns_service_(dns_service), ns_addr_(&forward), port_(port) 
     dns_service_(dns_service), ns_addr_(&forward), port_(port) 
 {}
 {}
 
 

+ 9 - 1
src/lib/asiolink/asiolink.h

@@ -207,6 +207,9 @@ public:
                const bool use_ipv4, const bool use_ipv6,
                const bool use_ipv4, const bool use_ipv6,
                SimpleCallback* checkin, DNSLookup* lookup,
                SimpleCallback* checkin, DNSLookup* lookup,
                DNSAnswer* answer);
                DNSAnswer* answer);
+    /// TODO This is temporary, until we merge with the config
+    DNSService(IOService& io_service, SimpleCallback* checkin,
+        DNSLookup* lookup, DNSAnswer* answer);
     /// \brief The destructor.
     /// \brief The destructor.
     ~DNSService();
     ~DNSService();
     //@}
     //@}
@@ -517,8 +520,13 @@ public:
     ///        query on
     ///        query on
     /// \param forward The address of the nameserver to forward to
     /// \param forward The address of the nameserver to forward to
     /// \param port The remote port to send the dns query to
     /// \param port The remote port to send the dns query to
+    /// \param timeout How long to timeout the query, in ms
+    ///     -1 means never timeout (but do not use that).
+    ///     TODO: This should be computed somehow dynamically in future
+    /// \param retries how many times we try again (0 means just send and
+    //      and return if it returs).
     RecursiveQuery(DNSService& dns_service, const char& forward,
     RecursiveQuery(DNSService& dns_service, const char& forward,
-                   uint16_t port = 53);
+                   uint16_t port = 53, int timeout = -1, unsigned retries = 0);
     //@}
     //@}
 
 
     /// \brief Initiates an upstream query in the \c RecursiveQuery object.
     /// \brief Initiates an upstream query in the \c RecursiveQuery object.

+ 78 - 1
src/lib/asiolink/tests/asiolink_unittest.cc

@@ -20,6 +20,7 @@
 #include <string.h>
 #include <string.h>
 
 
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
+#include <boost/bind.hpp>
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
@@ -34,10 +35,14 @@
 #include <asiolink/internal/tcpdns.h>
 #include <asiolink/internal/tcpdns.h>
 #include <asiolink/internal/udpdns.h>
 #include <asiolink/internal/udpdns.h>
 
 
+#include <asio.hpp>
+
 using isc::UnitTestUtil;
 using isc::UnitTestUtil;
 using namespace std;
 using namespace std;
 using namespace asiolink;
 using namespace asiolink;
 using namespace isc::dns;
 using namespace isc::dns;
+using namespace asio;
+using asio::ip::udp;
 
 
 namespace {
 namespace {
 const char* const TEST_SERVER_PORT = "53535";
 const char* const TEST_SERVER_PORT = "53535";
@@ -365,6 +370,16 @@ protected:
                                       NULL, NULL);
                                       NULL, NULL);
     }
     }
 
 
+    // Set up empty DNS Service
+    void setDNSService() {
+        delete dns_service_;
+        dns_service_ = NULL;
+        delete io_service_;
+        io_service_ = new IOService();
+        callback_ = new ASIOCallBack(this);
+        dns_service_ = new DNSService(*io_service_, callback_, NULL, NULL);
+    }
+
     // Run a simple server test, on either IPv4 or IPv6, and over either
     // Run a simple server test, on either IPv4 or IPv6, and over either
     // UDP or TCP.  Calls the sendUDP() or sendTCP() methods, which will
     // UDP or TCP.  Calls the sendUDP() or sendTCP() methods, which will
     // start the IO Service queue.  The UDPServer or TCPServer that was
     // start the IO Service queue.  The UDPServer or TCPServer that was
@@ -433,10 +448,11 @@ protected:
             }
             }
         }
         }
 
 
-    private:
+    protected:
         asio::io_service& io_;
         asio::io_service& io_;
         bool done_;
         bool done_;
 
 
+    private:
         // Currently unused; these will be used for testing
         // Currently unused; these will be used for testing
         // asynchronous lookup calls via the asyncLookup() method
         // asynchronous lookup calls via the asyncLookup() method
         boost::shared_ptr<asiolink::IOMessage> io_message_;
         boost::shared_ptr<asiolink::IOMessage> io_message_;
@@ -449,6 +465,28 @@ protected:
         const DNSAnswer* answer_;
         const DNSAnswer* answer_;
     };
     };
 
 
+    // This version of mock server just stops the io_service when it is resumed
+    class MockServerStop : public MockServer {
+        public:
+            explicit MockServerStop(asio::io_service& io_service) :
+                MockServer(io_service, asio::ip::address(), 0)
+            {}
+
+            void operator()(asio::error_code ec = asio::error_code(),
+                            size_t length = 0)
+            {
+                io_.stop();
+            }
+
+            DNSServer* clone() {
+                return (new MockServerStop(*this));
+            }
+
+            bool done() const {
+                return done_;
+            }
+    };
+
 private:
 private:
     class ASIOCallBack : public SimpleCallback {
     class ASIOCallBack : public SimpleCallback {
     public:
     public:
@@ -607,4 +645,43 @@ TEST_F(ASIOLinkTest, recursiveSend) {
     EXPECT_EQ(q.getClass(), q2->getClass());
     EXPECT_EQ(q.getClass(), q2->getClass());
 }
 }
 
 
+void
+receive_and_inc(udp::socket* socket, int* num) {
+    *num ++;
+    static char inbuff[512];
+    socket->async_receive(asio::buffer(inbuff, 512),
+        boost::bind(receive_and_inc, socket, num));
+}
+
+// Test it tries the correct amount of times before giving up
+TEST_F(ASIOLinkTest, recursiveTimeout) {
+    // Prepare the service (we do not use the common setup, we do not answer
+    setDNSService();
+    asio::io_service& service = io_service_->get_io_service();
+
+    // Prepare the socket
+    uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
+    udp::socket socket(service, udp::v4());
+    socket.set_option(socket_base::reuse_address(true));
+    socket.bind(udp::endpoint(ip::address::from_string(TEST_IPV4_ADDR), port));
+    // And count the answers
+    int num = -1; // One is counted before the receipt of the first one
+    receive_and_inc(&socket, &num);
+
+    // Prepare the server
+    MockServerStop server(service);
+
+    // Do the answer
+    RecursiveQuery query(*dns_service_, *TEST_IPV4_ADDR, port, 10, 2);
+    Question question(Name("example.net"), RRClass::IN(), RRType::A());
+    OutputBufferPtr buffer(new OutputBuffer(0));
+    query.sendQuery(question, buffer, &server);
+
+    // Run the test
+    service.run();
+
+    EXPECT_TRUE(server.done());
+    EXPECT_EQ(3, num);
+}
+
 }
 }