Browse Source

Added some asiolink tests, fixed BoB tests

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac327@3125 e5f2f494-b856-4b98-b285-d166d9295462
Evan Hunt 14 years ago
parent
commit
4cf1bd8a34

+ 4 - 4
src/bin/bind10/tests/bind10_test.py

@@ -99,7 +99,7 @@ class TestBoB(unittest.TestCase):
         bob = BoB()
         bob = BoB()
         self.assertEqual(bob.verbose, False)
         self.assertEqual(bob.verbose, False)
         self.assertEqual(bob.msgq_socket_file, None)
         self.assertEqual(bob.msgq_socket_file, None)
-        self.assertEqual(bob.auth_port, 5300)
+        self.assertEqual(bob.dns_port, 5300)
         self.assertEqual(bob.cc_session, None)
         self.assertEqual(bob.cc_session, None)
         self.assertEqual(bob.address, None)
         self.assertEqual(bob.address, None)
         self.assertEqual(bob.processes, {})
         self.assertEqual(bob.processes, {})
@@ -115,11 +115,11 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.dead_processes, {})
         self.assertEqual(bob.dead_processes, {})
         self.assertEqual(bob.runnable, False)
         self.assertEqual(bob.runnable, False)
 
 
-    def test_init_alternate_auth_port(self):
+    def test_init_alternate_dns_port(self):
         bob = BoB(None, 9999)
         bob = BoB(None, 9999)
         self.assertEqual(bob.verbose, False)
         self.assertEqual(bob.verbose, False)
         self.assertEqual(bob.msgq_socket_file, None)
         self.assertEqual(bob.msgq_socket_file, None)
-        self.assertEqual(bob.auth_port, 9999)
+        self.assertEqual(bob.dns_port, 9999)
         self.assertEqual(bob.cc_session, None)
         self.assertEqual(bob.cc_session, None)
         self.assertEqual(bob.address, None)
         self.assertEqual(bob.address, None)
         self.assertEqual(bob.processes, {})
         self.assertEqual(bob.processes, {})
@@ -129,7 +129,7 @@ class TestBoB(unittest.TestCase):
     def test_init_alternate_address(self):
     def test_init_alternate_address(self):
         bob = BoB(None, 5300, '127.127.127.127')
         bob = BoB(None, 5300, '127.127.127.127')
         self.assertEqual(bob.verbose, False)
         self.assertEqual(bob.verbose, False)
-        self.assertEqual(bob.auth_port, 5300)
+        self.assertEqual(bob.dns_port, 5300)
         self.assertEqual(bob.msgq_socket_file, None)
         self.assertEqual(bob.msgq_socket_file, None)
         self.assertEqual(bob.cc_session, None)
         self.assertEqual(bob.cc_session, None)
         self.assertEqual(bob.address.addr, socket.inet_aton('127.127.127.127'))
         self.assertEqual(bob.address.addr, socket.inet_aton('127.127.127.127'))

+ 4 - 7
src/bin/recurse/recursor.cc

@@ -81,8 +81,7 @@ public:
         }
         }
     }
     }
 
 
-    void processNormalQuery(const IOMessage& io_message,
-                            const Question& question, MessagePtr message,
+    void processNormalQuery(const Question& question, MessagePtr message,
                             OutputBufferPtr buffer,
                             OutputBufferPtr buffer,
                             DNSServer* server);
                             DNSServer* server);
     ModuleCCSession* config_session_;
     ModuleCCSession* config_session_;
@@ -406,8 +405,7 @@ Recursor::processMessage(const IOMessage& io_message, MessagePtr message,
             // The RecursiveQuery object will post the "resume" event to the
             // The RecursiveQuery object will post the "resume" event to the
             // DNSServer when an answer arrives, so we don't have to do it now.
             // DNSServer when an answer arrives, so we don't have to do it now.
             sendAnswer = false;
             sendAnswer = false;
-            impl_->processNormalQuery(io_message, *question, message,
-                                      buffer, server);
+            impl_->processNormalQuery(*question, message, buffer, server);
         }
         }
     }
     }
 
 
@@ -417,8 +415,7 @@ Recursor::processMessage(const IOMessage& io_message, MessagePtr message,
 }
 }
 
 
 void
 void
