Browse Source

Merge preparation, step 1

Doesn't compile yet. Only detected code-level conflicts resolved.

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/vorner-recursor-config@3423 e5f2f494-b856-4b98-b285-d166d9295462
Michal Vaner 14 years ago
parent
commit
d64bf0a863

+ 1 - 1
src/bin/auth/auth_srv.h

@@ -62,7 +62,7 @@ public:
     /// I/O service queue and return.  When the server resumes, it can
     /// send the reply.
     ///
-    /// \param io_message The I/O service queue
+    /// \param io_message The raw message received
     /// \param message Pointer to the \c Message object
     /// \param buffer Pointer to an \c OutputBuffer for the resposne
     /// \param server Pointer to the \c DNSServer

+ 12 - 11
src/bin/auth/main.cc

@@ -66,7 +66,7 @@ static const char* DNSPORT = "5300";
  * class itself? */
 static AuthSrv *auth_server;
 
-static IOService* io_service;
+static IOService io_service;
 
 ConstElementPtr
 my_config_handler(ConstElementPtr new_config) {
@@ -82,7 +82,7 @@ my_command_handler(const string& command, ConstElementPtr args) {
         /* let's add that message to our answer as well */
         answer = createAnswer(0, args);
     } else if (command == "shutdown") {
-        io_service->stop();
+        io_service.stop();
     }
     
     return (answer);
@@ -193,6 +193,7 @@ main(int argc, char* argv[]) {
         DNSLookup* lookup = auth_server->getDNSLookupProvider();
         DNSAnswer* answer = auth_server->getDNSAnswerProvider();
 
+        DNSService* dns_service;
         if (address != NULL) {
             // XXX: we can only specify at most one explicit address.
             // This also means the server cannot run in the dual address
@@ -200,16 +201,17 @@ main(int argc, char* argv[]) {
             // We don't bother to fix this problem, however.  The -a option
             // is a short term workaround until we support dynamic listening
             // port allocation.
-            io_service = new IOService(*port, *address,
-                                       checkin, lookup, answer);
+            dns_service = new DNSService(io_service,  *port, *address,
+                                         checkin, lookup, answer);
         } else {
-            io_service = new IOService(*port, use_ipv4, use_ipv6,
-                                       checkin, lookup, answer);
+            dns_service = new DNSService(io_service, *port, use_ipv4,
+                                         use_ipv6, checkin, lookup,
+                                         answer);
         }
-        auth_server->setIOService(*io_service);
+        auth_server->setIOService(io_service);
         cout << "[b10-auth] IOService created." << endl;
 
-        cc_session = new Session(io_service->get_io_service());
+        cc_session = new Session(io_service.get_io_service());
         cout << "[b10-auth] Configuration session channel created." << endl;
 
         config_session = new ModuleCCSession(specfile, *cc_session,
@@ -221,7 +223,7 @@ main(int argc, char* argv[]) {
             changeUser(uid);
         }
 
-        xfrin_session = new Session(io_service->get_io_service());
+        xfrin_session = new Session(io_service.get_io_service());
         cout << "[b10-auth] Xfrin session channel created." << endl;
         xfrin_session->establish(NULL);
         xfrin_session_established = true;
@@ -237,7 +239,7 @@ main(int argc, char* argv[]) {
         auth_server->updateConfig(ElementPtr());
 
         cout << "[b10-auth] Server started." << endl;
-        io_service->run();
+        io_service.run();
     } catch (const std::exception& ex) {
         cerr << "[b10-auth] Server failed: " << ex.what() << endl;
         ret = 1;
@@ -250,7 +252,6 @@ main(int argc, char* argv[]) {
     delete xfrin_session;
     delete config_session;
     delete cc_session;
-    delete io_service;
     delete auth_server;
 
     return (ret);

+ 7 - 7
src/bin/recurse/main.cc

@@ -62,7 +62,7 @@ static bool verbose_mode = false;
 // Default port current 5300 for testing purposes
 static const string PROGRAM = "Recurse";
 
-static IOService* io_service;
+IOService io_service;
 static Recursor *recursor;
 
 ConstElementPtr
@@ -79,7 +79,7 @@ my_command_handler(const string& command, ConstElementPtr args) {
         /* let's add that message to our answer as well */
         answer = createAnswer(0, args);
     } else if (command == "shutdown") {
-        io_service->stop();
+        io_service.stop();
     }
 
     return (answer);
@@ -139,11 +139,12 @@ main(int argc, char* argv[]) {
         DNSLookup* lookup = recursor->getDNSLookupProvider();
         DNSAnswer* answer = recursor->getDNSAnswerProvider();
 
-        io_service = new IOService(checkin, lookup, answer);
-        recursor->setIOService(*io_service);
+        DNSService dns_service(io_service, checkin, lookup, answer);
+
+        recursor->setDNSService(dns_service);
         cout << "[b10-recurse] IOService created." << endl;
 
-        cc_session = new Session(io_service->get_io_service());
+        cc_session = new Session(io_service.get_io_service());
         cout << "[b10-recurse] Configuration session channel created." << endl;
 
         config_session = new ModuleCCSession(specfile, *cc_session,
@@ -160,7 +161,7 @@ main(int argc, char* argv[]) {
         recursor->updateConfig(config_session->getFullConfig());
 
         cout << "[b10-recurse] Server started." << endl;
-        io_service->run();
+        io_service.run();
     } catch (const std::exception& ex) {
         cerr << "[b10-recurse] Server failed: " << ex.what() << endl;
         ret = 1;
@@ -168,7 +169,6 @@ main(int argc, char* argv[]) {
 
     delete config_session;
     delete cc_session;
-    delete io_service;
     delete recursor;
 
     return (ret);

+ 5 - 5
src/bin/recurse/recursor.cc

@@ -76,8 +76,8 @@ public:
         queryShutdown();
     }
 
-    void querySetup(IOService& ios) {
-        rec_query_ = new RecursiveQuery(ios, upstream_);
+    void querySetup(DNSService& dnss) {
+        rec_query_ = new RecursiveQuery(dnss, upstream_);
     }
 
     void queryShutdown() {
@@ -316,10 +316,10 @@ Recursor::~Recursor() {
 }
 
 void
-Recursor::setIOService(asiolink::IOService& ios) {
+Recursor::setDNSService(asiolink::DNSService& dnss) {
     impl_->queryShutdown();
-    impl_->querySetup(ios);
-    io_ = &ios;
+    impl_->querySetup(dnss);
+    dnss_ = &dnss;
 }
 
 void

+ 4 - 4
src/bin/recurse/recursor.h

@@ -51,7 +51,7 @@ public:
     /// I/O service queue and return.  When the server resumes, it can
     /// send the reply.
     ///
-    /// \param io_message The I/O service queue
+    /// \param io_message The raw message received
     /// \param message Pointer to the \c Message object
     /// \param buffer Pointer to an \c OutputBuffer for the resposne
     /// \param server Pointer to the \c DNSServer
@@ -76,10 +76,10 @@ public:
     isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
 
     /// \brief Assign an ASIO IO Service queue to this Recursor object
-    void setIOService(asiolink::IOService& ios);
+    void setDNSService(asiolink::DNSService& dnss);
 
     /// \brief Return this object's ASIO IO Service queue
-    asiolink::IOService& getIOService() const { return (*io_); }
+    asiolink::DNSService& getDNSService() const { return (*dnss_); }
 
     /// \brief Return pointer to the DNS Lookup callback function
     asiolink::DNSLookup* getDNSLookupProvider() { return (dns_lookup_); }
@@ -120,7 +120,7 @@ public:
 
 private:
     RecursorImpl* impl_;
-    asiolink::IOService* io_;
+    asiolink::DNSService* dnss_;
     asiolink::SimpleCallback* checkin_;
     asiolink::DNSLookup* dns_lookup_;
     asiolink::DNSAnswer* dns_answer_;

+ 1 - 13
src/bin/recurse/tests/Makefile.am

@@ -35,24 +35,12 @@ endif
 
 noinst_PROGRAMS = $(TESTS)
 
-EXTRA_DIST =  testdata/badExampleQuery_fromWire
-EXTRA_DIST += testdata/badExampleQuery_fromWire.spec
-EXTRA_DIST += testdata/example.com
-EXTRA_DIST += testdata/examplequery_fromWire
-EXTRA_DIST += testdata/examplequery_fromWire.spec
-EXTRA_DIST += testdata/example.sqlite3
-EXTRA_DIST += testdata/iqueryresponse_fromWire
-EXTRA_DIST += testdata/iqueryresponse_fromWire.spec
+EXTRA_DIST = testdata/iqueryresponse_fromWire
 EXTRA_DIST += testdata/multiquestion_fromWire
-EXTRA_DIST += testdata/multiquestion_fromWire.spec
 EXTRA_DIST += testdata/queryBadEDNS_fromWire
-EXTRA_DIST += testdata/queryBadEDNS_fromWire.spec
 EXTRA_DIST += testdata/shortanswer_fromWire
-EXTRA_DIST += testdata/shortanswer_fromWire.spec
 EXTRA_DIST += testdata/shortmessage_fromWire
 EXTRA_DIST += testdata/shortquestion_fromWire
 EXTRA_DIST += testdata/shortresponse_fromWire
 EXTRA_DIST += testdata/simplequery_fromWire
-EXTRA_DIST += testdata/simplequery_fromWire.spec
 EXTRA_DIST += testdata/simpleresponse_fromWire
-EXTRA_DIST += testdata/simpleresponse_fromWire.spec

+ 9 - 10
src/bin/recurse/tests/recursor_unittest.cc

@@ -63,15 +63,15 @@ private:
 
 class RecursorTest : public ::testing::Test {
 protected:
-    RecursorTest() : ios(*TEST_PORT, true, false, NULL, NULL, NULL),
-                    request_message(Message::RENDER),
-                    parse_message(new Message(Message::PARSE)),
-                    default_qid(0x1035), opcode(Opcode(Opcode::QUERY())),
-                    qname("www.example.com"),
-                    qclass(RRClass::IN()), qtype(RRType::A()),
-                    io_message(NULL), endpoint(NULL), request_obuffer(0),
-                    request_renderer(request_obuffer),
-                    response_obuffer(new OutputBuffer(0))
+    RecursorTest() : server(*DEFAULT_REMOTE_ADDRESS),
+                     request_message(Message::RENDER),
+                     parse_message(new Message(Message::PARSE)),
+                     default_qid(0x1035), opcode(Opcode(Opcode::QUERY())),
+                     qname("www.example.com"),
+                     qclass(RRClass::IN()), qtype(RRType::A()),
+                     io_message(NULL), endpoint(NULL), request_obuffer(0),
+                     request_renderer(request_obuffer),
+                     response_obuffer(new OutputBuffer(0))
     {
         vector<pair<string, uint16_t> > upstream;
         upstream.push_back(pair<string, uint16_t>(DEFAULT_REMOTE_ADDRESS, 53));
@@ -83,7 +83,6 @@ protected:
     }
     MockSession notify_session;
     MockServer dnsserv;
-    IOService ios;
     Recursor server;
     Message request_message;
     MessagePtr parse_message;

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

@@ -12,11 +12,12 @@ CLEANFILES = *.gcno *.gcda
 # which would make the build fail with -Werror (our default setting).
 lib_LTLIBRARIES = libasiolink.la
 libasiolink_la_SOURCES = asiolink.cc asiolink.h
-libasiolink_la_SOURCES += iosocket.h
+libasiolink_la_SOURCES += iosocket.h iomessage.h
 libasiolink_la_SOURCES += ioaddress.cc ioaddress.h
 libasiolink_la_SOURCES += ioendpoint.cc ioendpoint.h
 libasiolink_la_SOURCES += udpdns.cc internal/udpdns.h
 libasiolink_la_SOURCES += tcpdns.cc internal/tcpdns.h
+libasiolink_la_SOURCES += internal/coroutine.h
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # B10_CXXFLAGS)
 libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS)

+ 105 - 30
src/lib/asiolink/asiolink.cc

@@ -46,15 +46,84 @@ using namespace isc::dns;
 namespace asiolink {
 
 class IOServiceImpl {
+private:
+    IOServiceImpl(const IOService& source);
+    IOServiceImpl& operator=(const IOService& source);
 public:
-    IOServiceImpl(const char& port,
+    /// \brief The constructor
+    IOServiceImpl() : io_service_() {};
+    /// \brief The destructor.
+    ~IOServiceImpl() {};
+    //@}
+
+    /// \brief Start the underlying event loop.
+    ///
+    /// This method does not return control to the caller until
+    /// the \c stop() method is called via some handler.
+    void run() { io_service_.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() { io_service_.run_one();} ;
+
+    /// \brief Stop the underlying event loop.
+    ///
+    /// This will return the control to the caller of the \c run() method.
+    void stop() { io_service_.stop();} ;
+
+    /// \brief Return the native \c io_service object used in this wrapper.
+    ///
+    /// This is a short term work around to support other BIND 10 modules
+    /// that share the same \c io_service with the authoritative server.
+    /// It will eventually be removed once the wrapper interface is
+    /// generalized.
+    asio::io_service& get_io_service() { return io_service_; };
+private:
+    asio::io_service io_service_;
+};
+
+IOService::IOService() {
+    io_impl_ = new IOServiceImpl();
+}
+
+IOService::~IOService() {
+    delete io_impl_;
+}
+
+void
+IOService::run() {
+    io_impl_->run();
+}
+
+void
+IOService::run_one() {
+    io_impl_->run_one();
+}
+
+void
+IOService::stop() {
+    io_impl_->stop();
+}
+
+asio::io_service&
+IOService::get_io_service() {
+    return (io_impl_->get_io_service());
+}
+
+class DNSServiceImpl {
+public:
+    DNSServiceImpl(IOService& io_service, const char& port,
                   const ip::address* v4addr, const ip::address* v6addr,
                   SimpleCallback* checkin, DNSLookup* lookup,
                   DNSAnswer* answer);
-    asio::io_service io_service_;
+    //asio::io_service io_service_;
     // So it does not run out of work when there are no listening sockets
     asio::io_service::work work_;
 
+    void stop();
     typedef boost::shared_ptr<UDPServer> UDPServerPtr;
     typedef boost::shared_ptr<TCPServer> TCPServerPtr;
     typedef boost::shared_ptr<DNSServer> DNSServerPtr;
@@ -103,12 +172,14 @@ public:
     }
 };
 
-IOServiceImpl::IOServiceImpl(const char& port,
-                             const ip::address* const v4addr,
-                             const ip::address* const v6addr,
-                             SimpleCallback* checkin,
-                             DNSLookup* lookup,
-                             DNSAnswer* answer) :
+DNSServiceImpl::DNSServiceImpl(IOService& io_service_,
+                               const char& port,
+                               const ip::address* const v4addr,
+                               const ip::address* const v6addr,
+                               SimpleCallback* checkin,
+                               DNSLookup* lookup,
+                               DNSAnswer* answer) :
+    // TODO MERGE move work to IOService
     work_(io_service_),
     checkin_(checkin),
     lookup_(lookup),
@@ -123,36 +194,40 @@ IOServiceImpl::IOServiceImpl(const char& port,
     }
 }
 
-IOService::IOService(const char& port, const char& address,
-                     SimpleCallback* checkin,
-                     DNSLookup* lookup,
-                     DNSAnswer* answer) :
-    impl_(new IOServiceImpl(port, NULL, NULL, checkin, lookup, answer))
+DNSService::DNSService(IOService& io_service,
+                       const char& port, const char& address,
+                       SimpleCallback* checkin,
+                       DNSLookup* lookup,
+                       DNSAnswer* answer) :
+    impl_(new IOServiceImpl(io_service, port, NULL, NULL, checkin, lookup,
+        answer)), io_service_(io_service)
 {
     addServer(port, &address);
 }
 
-IOService::IOService(const char& port,
-                     const bool use_ipv4, const bool use_ipv6,
-                     SimpleCallback* checkin,
-                     DNSLookup* lookup,
-                     DNSAnswer* answer) :
-    impl_(NULL)
+DNSService::DNSService(IOService& io_service,
+                       const char& port,
+                       const bool use_ipv4, const bool use_ipv6,
+                       SimpleCallback* checkin,
+                       DNSLookup* lookup,
+                       DNSAnswer* answer) :
+    impl_(NULL), io_service_(io_service)
 {
     const ip::address v4addr_any = ip::address(ip::address_v4::any());
     const ip::address* const v4addrp = use_ipv4 ? &v4addr_any : NULL; 
     const ip::address v6addr_any = ip::address(ip::address_v6::any());
     const ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
-    impl_ = new IOServiceImpl(port, v4addrp, v6addrp, checkin, lookup, answer);
+    impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
 }
 
-IOService::IOService(SimpleCallback* checkin, DNSLookup* lookup,
-    DNSAnswer *answer) :
-    impl_(new IOServiceImpl(*"", NULL, NULL, checkin, lookup, answer))
+DNSService::DNSService(IOService& io_service, SimpleCallback* checkin,
+    DNSLookup* lookup, DNSAnswer *answer) :
+    impl_(new IOServiceImpl(io_service, *"0", NULL, NULL, checkin, lookup,
+        answer))
 {
 }
 
-IOService::~IOService() {
+DNSService::~DNSService() {
     delete impl_;
 }
 
@@ -172,17 +247,17 @@ convertAddr(const string& address) {
 }
 
 void
-IOService::addServer(const char& port, const string& address) {
+DNSService::addServer(const char& port, const string& address) {
     impl_->addServer(port, convertAddr(address));
 }
 
 void
-IOService::addServer(uint16_t port, const string &address) {
+DNSService::addServer(uint16_t port, const string &address) {
     impl_->addServer(port, convertAddr(address));
 }
 
 void
-IOService::clearServers() {
+DNSService::clearServers() {
     // FIXME: This does not work, it does not close the socket.
     // How is it done?
     impl_->servers_.clear();
@@ -208,9 +283,9 @@ IOService::get_io_service() {
     return (impl_->io_service_);
 }
 
-RecursiveQuery::RecursiveQuery(IOService& io_service,
+RecursiveQuery::RecursiveQuery(DNSService& dns_service,
         const std::vector<std::pair<std::string, uint16_t> >& upstream) :
-    io_service_(io_service), upstream_(upstream)
+    dns_service_(dns_service), upstream_(upstream)
 {}
 
 void
@@ -222,7 +297,7 @@ RecursiveQuery::sendQuery(const Question& question, OutputBufferPtr buffer,
     // 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 = io_service_.get_io_service();
+    asio::io_service& io = dns_service_.get_io_service();
     // TODO: Better way to choose the server
     int serverIndex(random() % upstream_.size());
     UDPQuery q(io, question, upstream_[serverIndex].first,

+ 99 - 30
src/lib/asiolink/asiolink.h

@@ -38,6 +38,7 @@
 #include <asiolink/ioendpoint.h>
 #include <asiolink/iomessage.h>
 #include <asiolink/iosocket.h>
+//#include <asio/io_service.hpp>
 
 namespace asio {
 // forward declaration for IOService::get_io_service() below
@@ -95,6 +96,7 @@ class io_service;
 /// http://think-async.com/Asio/asio-1.3.1/doc/asio/reference/asio_handler_allocate.html
 
 namespace asiolink {
+struct DNSServiceImpl;
 struct IOServiceImpl;
 
 /// \brief An exception that is thrown if an error occurs within the IO
@@ -114,18 +116,10 @@ class DNSAnswer;
 /// \brief The \c IOService class is a wrapper for the ASIO \c io_service
 /// class.
 ///
-/// Currently, the interface of this class is very specific to the
-/// authoritative/recursive DNS server implementationss in b10-auth
-/// and b10-recurse; this is reflected in the constructor signatures.
-/// Ultimately the plan is to generalize it so that other BIND 10
-/// modules can use this interface, too.
 class IOService {
     ///
     /// \name Constructors and Destructor
     ///
-    /// These are currently very specific to the authoritative server
-    /// implementation.
-    ///
     /// Note: The copy constructor and the assignment operator are
     /// intentionally defined as private, making this class non-copyable.
     //@{
@@ -133,22 +127,8 @@ private:
     IOService(const IOService& source);
     IOService& operator=(const IOService& source);
 public:
-    /// \brief The constructor with a specific IP address and port on which
-    /// the services listen on.
-    IOService(const char& port, const char& address,
-              SimpleCallback* checkin,
-              DNSLookup* lookup,
-              DNSAnswer* answer);
-    /// \brief The constructor with a specific port on which the services
-    /// listen on.
-    ///
-    /// It effectively listens on "any" IPv4 and/or IPv6 addresses.
-    /// IPv4/IPv6 services will be available if and only if \c use_ipv4
-    /// or \c use_ipv6 is \c true, respectively.
-    IOService(const char& port, const bool use_ipv4, const bool use_ipv6,
-              SimpleCallback* checkin,
-              DNSLookup* lookup,
-              DNSAnswer* answer);
+    /// \brief The constructor
+    IOService();
     /// \brief The constructor without any servers.
     ///
     /// Use addServer() to add some servers.
@@ -188,8 +168,71 @@ public:
     /// It will eventually be removed once the wrapper interface is
     /// generalized.
     asio::io_service& get_io_service();
+
 private:
-    IOServiceImpl* impl_;
+    IOServiceImpl* io_impl_;
+};
+
+///
+/// DNSService is the service that handles DNS queries and answers with
+/// a given IOService.
+/// 
+class DNSService {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are
+    /// intentionally defined as private, making this class non-copyable.
+    //@{
+private:
+    DNSService(const DNSService& source);
+    DNSService& operator=(const DNSService& source);
+
+public:
+    /// \brief The constructor with a specific IP address and port on which
+    /// the services listen on.
+    ///
+    /// \param io_service The IOService to work with
+    /// \param port the port to listen on
+    /// \param address the IP address to listen on
+    /// \param checkin Provider for cc-channel events (see \c SimpleCallback)
+    /// \param lookup The lookup provider (see \c DNSLookup)
+    /// \param answer The answer provider (see \c DNSAnswer)
+    DNSService(IOService& io_service, const char& port,
+               const char& address, SimpleCallback* checkin,
+               DNSLookup* lookup, DNSAnswer* answer);
+    /// \brief The constructor with a specific port on which the services
+    /// listen on.
+    ///
+    /// It effectively listens on "any" IPv4 and/or IPv6 addresses.
+    /// IPv4/IPv6 services will be available if and only if \c use_ipv4
+    /// or \c use_ipv6 is \c true, respectively.
+    ///
+    /// \param io_service The IOService to work with
+    /// \param port the port to listen on
+    /// \param ipv4 If true, listen on ipv4 'any'
+    /// \param ipv6 If true, listen on ipv6 'any'
+    /// \param checkin Provider for cc-channel events (see \c SimpleCallback)
+    /// \param lookup The lookup provider (see \c DNSLookup)
+    /// \param answer The answer provider (see \c DNSAnswer)
+    DNSService(IOService& io_service, const char& port,
+               const bool use_ipv4, const bool use_ipv6,
+               SimpleCallback* checkin, DNSLookup* lookup,
+               DNSAnswer* answer);
+    /// \brief The destructor.
+    ~DNSService();
+    //@}
+
+    /// \brief Return the native \c io_service object used in this wrapper.
+    ///
+    /// This is a short term work around to support other BIND 10 modules
+    /// that share the same \c io_service with the authoritative server.
+    /// It will eventually be removed once the wrapper interface is
+    /// generalized.
+    asio::io_service& get_io_service() { return io_service_.get_io_service(); };
+private:
+    DNSServiceImpl* impl_;
+    IOService& io_service_;
 };
 
 /// \brief The \c DNSServer class is a wrapper (and base class) for
@@ -248,6 +291,9 @@ public:
 
     /// \brief Resume processing of the server coroutine after an 
     /// asynchronous call (e.g., to the DNS Lookup provider) has completed.
+    ///
+    /// \param done If true, this signals the system there is an answer
+    ///             to return.
     virtual inline void resume(const bool done) { self_->resume(done); }
 
     /// \brief Indicate whether the server is able to send an answer
@@ -262,6 +308,8 @@ public:
     /// purposes during development and removed later.  It allows
     /// callers from outside the coroutine object to retrieve information
     /// about its current state.
+    ///
+    /// \return The value of the 'coroutine' object
     virtual inline int value() { return (self_->value()); }
 
     /// \brief Returns a pointer to a clone of this DNSServer object.
@@ -270,6 +318,8 @@ public:
     /// normally be another \c DNSServer object containing a copy
     /// of the original "self_" pointer.  Calling clone() guarantees
     /// that the underlying object is also correctly copied.
+    ///
+    /// \return A deep copy of this DNSServer object
     virtual inline DNSServer* clone() { return (self_->clone()); }
     //@}
 
@@ -349,6 +399,11 @@ public:
     /// This makes its call indirectly via the "self" pointer, ensuring
     /// that the function ultimately invoked will be the one in the derived
     /// class.
+    ///
+    /// \param io_message The event message to handle
+    /// \param message The DNS MessagePtr that needs handling
+    /// \param buffer The final answer is put here
+    /// \param DNSServer DNSServer object to use
     virtual void operator()(const IOMessage& io_message,
                             isc::dns::MessagePtr message,
                             isc::dns::OutputBufferPtr buffer,
@@ -394,6 +449,14 @@ public:
     virtual ~DNSAnswer() {}
     //@}
     /// \brief The function operator
+    ///
+    /// This makes its call indirectly via the "self" pointer, ensuring
+    /// that the function ultimately invoked will be the one in the derived
+    /// class.
+    ///
+    /// \param io_message The event message to handle
+    /// \param message The DNS MessagePtr that needs handling
+    /// \param buffer The result is put here
     virtual void operator()(const IOMessage& io_message,
                             isc::dns::MessagePtr message,
                             isc::dns::OutputBufferPtr buffer) const = 0;
@@ -436,6 +499,8 @@ public:
     /// This makes its call indirectly via the "self" pointer, ensuring
     /// that the function ultimately invoked will be the one in the derived
     /// class.
+    ///
+    /// \param io_message The event message to handle
     virtual void operator()(const IOMessage& io_message) const {
         (*self_)(io_message);
     }
@@ -459,6 +524,10 @@ public:
     /// 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.
+    /// \param dns_service The DNS Service to perform the recursive
+    ///        query on.
+    /// \param upstream Addresses and ports of the upstream servers
+    ///        to forward queries to.
     RecursiveQuery(IOService& io_service,
                    const std::vector<std::pair<std::string, uint16_t> >&
                    upstream);
@@ -466,19 +535,19 @@ public:
 
     /// \brief Initiates an upstream query in the \c RecursiveQuery object.
     ///
-    /// \param question The question being answered <qname/qclass/qtype>
-    /// \param buffer An output buffer into which the response can be copied
-    /// \param server A pointer to the \c DNSServer object handling the client
-    ///
     /// 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.
+    ///
+    /// \param question The question being answered <qname/qclass/qtype>
+    /// \param buffer An output buffer into which the response can be copied
+    /// \param server A pointer to the \c DNSServer object handling the client
     void sendQuery(const isc::dns::Question& question,
                    isc::dns::OutputBufferPtr buffer,
                    DNSServer* server);
 private:
-    IOService& io_service_;
+    DNSService& dns_service_;
     std::vector<std::pair<std::string, uint16_t> > upstream_;
 };
 

+ 84 - 56
src/lib/asiolink/tests/asiolink_unittest.cc

@@ -135,69 +135,92 @@ TEST(IOSocketTest, dummySockets) {
 }
 
 TEST(IOServiceTest, badPort) {
-    EXPECT_THROW(IOService(*"65536", true, false, NULL, NULL, NULL), IOError);
-    EXPECT_THROW(IOService(*"5300.0", true, false, NULL, NULL, NULL), IOError);
-    EXPECT_THROW(IOService(*"-1", true, false, NULL, NULL, NULL), IOError);
-    EXPECT_THROW(IOService(*"domain", true, false, NULL, NULL, NULL), IOError);
+    IOService io_service;
+    EXPECT_THROW(DNSService(io_service, *"65536", true, false, NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *"5300.0", true, false, NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *"-1", true, false, NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *"domain", true, false, NULL, NULL, NULL), IOError);
 }
 
 TEST(IOServiceTest, badAddress) {
-    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);
+    IOService io_service;
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.1.1", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"2001:db8:::1", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"localhost", NULL, NULL, NULL), IOError);
 }
 
 TEST(IOServiceTest, unavailableAddress) {
+    IOService io_service;
     // These addresses should generally be unavailable as a valid local
     // address, although there's no guarantee in theory.
-    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *"255.255.0.0", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"255.255.0.0", NULL, NULL, NULL), IOError);
 
     // 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
     // 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
     // as the previous one.
-    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *"::ffff:255.255.0.0", NULL, NULL, NULL), IOError);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:255.255.0.0", NULL, NULL, NULL), IOError);
 }
 
-TEST(IOServiceTest, duplicateBind) {
+TEST(IOServiceTest, duplicateBind_v6) {
     // In each sub test case, second attempt should fail due to duplicate bind
+    IOService io_service;
 
     // IPv6, "any" address
-    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;
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL), IOError);
+    delete dns_service;
+
+}
+
+TEST(IOServiceTest, duplicateBind_v6_address) {
+    // In each sub test case, second attempt should fail due to duplicate bind
+    IOService io_service;
 
     // IPv6, specific address
-    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;
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL), IOError);
+    delete dns_service;
+
+}
+
+TEST(IOServiceTest, duplicateBind_v4) {
+    // In each sub test case, second attempt should fail due to duplicate bind
+    IOService io_service;
 
     // IPv4, "any" address
-    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;
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL), IOError);
+    delete dns_service;
+
+}
+
+TEST(IOServiceTest, duplicateBind_v4_address) {
+    // In each sub test case, second attempt should fail due to duplicate bind
+    IOService io_service;
 
     // IPv4, specific address
-    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;
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL), IOError);
+    delete dns_service;
 }
 
 // Disabled because IPv4-mapped addresses don't seem to be working with
 // the IOService constructor
 TEST(IOServiceTest, DISABLED_IPv4MappedDuplicateBind) {
+    IOService io_service;
     // Duplicate bind on IPv4-mapped IPv6 address
-    IOService* io_service = new IOService(*TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL);
-    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL), IOError);
-    delete io_service;
+    DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL), IOError);
+    delete dns_service;
 
     // XXX:
     // Currently, this throws an "invalid argument" exception.  I have
     // not been able to get IPv4-mapped addresses to work.
-    io_service = new IOService(*TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL);
-    EXPECT_THROW(IOService(*TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL), IOError);
-    delete io_service;
+    dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL);
+    EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL), IOError);
+    delete dns_service;
 }
 
 // This function returns an addrinfo structure for use by tests, using
@@ -234,7 +257,7 @@ resolveAddress(const int family, const int protocol, const bool client) {
 // received on the server side.  It then checks the received data matches
 // expected parameters.
 // If initialization parameters of the IOService should be modified, the test
-// case can do it using the setIOService() method.
+// case can do it using the setDNSService() method.
 // Note: the set of tests in ASIOLinkTest use actual network services and may
 // involve undesirable side effects such as blocking.
 class ASIOLinkTest : public ::testing::Test {
@@ -247,12 +270,9 @@ protected:
         if (sock_ != -1) {
             close(sock_);
         }
-        if (io_service_ != NULL) {
-            delete io_service_;
-        }
-        if (callback_ != NULL) {
-            delete callback_;
-        }
+        delete dns_service_;
+        delete callback_;
+        delete io_service_;
     }
 
     // Send a test UDP packet to a mock server
@@ -324,21 +344,25 @@ protected:
 
 
     // Set up an IO Service queue using the specified address
-    void setIOService(const char& address) {
+    void setDNSService(const char& address) {
+        delete dns_service_;
+        dns_service_ = NULL;
         delete io_service_;
-        io_service_ = NULL;
+        io_service_ = new IOService();
         callback_ = new ASIOCallBack(this);
-        io_service_ = new IOService(*TEST_SERVER_PORT, address, callback_, NULL, NULL);
+        dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, address, callback_, NULL, NULL);
     }
 
     // Set up an IO Service queue using the "any" address, on IPv4 if
     // 'use_ipv4' is true and on IPv6 if 'use_ipv6' is true.
-    void setIOService(const bool use_ipv4, const bool use_ipv6) {
+    void setDNSService(const bool use_ipv4, const bool use_ipv6) {
+        delete dns_service_;
+        dns_service_ = NULL;
         delete io_service_;
-        io_service_ = NULL;
+        io_service_ = new IOService();
         callback_ = new ASIOCallBack(this);
-        io_service_ = new IOService(*TEST_SERVER_PORT, use_ipv4, use_ipv6, callback_,
-                                    NULL, NULL);
+        dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, use_ipv4, use_ipv6, callback_,
+                                      NULL, NULL);
     }
 
     // Set up an IO Service queue without any addresses
@@ -455,7 +479,10 @@ private:
         io_service_->stop();
     }
 protected:
+    // We use a pointer for io_service_, because for some tests we
+    // need to recreate a new one within one onstance of this class
     IOService* io_service_;
+    DNSService* dns_service_;
     ASIOCallBack* callback_;
     int callback_protocol_;
     int callback_native_;
@@ -467,9 +494,10 @@ private:
 };
 
 ASIOLinkTest::ASIOLinkTest() :
-    io_service_(NULL), callback_(NULL), sock_(-1), res_(NULL)
+    dns_service_(NULL), callback_(NULL), sock_(-1), res_(NULL)
 {
-    setIOService(true, true);
+    io_service_ = new IOService();
+    setDNSService(true, true);
 }
 
 TEST_F(ASIOLinkTest, v6UDPSend) {
@@ -500,24 +528,24 @@ TEST_F(ASIOLinkTest, v6UDPSendSpecific) {
     // an error on a subsequent read operation.  We could do it, but for
     // simplicity we only tests the easier cases for now.
 
-    setIOService(*TEST_IPV6_ADDR);
+    setDNSService(*TEST_IPV6_ADDR);
     doTest(AF_INET6, IPPROTO_UDP);
 }
 
 TEST_F(ASIOLinkTest, v6TCPSendSpecific) {
-    setIOService(*TEST_IPV6_ADDR);
+    setDNSService(*TEST_IPV6_ADDR);
     doTest(AF_INET6, IPPROTO_TCP);
 
     EXPECT_THROW(sendTCP(AF_INET), IOError);
 }
 
 TEST_F(ASIOLinkTest, v4UDPSendSpecific) {
-    setIOService(*TEST_IPV4_ADDR);
+    setDNSService(*TEST_IPV4_ADDR);
     doTest(AF_INET, IPPROTO_UDP);
 }
 
 TEST_F(ASIOLinkTest, v4TCPSendSpecific) {
-    setIOService(*TEST_IPV4_ADDR);
+    setDNSService(*TEST_IPV4_ADDR);
     doTest(AF_INET, IPPROTO_TCP);
 
     EXPECT_THROW(sendTCP(AF_INET6), IOError);
@@ -552,12 +580,12 @@ TEST_F(ASIOLinkTest, v6TCPOnly) {
     // Open only IPv6 TCP socket.  A subsequent attempt of establishing an
     // IPv4/TCP connection should fail.  See above for why we only test this
     // for TCP.
-    setIOService(false, true);
+    setDNSService(false, true);
     EXPECT_THROW(sendTCP(AF_INET), IOError);
 }
 
 TEST_F(ASIOLinkTest, v4TCPOnly) {
-    setIOService(true, false);
+    setDNSService(true, false);
     EXPECT_THROW(sendTCP(AF_INET6), IOError);
 }
 
@@ -569,16 +597,16 @@ singleAddress(const string &address, uint16_t port) {
 }
 
 TEST_F(ASIOLinkTest, recursiveSetupV4) {
-    setIOService(true, false);
+    setDNSService(true, false);
     uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
-    EXPECT_NO_THROW(RecursiveQuery(*io_service_, singleAddress(TEST_IPV6_ADDR,
+    EXPECT_NO_THROW(RecursiveQuery(*dns_service_, singleAddress(TEST_IPV6_ADDR,
         port)));
 }
 
 TEST_F(ASIOLinkTest, recursiveSetupV6) {
-    setIOService(false, true);
+    setDNSService(false, true);
     uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
-    EXPECT_NO_THROW(RecursiveQuery(*io_service_, singleAddress(TEST_IPV6_ADDR,
+    EXPECT_NO_THROW(RecursiveQuery(*dns_service_, singleAddress(TEST_IPV6_ADDR,
         port)));
 }
 
@@ -588,7 +616,7 @@ TEST_F(ASIOLinkTest, recursiveSetupV6) {
 // port, and with the various callbacks defined in such a way as to ensure
 // full code coverage including error cases.
 TEST_F(ASIOLinkTest, recursiveSend) {
-    setIOService(true, false);
+    setDNSService(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
@@ -597,7 +625,7 @@ TEST_F(ASIOLinkTest, recursiveSend) {
     asio::ip::address addr = asio::ip::address::from_string(TEST_IPV4_ADDR);
 
     MockServer server(io, addr, port, NULL, NULL, NULL);
-    RecursiveQuery rq(*io_service_, singleAddress(TEST_IPV4_ADDR, port));
+    RecursiveQuery rq(*dns_service_, singleAddress(TEST_IPV4_ADDR, port));
 
     Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
     OutputBufferPtr buffer(new OutputBuffer(0));