-RecursorImpl::processNormalQuery(const IOMessage& io_message,
-                                 const Question& question, MessagePtr message,
+RecursorImpl::processNormalQuery(const Question& question, MessagePtr message,
                                  OutputBufferPtr buffer, DNSServer* server)
                                  OutputBufferPtr buffer, DNSServer* server)
 {
 {
     const bool dnssec_ok = message->isDNSSECSupported();
     const bool dnssec_ok = message->isDNSSECSupported();
@@ -428,7 +425,7 @@ RecursorImpl::processNormalQuery(const IOMessage& io_message,
     message->setRcode(Rcode::NOERROR());
     message->setRcode(Rcode::NOERROR());
     message->setDNSSECSupported(dnssec_ok);
     message->setDNSSECSupported(dnssec_ok);
     message->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
     message->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
-    rec_query_->sendQuery(io_message, question, buffer, server);
+    rec_query_->sendQuery(question, buffer, server);
 }
 }
 
 
 ConstElementPtr
 ConstElementPtr

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

@@ -93,8 +93,9 @@ IOMessage::IOMessage(const void* data, const size_t data_size,
     remote_endpoint_(remote_endpoint)
     remote_endpoint_(remote_endpoint)
 {}
 {}
 
 
-RecursiveQuery::RecursiveQuery(IOService& io_service, const char& forward) :
-    io_service_(io_service)
+RecursiveQuery::RecursiveQuery(IOService& io_service, const char& forward,
+                               uint16_t port) :
+    io_service_(io_service), port_(port)
 {
 {
     error_code err;
     error_code err;
     ns_addr_ = ip::address::from_string(&forward, err);
     ns_addr_ = ip::address::from_string(&forward, err);
@@ -105,8 +106,7 @@ RecursiveQuery::RecursiveQuery(IOService& io_service, const char& forward) :
 }
 }
 
 
 void
 void
-RecursiveQuery::sendQuery(const IOMessage& io_message,
-                          const Question& question, OutputBufferPtr buffer,
+RecursiveQuery::sendQuery(const Question& question, OutputBufferPtr buffer,
                           DNSServer* server)
                           DNSServer* server)
 {
 {
 
 
@@ -115,7 +115,7 @@ RecursiveQuery::sendQuery(const IOMessage& io_message,
     // UDP and then fall back to TCP on failure, but for the moment
     // UDP and then fall back to TCP on failure, but for the moment
     // we're only going to handle UDP.
     // we're only going to handle UDP.
     asio::io_service& io = io_service_.get_io_service();
     asio::io_service& io = io_service_.get_io_service();
-    UDPQuery q(io, io_message, question, ns_addr_, buffer, server);
+    UDPQuery q(io, question, ns_addr_, port_, buffer, server);
     io.post(q);
     io.post(q);
 }
 }
 
 
@@ -233,6 +233,11 @@ IOService::run() {
 }
 }
 
 
 void
 void
+IOService::run_one() {
+    impl_->io_service_.run_one();
+}
+
+void
 IOService::stop() {
 IOService::stop() {
     impl_->io_service_.stop();
     impl_->io_service_.stop();
 }
 }

+ 11 - 4
src/lib/asiolink/asiolink.h

@@ -446,6 +446,13 @@ public:
     /// the \c stop() method is called via some handler.
     /// the \c stop() method is called via some handler.
     void run();
     void run();
 
 
+    /// \brief Run the underlying event loop for a single event.
+    ///
+    /// This method return control to the caller as soon as the
+    /// first handler has completed.  (If no handlers are ready when
+    /// it is run, it will block until one is.)
+    void run_one();
+
     /// \brief Stop the underlying event loop.
     /// \brief Stop the underlying event loop.
     ///
     ///
     /// This will return the control to the caller of the \c run() method.
     /// This will return the control to the caller of the \c run() method.
@@ -727,12 +734,12 @@ public:
     /// This is currently the only way to construct \c RecursiveQuery
     /// This is currently the only way to construct \c RecursiveQuery
     /// object.  The address of the forward nameserver is specified,
     /// object.  The address of the forward nameserver is specified,
     /// and all upstream queries will be sent to that one address.
     /// and all upstream queries will be sent to that one address.
-    RecursiveQuery(IOService& io_service, const char& forward);
+    RecursiveQuery(IOService& io_service, const char& forward,
+                   uint16_t port = 53);
     //@}
     //@}
 
 
     /// \brief Initiates an upstream query in the \c RecursiveQuery object.
     /// \brief Initiates an upstream query in the \c RecursiveQuery object.
     ///
     ///
-    /// \param io_message The message from the original client
     /// \param question The question being answered <qname/qclass/qtype>
     /// \param question The question being answered <qname/qclass/qtype>
     /// \param buffer An output buffer into which the response can be copied
     /// \param buffer An output buffer into which the response can be copied
     /// \param server A pointer to the \c DNSServer object handling the client
     /// \param server A pointer to the \c DNSServer object handling the client
@@ -741,13 +748,13 @@ public:
     /// the upstream name server.  When a reply arrives, 'server'
     /// the upstream name server.  When a reply arrives, 'server'
     /// is placed on the ASIO service queue via io_service::post(), so
     /// is placed on the ASIO service queue via io_service::post(), so
     /// that the original \c DNSServer objct can resume processing.
     /// that the original \c DNSServer objct can resume processing.
-    void sendQuery(const IOMessage& io_message,
-                   const isc::dns::Question& question,
+    void sendQuery(const isc::dns::Question& question,
                    isc::dns::OutputBufferPtr buffer,
                    isc::dns::OutputBufferPtr buffer,
                    DNSServer* server);
                    DNSServer* server);
 private:
 private:
     IOService& io_service_;
     IOService& io_service_;
     asio::ip::address ns_addr_;
     asio::ip::address ns_addr_;
+    uint16_t port_;
 };
 };
 
 
 }      // asiolink
 }      // asiolink

+ 1 - 1
src/lib/asiolink/internal/udpdns.h

@@ -166,9 +166,9 @@ private:
 class UDPQuery : public coroutine {
 class UDPQuery : public coroutine {
 public:
 public:
     explicit UDPQuery(asio::io_service& io_service,
     explicit UDPQuery(asio::io_service& io_service,
-                      const IOMessage& io_message,
                       const isc::dns::Question& q,
                       const isc::dns::Question& q,
                       const asio::ip::address& addr,
                       const asio::ip::address& addr,
+                      uint16_t port,
                       isc::dns::OutputBufferPtr buffer,
                       isc::dns::OutputBufferPtr buffer,
                       DNSServer* server);
                       DNSServer* server);
     void operator()(asio::error_code ec = asio::error_code(),
     void operator()(asio::error_code ec = asio::error_code(),

+ 140 - 21
src/lib/asiolink/tests/asio_link_unittest.cc

@@ -17,12 +17,19 @@
 
 
 #include <config.h>
 #include <config.h>
 
 
+#include <string.h>
+
+#include <boost/lexical_cast.hpp>
+
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 
 
 #include <dns/tests/unittest_util.h>
 #include <dns/tests/unittest_util.h>
 
 
+#include <dns/buffer.h>
+#include <dns/message.h>
+
 #include <asiolink/asiolink.h>
 #include <asiolink/asiolink.h>
 #include <asiolink/internal/tcpdns.h>
 #include <asiolink/internal/tcpdns.h>
 #include <asiolink/internal/udpdns.h>
 #include <asiolink/internal/udpdns.h>
@@ -30,9 +37,11 @@
 using isc::UnitTestUtil;
 using isc::UnitTestUtil;
 using namespace std;
 using namespace std;
 using namespace asiolink;
 using namespace asiolink;
+using namespace isc::dns;
 
 
 namespace {
 namespace {
-const char* const TEST_PORT = "53535";
+const char* const TEST_SERVER_PORT = "53535";
+const char* const TEST_CLIENT_PORT = "53535";
 const char* const TEST_IPV6_ADDR = "::1";
 const char* const TEST_IPV6_ADDR = "::1";
 const char* const TEST_IPV4_ADDR = "127.0.0.1";
 const char* const TEST_IPV4_ADDR = "127.0.0.1";
 // This data is intended to be valid as a DNS/TCP-like message: the first
 // This data is intended to be valid as a DNS/TCP-like message: the first
@@ -127,52 +136,54 @@ TEST(IOServiceTest, badPort) {
 }
 }
 
 
 TEST(IOServiceTest, badAddress) {
 TEST(IOServiceTest, badAddress) {
-    EXPECT_THROW(IOService(*TEST_PORT, *"192.0.2.1.1", NULL, NULL, NULL), IOError);
-    EXPECT_THROW(IOService(*TEST_PORT, *"2001:db8:::1", NULL, NULL, NULL), IOError);
-    EXPECT_THROW(IOService(*TEST_PORT, *"localhost", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *"192.0.2.1.1", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *"2001:db8:::1", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *"localhost", NULL, NULL, NULL), IOError);
 }
 }
 
 
 TEST(IOServiceTest, unavailableAddress) {
 TEST(IOServiceTest, unavailableAddress) {
     // These addresses should generally be unavailable as a valid local
     // These addresses should generally be unavailable as a valid local
     // address, although there's no guarantee in theory.
     // address, although there's no guarantee in theory.
-    EXPECT_THROW(IOService(*TEST_PORT, *"255.255.0.0", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *"255.255.0.0", NULL, NULL, NULL), IOError);
 
 
     // Some OSes would simply reject binding attempt for an AF_INET6 socket
     // Some OSes would simply reject binding attempt for an AF_INET6 socket
     // to an IPv4-mapped IPv6 address.  Even if those that allow it, since
     // to an IPv4-mapped IPv6 address.  Even if those that allow it, since
     // the corresponding IPv4 address is the same as the one used in the
     // the corresponding IPv4 address is the same as the one used in the
     // AF_INET socket case above, it should at least show the same result
     // AF_INET socket case above, it should at least show the same result
     // as the previous one.
     // as the previous one.
-    EXPECT_THROW(IOService(*TEST_PORT, *"::ffff:255.255.0.0", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *"::ffff:255.255.0.0", NULL, NULL, NULL), IOError);
 }
 }
 
 
 TEST(IOServiceTest, duplicateBind) {
 TEST(IOServiceTest, duplicateBind) {
     // In each sub test case, second attempt should fail due to duplicate bind
     // In each sub test case, second attempt should fail due to duplicate bind
 
 
     // IPv6, "any" address
     // IPv6, "any" address
-    IOService* io_service = new IOService(*TEST_PORT, false, true, NULL, NULL, NULL);
-    EXPECT_THROW(IOService(*TEST_PORT, false, true, NULL, NULL, NULL), IOError);
+    IOService* io_service = new IOService(*TEST_SERVER_PORT, false, true, NULL, NULL, NULL);
+    EXPECT_THROW(IOService(*TEST_SERVER_PORT, false, true, NULL, NULL, NULL), IOError);
     delete io_service;
     delete io_service;
 
 
     // IPv6, specific address
     // IPv6, specific address
-    io_service = new IOService(*TEST_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL);
-    EXPECT_THROW(IOService(*TEST_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL), IOError);
+    io_service = new IOService(*TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL);
+    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL), IOError);
     delete io_service;
     delete io_service;
 
 
     // IPv4, "any" address
     // IPv4, "any" address
-    io_service = new IOService(*TEST_PORT, true, false, NULL, NULL, NULL);
-    EXPECT_THROW(IOService(*TEST_PORT, true, false, NULL, NULL, NULL), IOError);
+    io_service = new IOService(*TEST_SERVER_PORT, true, false, NULL, NULL, NULL);
+    EXPECT_THROW(IOService(*TEST_SERVER_PORT, true, false, NULL, NULL, NULL), IOError);
     delete io_service;
     delete io_service;
 
 
     // IPv4, specific address
     // IPv4, specific address
-    io_service = new IOService(*TEST_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL);
-    EXPECT_THROW(IOService(*TEST_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL), IOError);
+    io_service = new IOService(*TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL);
+    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL), IOError);
     delete io_service;
     delete io_service;
 }
 }
 
 
 struct addrinfo*
 struct addrinfo*
-resolveAddress(const int family, const int sock_type, const int protocol) {
+resolveAddress(const int family, const int sock_type, const int protocol,
+               const bool client) {
     const char* const addr = (family == AF_INET6) ?
     const char* const addr = (family == AF_INET6) ?
         TEST_IPV6_ADDR : TEST_IPV4_ADDR;
         TEST_IPV6_ADDR : TEST_IPV4_ADDR;
+    const char* const port = client ? TEST_CLIENT_PORT : TEST_SERVER_PORT;
 
 
     struct addrinfo hints;
     struct addrinfo hints;
     memset(&hints, 0, sizeof(hints));
     memset(&hints, 0, sizeof(hints));
@@ -181,7 +192,7 @@ resolveAddress(const int family, const int sock_type, const int protocol) {
     hints.ai_protocol = protocol;
     hints.ai_protocol = protocol;
 
 
     struct addrinfo* res;
     struct addrinfo* res;
-    const int error = getaddrinfo(addr, TEST_PORT, &hints, &res);
+    const int error = getaddrinfo(addr, port, &hints, &res);
     if (error != 0) {
     if (error != 0) {
         isc_throw(IOError, "getaddrinfo failed: " << gai_strerror(error));
         isc_throw(IOError, "getaddrinfo failed: " << gai_strerror(error));
     }
     }
@@ -219,7 +230,7 @@ protected:
         }
         }
     }
     }
     void sendUDP(const int family) {
     void sendUDP(const int family) {
-        res_ = resolveAddress(family, SOCK_DGRAM, IPPROTO_UDP);
+        res_ = resolveAddress(family, SOCK_DGRAM, IPPROTO_UDP, false);
 
 
         sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
         sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
         if (sock_ < 0) {
         if (sock_ < 0) {
@@ -233,7 +244,7 @@ protected:
         io_service_->run();
         io_service_->run();
     }
     }
     void sendTCP(const int family) {
     void sendTCP(const int family) {
-        res_ = resolveAddress(family, SOCK_STREAM, IPPROTO_TCP);
+        res_ = resolveAddress(family, SOCK_STREAM, IPPROTO_TCP, false);
 
 
         sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
         sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
         if (sock_ < 0) {
         if (sock_ < 0) {
@@ -244,21 +255,51 @@ protected:
         }
         }
         const int cc = send(sock_, test_data, sizeof(test_data), 0);
         const int cc = send(sock_, test_data, sizeof(test_data), 0);
         if (cc != sizeof(test_data)) {
         if (cc != sizeof(test_data)) {
-            isc_throw(IOError, "unexpected sendto result: " << cc);
+            isc_throw(IOError, "unexpected send result: " << cc);
         }
         }
         io_service_->run();
         io_service_->run();
     }
     }
+    void recvUDP(const int family, void* buffer, size_t size) {
+        res_ = resolveAddress(family, SOCK_DGRAM, IPPROTO_UDP, true);
+
+        sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
+        if (sock_ < 0) {
+            isc_throw(IOError, "failed to open test socket");
+        }
+
+        if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
+            isc_throw(IOError, "bind failed: " << gai_strerror(errno));
+        }
+
+        // The IO service queue should have a RecursiveQuery object scheduled
+        // to run at this point.  This call will cause it to begin an
+        // async send, then return.
+        io_service_->run_one();
+
+        // ... and this completes the send().
+        io_service_->run_one();
+
+        // Now we attempt to recv() whatever was sent
+        struct sockaddr addr;
+        socklen_t addrlen;
+        fcntl(sock_, F_SETFD, O_NONBLOCK);
+        const int cc = recvfrom(sock_, buffer, size, MSG_DONTWAIT,
+                                &addr, &addrlen);
+        if (cc < 0) {
+            isc_throw(IOError, "recvfrom failed");
+        }
+    }
     void setIOService(const char& address) {
     void setIOService(const char& address) {
         delete io_service_;
         delete io_service_;
         io_service_ = NULL;
         io_service_ = NULL;
         callback_ = new ASIOCallBack(this);
         callback_ = new ASIOCallBack(this);
-        io_service_ = new IOService(*TEST_PORT, address, callback_, NULL, NULL);
+        io_service_ = new IOService(*TEST_SERVER_PORT, address, callback_, NULL, NULL);
     }
     }
     void setIOService(const bool use_ipv4, const bool use_ipv6) {
     void setIOService(const bool use_ipv4, const bool use_ipv6) {
         delete io_service_;
         delete io_service_;
         io_service_ = NULL;
         io_service_ = NULL;
         callback_ = new ASIOCallBack(this);
         callback_ = new ASIOCallBack(this);
-        io_service_ = new IOService(*TEST_PORT, use_ipv4, use_ipv6, callback_,
+        io_service_ = new IOService(*TEST_SERVER_PORT, use_ipv4, use_ipv6, callback_,
                                     NULL, NULL);
                                     NULL, NULL);
     }
     }
     void doTest(const int family, const int protocol) {
     void doTest(const int family, const int protocol) {
@@ -285,6 +326,51 @@ protected:
                             callback_data_.size(),
                             callback_data_.size(),
                             expected_data, expected_datasize);
                             expected_data, expected_datasize);
     }
     }
+
+protected:
+    class MockServer : public DNSServer {
+    public:
+        explicit MockServer(asio::io_service& io_service,
+                            const asio::ip::address& addr, const uint16_t port,
+                            SimpleCallback* checkin = NULL,
+                            DNSLookup* lookup = NULL,
+                            DNSAnswer* answer = NULL) :
+            io_(io_service),
+            checkin_(checkin), lookup_(lookup), answer_(answer)
+        {
+        // HERE set up address
+        }
+
+        void operator()(asio::error_code ec = asio::error_code(),
+                        size_t length = 0)
+        {
+            // Do some stuff
+        }
+
+        void resume(const bool done) {
+            done_ = done;
+            io_.post(*this);
+        }
+
+        DNSServer* clone() {
+            MockServer* s = new MockServer(*this);
+            return (s);
+        }
+
+        inline void asyncLookup() {
+            // (*lookup_)(*io_message_, message_, respbuf_, this);
+        }
+
+    private:
+        asio::io_service& io_;
+        bool done_;
+
+        // Callback functions provided by the caller
+        const SimpleCallback* checkin_;
+        const DNSLookup* lookup_;
+        const DNSAnswer* answer_;
+    };
+
 private:
 private:
     class ASIOCallBack : public SimpleCallback {
     class ASIOCallBack : public SimpleCallback {
     public:
     public:
@@ -388,4 +474,37 @@ TEST_F(ASIOLinkTest, v4TCPOnly) {
     EXPECT_THROW(sendTCP(AF_INET6), IOError);
     EXPECT_THROW(sendTCP(AF_INET6), IOError);
 }
 }
 
 
+TEST_F(ASIOLinkTest, recursiveSetupV4) {
+    setIOService(true, false);
+    uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
+    EXPECT_NO_THROW(RecursiveQuery(*io_service_, *TEST_IPV4_ADDR, port));
+}
+
+TEST_F(ASIOLinkTest, recursiveSetupV6) {
+    setIOService(false, true);
+    uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
+    EXPECT_NO_THROW(RecursiveQuery(*io_service_, *TEST_IPV6_ADDR, port));
+}
+
+// Test disabled because recvUDP() isn't working yet
+TEST_F(ASIOLinkTest, DISABLED_recursiveSend) {
+    setIOService(true, false);
+    asio::io_service& io = io_service_->get_io_service();
+
+    // Note: We use the test prot plus one to ensure we aren't binding
+    // to the same port as the actual server
+    uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
+    asio::ip::address addr = asio::ip::address::from_string(TEST_IPV4_ADDR);
+
+    MockServer server(io, addr, port, NULL, NULL, NULL);
+    RecursiveQuery rq(*io_service_, *TEST_IPV4_ADDR, port);
+
+    Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
+    OutputBufferPtr buffer(new OutputBuffer(0));
+    rq.sendQuery(q, buffer, &server);
+
+    char data[4096];
+    EXPECT_NO_THROW(recvUDP(AF_INET, data, sizeof(data)));
+}
+
 }
 }

+ 3 - 3
src/lib/asiolink/udpdns.cc

@@ -207,15 +207,15 @@ UDPServer::resume(const bool done) {
 /// The following functions implement the \c UDPQuery class.
 /// The following functions implement the \c UDPQuery class.
 ///
 ///
 /// The constructor
 /// The constructor
-UDPQuery::UDPQuery(io_service& io_service, const IOMessage& io_message,
-                   const Question& q, const ip::address& addr,
+UDPQuery::UDPQuery(io_service& io_service,
+                   const Question& q, const ip::address& addr, uint16_t port,
                    OutputBufferPtr buffer, DNSServer* server) :
                    OutputBufferPtr buffer, DNSServer* server) :
     question_(q), buffer_(buffer), server_(server->clone())
     question_(q), buffer_(buffer), server_(server->clone())
 {
 {
     udp proto = addr.is_v4() ? udp::v4() : udp::v6();
     udp proto = addr.is_v4() ? udp::v4() : udp::v6();
     socket_.reset(new udp::socket(io_service, proto));
     socket_.reset(new udp::socket(io_service, proto));
     msgbuf_.reset(new OutputBuffer(512));
     msgbuf_.reset(new OutputBuffer(512));
-    remote_ = udp::endpoint(addr, 53);
+    remote_ = udp::endpoint(addr, port);
 }
 }
 
 
 /// The function operator is implemented with the "stackless coroutine"
 /// The function operator is implemented with the "stackless coroutine"