BIND 10 trac569, updated. a151c4a62009d73ab3f05607ccd12889de4b9718 [trac569] split up udpdns.[h|cc] and tcpdns.[h|cc] too

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Feb 14 11:58:43 UTC 2011


The branch, trac569 has been updated
       via  a151c4a62009d73ab3f05607ccd12889de4b9718 (commit)
      from  c9eb48c9a8c49d99a31ce752b11ac507f3346356 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a151c4a62009d73ab3f05607ccd12889de4b9718
Author: Jelte Jansen <jelte at isc.org>
Date:   Mon Feb 14 12:56:49 2011 +0100

    [trac569] split up udpdns.[h|cc] and tcpdns.[h|cc] too
    
    and moved them out of internal. Changed the internal/ workaround (to prevent files outside of asiolink/ to indirectly include asio.hpp), the .cc files that include the relevant headers must include asio.hpp themselves (and this is checked in the headers)
    Also moved coroutine out of internal.
    Tests are still todo (which is why internal/ still exists)

-----------------------------------------------------------------------

Summary of changes:
 src/lib/asiolink/Makefile.am                       |    9 +-
 src/lib/asiolink/{internal => }/coroutine.h        |    0 
 src/lib/asiolink/dns_lookup.h                      |    1 +
 src/lib/asiolink/dns_service.cc                    |    5 +-
 src/lib/asiolink/internal/tcpdns.h                 |  224 ----------
 src/lib/asiolink/internal/tests/udpdns_unittest.cc |    2 +-
 src/lib/asiolink/internal/udpdns.h                 |  253 ------------
 src/lib/asiolink/ioendpoint.cc                     |    8 +-
 src/lib/asiolink/recursive_query.cc                |    5 +-
 src/lib/asiolink/tcp_endpoint.h                    |   98 +++++
 src/lib/asiolink/{tcpdns.cc => tcp_server.cc}      |   25 +-
 src/lib/asiolink/tcp_server.h                      |  119 ++++++
 src/lib/asiolink/tcp_socket.h                      |   52 +++
 src/lib/asiolink/udp_endpoint.h                    |   89 ++++
 src/lib/asiolink/udp_query.h                       |   88 ++++
 src/lib/asiolink/udp_server.h                      |  102 +++++
 src/lib/asiolink/udp_socket.h                      |   48 +++
 src/lib/asiolink/udpdns.cc                         |  432 --------------------
 18 files changed, 626 insertions(+), 934 deletions(-)
 rename src/lib/asiolink/{internal => }/coroutine.h (100%)
 delete mode 100644 src/lib/asiolink/internal/tcpdns.h
 delete mode 100644 src/lib/asiolink/internal/udpdns.h
 create mode 100644 src/lib/asiolink/tcp_endpoint.h
 rename src/lib/asiolink/{tcpdns.cc => tcp_server.cc} (93%)
 create mode 100644 src/lib/asiolink/tcp_server.h
 create mode 100644 src/lib/asiolink/tcp_socket.h
 create mode 100644 src/lib/asiolink/udp_endpoint.h
 create mode 100644 src/lib/asiolink/udp_query.h
 create mode 100644 src/lib/asiolink/udp_server.h
 create mode 100644 src/lib/asiolink/udp_socket.h
 delete mode 100644 src/lib/asiolink/udpdns.cc

-----------------------------------------------------------------------
diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am
index a4442a6..e1590fd 100644
--- a/src/lib/asiolink/Makefile.am
+++ b/src/lib/asiolink/Makefile.am
@@ -25,9 +25,12 @@ libasiolink_la_SOURCES += iosocket.cc iosocket.h
 libasiolink_la_SOURCES += 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
+libasiolink_la_SOURCES += udp_endpoint.h udp_socket.h
+libasiolink_la_SOURCES += udp_server.h udp_server.cc
+libasiolink_la_SOURCES += udp_query.h udp_query.cc
+libasiolink_la_SOURCES += tcp_endpoint.h tcp_socket.h
+libasiolink_la_SOURCES += tcp_server.h tcp_server.cc
+libasiolink_la_SOURCES += coroutine.h
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # B10_CXXFLAGS)
 libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS)
diff --git a/src/lib/asiolink/coroutine.h b/src/lib/asiolink/coroutine.h
new file mode 100644
index 0000000..985888b
--- /dev/null
+++ b/src/lib/asiolink/coroutine.h
@@ -0,0 +1,133 @@
+//
+// coroutine.h
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef COROUTINE_HPP
+#define COROUTINE_HPP
+
+
+// \brief Coroutine object
+//
+// A coroutine object maintains the state of a re-enterable routine.  It
+// is assignable and copy-constructable, and can be used as a base class
+// for a class that uses it, or as a data member.  The copy overhead is
+// a single int.
+//
+// A reenterable function contains a CORO_REENTER (coroutine)  { ... }
+// block.  Whenever an asychrnonous operation is initiated within the
+// routine, the function is provided as the handler object.  (The simplest
+// way to do this is to have the reenterable function be the operator()
+// member for the coroutine object itself.)   For example:
+// 
+//     CORO_YIELD socket->async_read_some(buffer, *this);
+//
+// The CORO_YIELD keyword updates the current status of the coroutine to
+// indicate the line number currently being executed.  The
+// async_read_some() call is initiated, with a copy of the updated
+// corotutine as its handler object, and the current coroutine exits.  When
+// the async_read_some() call finishes, the copied coroutine will be
+// called, and will resume processing exactly where the original one left
+// off--right after asynchronous call.  This allows asynchronous I/O
+// routines to be written with a logical flow, step following step, rather
+// than as a linked chain of separate handler functions.
+//
+// When necessary, a coroutine can fork itself using the CORO_FORK keyword.
+// This updates the status of the coroutine and makes a copy.  The copy can
+// then be called directly or posted to the ASIO service queue so that both
+// coroutines will continue forward, one "parent" and one "child".  The
+// is_parent() and is_child() methods indicate which is which.
+//
+// The CORO_REENTER, CORO_YIELD and CORO_FORK keywords are implemented
+// via preprocessor macros.  The CORO_REENTER block is actually a large,
+// complex switch statement.  Because of this, inline variable declaration
+// is impossible within CORO_REENTER unless it is done in a subsidiary
+// scope--and if it is, that scope cannot contain CORO_YIELD or CORO_FORK
+// keywords.
+//
+// Because coroutines are frequently copied, it is best to minimize copy
+// overhead by limiting the size of data members in derived classes.
+//
+// It should be noted that when a coroutine falls out of scope its memory
+// is reclaimed, even though it may be scheduled to resume when an
+// asynchronous operation completes.  Any shared_ptr<> objects declared in
+// the coroutine may be destroyed if their reference count drops to zero,
+// in which case the coroutine will have serious problems once it resumes.
+// One solution so this is to have the space that will be used by a
+// coroutine pre-allocated and stored on a free list; a new coroutine can
+// fetch the block of space off a free list, place a shared pointer to it
+// on an "in use" list, and carry on.  The reference in the "in use" list
+// would prevent the data from being destroyed.
+class coroutine
+{
+public:
+  coroutine() : value_(0) {}
+  virtual ~coroutine() {}
+  bool is_child() const { return value_ < 0; }
+  bool is_parent() const { return !is_child(); }
+  bool is_complete() const { return value_ == -1; }
+  int get_value() const { return value_; }
+private:
+  friend class coroutine_ref;
+  int value_;
+};
+
+class coroutine_ref
+{
+public:
+  coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
+  coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
+  ~coroutine_ref() { if (!modified_) value_ = -1; }
+  operator int() const { return value_; }
+  int& operator=(int v) { modified_ = true; return value_ = v; }
+private:
+  void operator=(const coroutine_ref&);
+  int& value_;
+  bool modified_;
+};
+
+#define CORO_REENTER(c) \
+  switch (coroutine_ref _coro_value = c) \
+    case -1: if (_coro_value) \
+    { \
+      goto terminate_coroutine; \
+      terminate_coroutine: \
+      _coro_value = -1; \
+      goto bail_out_of_coroutine; \
+      bail_out_of_coroutine: \
+      break; \
+    } \
+    else case 0:
+
+#define CORO_YIELD \
+  for (_coro_value = __LINE__;;) \
+    if (_coro_value == 0) \
+    { \
+      case __LINE__: ; \
+      break; \
+    } \
+    else \
+      switch (_coro_value ? 0 : 1) \
+        for (;;) \
+          case -1: if (_coro_value) \
+            goto terminate_coroutine; \
+          else for (;;) \
+            case 1: if (_coro_value) \
+              goto bail_out_of_coroutine; \
+            else case 0:
+
+#define CORO_FORK \
+  for (_coro_value = -__LINE__;; _coro_value = __LINE__) \
+    if (_coro_value == __LINE__) \
+    { \
+      case -__LINE__: ; \
+      break; \
+    } \
+    else
+#endif // COROUTINE_HPP
+
diff --git a/src/lib/asiolink/dns_lookup.h b/src/lib/asiolink/dns_lookup.h
index 5a5949d..e4ccb81 100644
--- a/src/lib/asiolink/dns_lookup.h
+++ b/src/lib/asiolink/dns_lookup.h
@@ -18,6 +18,7 @@
 #include <asiolink/iomessage.h>
 #include <asiolink/dns_server.h>
 #include <dns/buffer.h>
+#include <dns/message.h>
 
 namespace asiolink {
 
diff --git a/src/lib/asiolink/dns_service.cc b/src/lib/asiolink/dns_service.cc
index 8188622..ee4f31b 100644
--- a/src/lib/asiolink/dns_service.cc
+++ b/src/lib/asiolink/dns_service.cc
@@ -18,8 +18,9 @@
 
 #include <asio/ip/address.hpp>
 
-#include <asiolink/internal/tcpdns.h>
-#include <asiolink/internal/udpdns.h>
+#include <asio.hpp>
+#include <tcp_server.h>
+#include <asiolink/udp_server.h>
 
 #include <log/dummylog.h>
 
diff --git a/src/lib/asiolink/internal/coroutine.h b/src/lib/asiolink/internal/coroutine.h
deleted file mode 100644
index 985888b..0000000
--- a/src/lib/asiolink/internal/coroutine.h
+++ /dev/null
@@ -1,133 +0,0 @@
-//
-// coroutine.h
-// ~~~~~~~~~~~
-//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef COROUTINE_HPP
-#define COROUTINE_HPP
-
-
-// \brief Coroutine object
-//
-// A coroutine object maintains the state of a re-enterable routine.  It
-// is assignable and copy-constructable, and can be used as a base class
-// for a class that uses it, or as a data member.  The copy overhead is
-// a single int.
-//
-// A reenterable function contains a CORO_REENTER (coroutine)  { ... }
-// block.  Whenever an asychrnonous operation is initiated within the
-// routine, the function is provided as the handler object.  (The simplest
-// way to do this is to have the reenterable function be the operator()
-// member for the coroutine object itself.)   For example:
-// 
-//     CORO_YIELD socket->async_read_some(buffer, *this);
-//
-// The CORO_YIELD keyword updates the current status of the coroutine to
-// indicate the line number currently being executed.  The
-// async_read_some() call is initiated, with a copy of the updated
-// corotutine as its handler object, and the current coroutine exits.  When
-// the async_read_some() call finishes, the copied coroutine will be
-// called, and will resume processing exactly where the original one left
-// off--right after asynchronous call.  This allows asynchronous I/O
-// routines to be written with a logical flow, step following step, rather
-// than as a linked chain of separate handler functions.
-//
-// When necessary, a coroutine can fork itself using the CORO_FORK keyword.
-// This updates the status of the coroutine and makes a copy.  The copy can
-// then be called directly or posted to the ASIO service queue so that both
-// coroutines will continue forward, one "parent" and one "child".  The
-// is_parent() and is_child() methods indicate which is which.
-//
-// The CORO_REENTER, CORO_YIELD and CORO_FORK keywords are implemented
-// via preprocessor macros.  The CORO_REENTER block is actually a large,
-// complex switch statement.  Because of this, inline variable declaration
-// is impossible within CORO_REENTER unless it is done in a subsidiary
-// scope--and if it is, that scope cannot contain CORO_YIELD or CORO_FORK
-// keywords.
-//
-// Because coroutines are frequently copied, it is best to minimize copy
-// overhead by limiting the size of data members in derived classes.
-//
-// It should be noted that when a coroutine falls out of scope its memory
-// is reclaimed, even though it may be scheduled to resume when an
-// asynchronous operation completes.  Any shared_ptr<> objects declared in
-// the coroutine may be destroyed if their reference count drops to zero,
-// in which case the coroutine will have serious problems once it resumes.
-// One solution so this is to have the space that will be used by a
-// coroutine pre-allocated and stored on a free list; a new coroutine can
-// fetch the block of space off a free list, place a shared pointer to it
-// on an "in use" list, and carry on.  The reference in the "in use" list
-// would prevent the data from being destroyed.
-class coroutine
-{
-public:
-  coroutine() : value_(0) {}
-  virtual ~coroutine() {}
-  bool is_child() const { return value_ < 0; }
-  bool is_parent() const { return !is_child(); }
-  bool is_complete() const { return value_ == -1; }
-  int get_value() const { return value_; }
-private:
-  friend class coroutine_ref;
-  int value_;
-};
-
-class coroutine_ref
-{
-public:
-  coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
-  coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
-  ~coroutine_ref() { if (!modified_) value_ = -1; }
-  operator int() const { return value_; }
-  int& operator=(int v) { modified_ = true; return value_ = v; }
-private:
-  void operator=(const coroutine_ref&);
-  int& value_;
-  bool modified_;
-};
-
-#define CORO_REENTER(c) \
-  switch (coroutine_ref _coro_value = c) \
-    case -1: if (_coro_value) \
-    { \
-      goto terminate_coroutine; \
-      terminate_coroutine: \
-      _coro_value = -1; \
-      goto bail_out_of_coroutine; \
-      bail_out_of_coroutine: \
-      break; \
-    } \
-    else case 0:
-
-#define CORO_YIELD \
-  for (_coro_value = __LINE__;;) \
-    if (_coro_value == 0) \
-    { \
-      case __LINE__: ; \
-      break; \
-    } \
-    else \
-      switch (_coro_value ? 0 : 1) \
-        for (;;) \
-          case -1: if (_coro_value) \
-            goto terminate_coroutine; \
-          else for (;;) \
-            case 1: if (_coro_value) \
-              goto bail_out_of_coroutine; \
-            else case 0:
-
-#define CORO_FORK \
-  for (_coro_value = -__LINE__;; _coro_value = __LINE__) \
-    if (_coro_value == __LINE__) \
-    { \
-      case -__LINE__: ; \
-      break; \
-    } \
-    else
-#endif // COROUTINE_HPP
-
diff --git a/src/lib/asiolink/internal/tcpdns.h b/src/lib/asiolink/internal/tcpdns.h
deleted file mode 100644
index a97ed17..0000000
--- a/src/lib/asiolink/internal/tcpdns.h
+++ /dev/null
@@ -1,224 +0,0 @@
-// 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.
-
-#ifndef __TCPDNS_H
-#define __TCPDNS_H 1
-
-#include <config.h>
-
-
-#include <asio.hpp>
-#include <boost/shared_array.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <dns/buffer.h>
-#include <dns/message.h>
-
-#include <asiolink/asiolink.h>
-#include <asiolink/internal/coroutine.h>
-
-// This file contains TCP-specific implementations of generic classes 
-// defined in asiolink.h.  It is *not* intended to be part of the public
-// API.
-
-namespace asiolink {
-/// \brief The \c TCPEndpoint class is a concrete derived class of
-/// \c IOEndpoint that represents an endpoint of a TCP connection.
-///
-/// In the current implementation, an object of this class is always
-/// instantiated within the wrapper routines.  Applications are expected to
-/// get access to the object via the abstract base class, \c IOEndpoint.
-/// This design may be changed when we generalize the wrapper interface.
-///
-/// Note: this implementation is optimized for the case where this object
-/// is created from an ASIO endpoint object in a receiving code path
-/// by avoiding to make a copy of the base endpoint.  For TCP it may not be
-/// a big deal, but when we receive UDP packets at a high rate, the copy
-/// overhead might be significant.
-class TCPEndpoint : public IOEndpoint {
-public:
-    ///
-    /// \name Constructors and Destructor
-    ///
-    //@{
-    /// \brief Constructor from a pair of address and port.
-    ///
-    /// \param address The IP address of the endpoint.
-    /// \param port The TCP port number of the endpoint.
-    TCPEndpoint(const IOAddress& address, const unsigned short port) :
-        asio_endpoint_placeholder_(
-            new asio::ip::tcp::endpoint(
-                asio::ip::address::from_string(address.toText()), port)),
-        asio_endpoint_(*asio_endpoint_placeholder_)
-    {}
-
-    /// \brief Constructor from an ASIO TCP endpoint.
-    ///
-    /// This constructor is designed to be an efficient wrapper for the
-    /// corresponding ASIO class, \c tcp::endpoint.
-    ///
-    /// \param asio_endpoint The ASIO representation of the TCP endpoint.
-    TCPEndpoint(const asio::ip::tcp::endpoint& asio_endpoint) :
-        asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint)
-    {}
-
-    /// \brief The destructor.
-    ~TCPEndpoint() { delete asio_endpoint_placeholder_; }
-    //@}
-
-    IOAddress getAddress() const {
-        return (asio_endpoint_.address());
-    }
-
-    uint16_t getPort() const {
-        return (asio_endpoint_.port());
-    }
-
-    short getProtocol() const {
-        return (asio_endpoint_.protocol().protocol());
-    }
-
-    short getFamily() const {
-        return (asio_endpoint_.protocol().family());
-    }
-
-    // This is not part of the exosed IOEndpoint API but allows
-    // direct access to the ASIO implementation of the endpoint
-    const asio::ip::tcp::endpoint& getASIOEndpoint() const {
-        return (asio_endpoint_);
-    }
-
-private:
-    const asio::ip::tcp::endpoint* asio_endpoint_placeholder_;
-    const asio::ip::tcp::endpoint& asio_endpoint_;
-};
-
-/// \brief The \c TCPSocket class is a concrete derived class of
-/// \c IOSocket that represents a TCP socket.
-///
-/// In the current implementation, an object of this class is always
-/// instantiated within the wrapper routines.  Applications are expected to
-/// get access to the object via the abstract base class, \c IOSocket.
-/// This design may be changed when we generalize the wrapper interface.
-class TCPSocket : public IOSocket {
-private:
-    TCPSocket(const TCPSocket& source);
-    TCPSocket& operator=(const TCPSocket& source);
-public:
-    /// \brief Constructor from an ASIO TCP socket.
-    ///
-    /// \param socket The ASIO representation of the TCP socket.
-    TCPSocket(asio::ip::tcp::socket& socket) : socket_(socket) {}
-
-    int getNative() const { return (socket_.native()); }
-    int getProtocol() const { return (IPPROTO_TCP); }
-
-private:
-    asio::ip::tcp::socket& socket_;
-};
-
-/// \brief A TCP-specific \c DNSServer object.
-///
-/// This class inherits from both \c DNSServer and from \c coroutine,
-/// defined in coroutine.h. 
-class TCPServer : public virtual DNSServer, public virtual coroutine {
-public:
-    explicit TCPServer(asio::io_service& io_service,
-                       const asio::ip::address& addr, const uint16_t port, 
-                       const SimpleCallback* checkin = NULL,
-                       const DNSLookup* lookup = NULL,
-                       const DNSAnswer* answer = NULL);
-
-    void operator()(asio::error_code ec = asio::error_code(),
-                    size_t length = 0);
-    void asyncLookup();
-    void resume(const bool done);
-    bool hasAnswer() { return (done_); }
-    int value() { return (get_value()); }
-
-    DNSServer* clone() {
-        TCPServer* s = new TCPServer(*this);
-        return (s);
-    }
-
-private:
-    enum { MAX_LENGTH = 65535 };
-    static const size_t TCP_MESSAGE_LENGTHSIZE = 2;
-
-    // The ASIO service object
-    asio::io_service& io_;
-
-    // Class member variables which are dynamic, and changes to which
-    // need to accessible from both sides of a coroutine fork or from
-    // outside of the coroutine (i.e., from an asynchronous I/O call),
-    // should be declared here as pointers and allocated in the
-    // constructor or in the coroutine.  This allows state information
-    // to persist when an individual copy of the coroutine falls out
-    // scope while waiting for an event, *so long as* there is another
-    // object that is referencing the same data.  As a side-benefit, using
-    // pointers also reduces copy overhead for coroutine objects.
-    //
-    // Note: Currently these objects are allocated by "new" in the
-    // constructor, or in the function operator while processing a query.
-    // Repeated allocations from the heap for every incoming query is
-    // clearly a performance issue; this must be optimized in the future.
-    // The plan is to have a structure pre-allocate several "server state"
-    // objects which can be pulled off a free list and placed on an in-use
-    // list whenever a query comes in.  This will serve the dual purpose
-    // of improving performance and guaranteeing that state information
-    // will *not* be destroyed when any one instance of the coroutine
-    // falls out of scope while waiting for an event.
-    //
-    // An ASIO acceptor object to handle new connections.  Created in
-    // the constructor.
-    boost::shared_ptr<asio::ip::tcp::acceptor> acceptor_;
-
-    // Socket used to for listen for queries.  Created in the
-    // constructor and stored in a shared_ptr because socket objects
-    // are not copyable.
-    boost::shared_ptr<asio::ip::tcp::socket> socket_;
-
-    // The buffer into which the response is written
-    boost::shared_ptr<isc::dns::OutputBuffer> respbuf_;
-
-    // \c IOMessage and \c Message objects to be passed to the
-    // DNS lookup and answer providers
-    boost::shared_ptr<asiolink::IOMessage> io_message_;
-    isc::dns::MessagePtr query_message_;
-    isc::dns::MessagePtr answer_message_;
-
-    // The buffer into which the query packet is written
-    boost::shared_array<char>data_;
-
-    // State information that is entirely internal to a given instance
-    // of the coroutine can be declared here.
-    size_t bytes_;
-    bool done_;
-
-    // Callback functions provided by the caller
-    const SimpleCallback* checkin_callback_;
-    const DNSLookup* lookup_callback_;
-    const DNSAnswer* answer_callback_;
-
-    boost::shared_ptr<IOEndpoint> peer_;
-    boost::shared_ptr<IOSocket> iosock_;
-};
-
-}
-
-#endif // __TCPDNS_H
-
-// Local Variables: 
-// mode: c++
-// End: 
diff --git a/src/lib/asiolink/internal/tests/udpdns_unittest.cc b/src/lib/asiolink/internal/tests/udpdns_unittest.cc
index 099071c..fe52244 100644
--- a/src/lib/asiolink/internal/tests/udpdns_unittest.cc
+++ b/src/lib/asiolink/internal/tests/udpdns_unittest.cc
@@ -19,7 +19,7 @@
 
 #include <dns/question.h>
 
-#include <asiolink/internal/udpdns.h>
+#include <asiolink/udp_query.h>
 
 using namespace asio;
 using namespace isc::dns;
diff --git a/src/lib/asiolink/internal/udpdns.h b/src/lib/asiolink/internal/udpdns.h
deleted file mode 100644
index 5b67ca9..0000000
--- a/src/lib/asiolink/internal/udpdns.h
+++ /dev/null
@@ -1,253 +0,0 @@
-// 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.
-
-#ifndef __UDPDNS_H
-#define __UDPDNS_H 1
-
-#include <config.h>
-
-#include <asio.hpp>
-#include <boost/shared_array.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <dns/buffer.h>
-#include <dns/message.h>
-#include <dns/messagerenderer.h>
-
-#include <asiolink/asiolink.h>
-#include <asiolink/internal/coroutine.h>
-
-// This file contains UDP-specific implementations of generic classes 
-// defined in asiolink.h.  It is *not* intended to be part of the public
-// API.
-
-namespace asiolink {
-/// \brief The \c UDPEndpoint class is a concrete derived class of
-/// \c IOEndpoint that represents an endpoint of a UDP packet.
-///
-/// Other notes about \c TCPEndpoint applies to this class, too.
-class UDPEndpoint : public IOEndpoint {
-public:
-    ///
-    /// \name Constructors and Destructor.
-    ///
-    //@{
-    /// \brief Constructor from a pair of address and port.
-    ///
-    /// \param address The IP address of the endpoint.
-    /// \param port The UDP port number of the endpoint.
-    UDPEndpoint(const IOAddress& address, const unsigned short port) :
-        asio_endpoint_placeholder_(
-            new asio::ip::udp::endpoint(asio::ip::address::from_string(address.toText()),
-                              port)),
-        asio_endpoint_(*asio_endpoint_placeholder_)
-    {}
-
-    /// \brief Constructor from an ASIO UDP endpoint.
-    ///
-    /// This constructor is designed to be an efficient wrapper for the
-    /// corresponding ASIO class, \c udp::endpoint.
-    ///
-    /// \param asio_endpoint The ASIO representation of the UDP endpoint.
-    UDPEndpoint(const asio::ip::udp::endpoint& asio_endpoint) :
-        asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint)
-    {}
-
-    /// \brief The destructor.
-    ~UDPEndpoint() { delete asio_endpoint_placeholder_; }
-    //@}
-
-    inline IOAddress getAddress() const {
-        return (asio_endpoint_.address());
-    }
-
-    inline uint16_t getPort() const {
-        return (asio_endpoint_.port());
-    }
-
-    inline short getProtocol() const {
-        return (asio_endpoint_.protocol().protocol());
-    }
-
-    inline short getFamily() const {
-        return (asio_endpoint_.protocol().family());
-    }
-
-    // This is not part of the exosed IOEndpoint API but allows
-    // direct access to the ASIO implementation of the endpoint
-    inline const asio::ip::udp::endpoint& getASIOEndpoint() const {
-        return (asio_endpoint_);
-    }
-
-private:
-    const asio::ip::udp::endpoint* asio_endpoint_placeholder_;
-    const asio::ip::udp::endpoint& asio_endpoint_;
-};
-
-/// \brief The \c UDPSocket class is a concrete derived class of
-/// \c IOSocket that represents a UDP socket.
-///
-/// Other notes about \c TCPSocket applies to this class, too.
-class UDPSocket : public IOSocket {
-private:
-    UDPSocket(const UDPSocket& source);
-    UDPSocket& operator=(const UDPSocket& source);
-public:
-    /// \brief Constructor from an ASIO UDP socket.
-    ///
-    /// \param socket The ASIO representation of the UDP socket.
-    UDPSocket(asio::ip::udp::socket& socket) : socket_(socket) {}
-
-    virtual int getNative() const { return (socket_.native()); }
-    virtual int getProtocol() const { return (IPPROTO_UDP); }
-
-private:
-    asio::ip::udp::socket& socket_;
-};
-
-//
-// Asynchronous UDP server coroutine
-//
-///
-/// \brief This class implements the coroutine to handle UDP
-///        DNS query event. As such, it is both a \c DNSServer and
-///        a \c coroutine
-///
-class UDPServer : public virtual DNSServer, public virtual coroutine {
-public:
-    /// \brief Constructor
-    /// \param io_service the asio::io_service to work with
-    /// \param addr the IP address to listen for queries on
-    /// \param port the port to listen for queries on
-    /// \param checkin the callbackprovider for non-DNS events
-    /// \param lookup the callbackprovider for DNS lookup events
-    /// \param answer the callbackprovider for DNS answer events
-    explicit UDPServer(asio::io_service& io_service,
-                       const asio::ip::address& addr, const uint16_t port,
-                       SimpleCallback* checkin = NULL,
-                       DNSLookup* lookup = NULL,
-                       DNSAnswer* answer = NULL);
-
-    /// \brief The function operator
-    void operator()(asio::error_code ec = asio::error_code(),
-                    size_t length = 0);
-
-    /// \brief Calls the lookup callback
-    void asyncLookup();
-
-    /// \brief Resume operation
-    ///
-    /// \param done Set this to true if the lookup action is done and
-    ///        we have an answer
-    void resume(const bool done);
-
-    /// \brief Check if we have an answer
-    ///
-    /// \return true if we have an answer
-    bool hasAnswer();
-
-    /// \brief Returns the coroutine state value
-    ///
-    /// \return the coroutine state value
-    int value() { return (get_value()); }
-
-    /// \brief Clones the object
-    ///
-    /// \return a newly allocated copy of this object
-    DNSServer* clone() {
-        UDPServer* s = new UDPServer(*this);
-        return (s);
-    }
-
-private:
-    enum { MAX_LENGTH = 4096 };
-
-    /**
-     * \brief Internal state and data.
-     *
-     * We use the pimple design pattern, but not because we need to hide
-     * internal data. This class and whole header is for private use anyway.
-     * It turned out that UDPServer is copied a lot, because it is a coroutine.
-     * This way the overhead of copying is lower, we copy only one shared
-     * pointer instead of about 10 of them.
-     */
-    class Data;
-    boost::shared_ptr<Data> data_;
-};
-
-//
-// Asynchronous UDP coroutine for upstream queries
-//
-class UDPQuery : public coroutine {
-public:
-    // TODO Maybe this should be more generic than just for UDPQuery?
-    ///
-    /// \brief Result of the query
-    ///
-    /// This is related only to contacting the remote server. If the answer
-    ///indicates error, it is still counted as SUCCESS here, if it comes back.
-    ///
-    enum Result {
-        SUCCESS,
-        TIME_OUT,
-        STOPPED
-    };
-    /// Abstract callback for the UDPQuery.
-    class Callback {
-    public:
-        virtual ~Callback() {}
-
-        /// This will be called when the UDPQuery is completed
-        virtual void operator()(Result result) = 0;
-    };
-    ///
-    /// \brief Constructor.
-    ///
-    /// It creates the query.
-    /// @param callback will be called when we terminate. It is your task to
-    ///        delete it if allocated on heap.
-    ///@param timeout in ms.
-    ///
-    explicit UDPQuery(asio::io_service& io_service,
-                      const isc::dns::Question& q,
-                      const IOAddress& addr, uint16_t port,
-                      isc::dns::OutputBufferPtr buffer,
-                      Callback* callback, int timeout = -1);
-    void operator()(asio::error_code ec = asio::error_code(),
-                    size_t length = 0);
-    /// Terminate the query.
-    void stop(Result reason = STOPPED);
-private:
-    enum { MAX_LENGTH = 4096 };
-
-    ///
-    /// \short Private data
-    ///
-    /// They are not private because of stability of the
-    /// interface (this is private class anyway), but because this class
-    /// will be copyed often (it is used as a coroutine and passed as callback
-    /// to many async_*() functions) and we want keep the same data. Some of
-    /// the data is not copyable too.
-    ///
-    struct PrivateData;
-    boost::shared_ptr<PrivateData> data_;
-};
-}
-
-
-#endif // __UDPDNS_H
-
-// Local Variables: 
-// mode: c++
-// End: 
diff --git a/src/lib/asiolink/ioendpoint.cc b/src/lib/asiolink/ioendpoint.cc
index 2807f8d..86e0607 100644
--- a/src/lib/asiolink/ioendpoint.cc
+++ b/src/lib/asiolink/ioendpoint.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+// 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
@@ -18,9 +18,11 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 
+#include <asio.hpp>
+
 #include <asiolink/asiolink.h>
-#include <internal/tcpdns.h>
-#include <internal/udpdns.h>
+#include <asiolink/tcp_endpoint.h>
+#include <asiolink/udp_endpoint.h>
 
 using namespace std;
 
diff --git a/src/lib/asiolink/recursive_query.cc b/src/lib/asiolink/recursive_query.cc
index 42ed89e..2172eea 100644
--- a/src/lib/asiolink/recursive_query.cc
+++ b/src/lib/asiolink/recursive_query.cc
@@ -16,10 +16,11 @@
 
 #include <asio/ip/address.hpp>
 
+#include <asio.hpp>
+
 #include <asiolink/recursive_query.h>
 #include <asiolink/dns_service.h>
-#include <asiolink/internal/tcpdns.h>
-#include <asiolink/internal/udpdns.h>
+#include <asiolink/udp_query.h>
 
 #include <log/dummylog.h>
 
diff --git a/src/lib/asiolink/tcp_endpoint.h b/src/lib/asiolink/tcp_endpoint.h
new file mode 100644
index 0000000..6c3cbbc
--- /dev/null
+++ b/src/lib/asiolink/tcp_endpoint.h
@@ -0,0 +1,98 @@
+// 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 __TCP_ENDPOINT_H
+#define __TCP_ENDPOINT_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <asiolink/ioendpoint.h>
+
+namespace asiolink {
+
+/// \brief The \c TCPEndpoint class is a concrete derived class of
+/// \c IOEndpoint that represents an endpoint of a TCP connection.
+///
+/// In the current implementation, an object of this class is always
+/// instantiated within the wrapper routines.  Applications are expected to
+/// get access to the object via the abstract base class, \c IOEndpoint.
+/// This design may be changed when we generalize the wrapper interface.
+///
+/// Note: this implementation is optimized for the case where this object
+/// is created from an ASIO endpoint object in a receiving code path
+/// by avoiding to make a copy of the base endpoint.  For TCP it may not be
+/// a big deal, but when we receive UDP packets at a high rate, the copy
+/// overhead might be significant.
+class TCPEndpoint : public IOEndpoint {
+public:
+    ///
+    /// \name Constructors and Destructor
+    ///
+    //@{
+    /// \brief Constructor from a pair of address and port.
+    ///
+    /// \param address The IP address of the endpoint.
+    /// \param port The TCP port number of the endpoint.
+    TCPEndpoint(const IOAddress& address, const unsigned short port) :
+        asio_endpoint_placeholder_(
+            new asio::ip::tcp::endpoint(
+                asio::ip::address::from_string(address.toText()), port)),
+        asio_endpoint_(*asio_endpoint_placeholder_)
+    {}
+
+    /// \brief Constructor from an ASIO TCP endpoint.
+    ///
+    /// This constructor is designed to be an efficient wrapper for the
+    /// corresponding ASIO class, \c tcp::endpoint.
+    ///
+    /// \param asio_endpoint The ASIO representation of the TCP endpoint.
+    TCPEndpoint(const asio::ip::tcp::endpoint& asio_endpoint) :
+        asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint)
+    {}
+
+    /// \brief The destructor.
+    ~TCPEndpoint() { delete asio_endpoint_placeholder_; }
+    //@}
+
+    IOAddress getAddress() const {
+        return (asio_endpoint_.address());
+    }
+
+    uint16_t getPort() const {
+        return (asio_endpoint_.port());
+    }
+
+    short getProtocol() const {
+        return (asio_endpoint_.protocol().protocol());
+    }
+
+    short getFamily() const {
+        return (asio_endpoint_.protocol().family());
+    }
+
+    // This is not part of the exosed IOEndpoint API but allows
+    // direct access to the ASIO implementation of the endpoint
+    const asio::ip::tcp::endpoint& getASIOEndpoint() const {
+        return (asio_endpoint_);
+    }
+
+private:
+    const asio::ip::tcp::endpoint* asio_endpoint_placeholder_;
+    const asio::ip::tcp::endpoint& asio_endpoint_;
+};
+
+}      // namespace asiolink
+#endif // __TCP_ENDPOINT_H
diff --git a/src/lib/asiolink/tcp_server.cc b/src/lib/asiolink/tcp_server.cc
new file mode 100644
index 0000000..3928bc1
--- /dev/null
+++ b/src/lib/asiolink/tcp_server.cc
@@ -0,0 +1,191 @@
+// 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 <config.h>
+
+#include <boost/shared_array.hpp>
+
+#include <asio.hpp>
+
+#include <log/dummylog.h>
+
+#include <asiolink/tcp_endpoint.h>
+#include <asiolink/tcp_socket.h>
+
+#include <asiolink/tcp_server.h>
+
+
+using namespace asio;
+using asio::ip::udp;
+using asio::ip::tcp;
+
+using namespace std;
+using namespace isc::dns;
+
+namespace asiolink {
+
+/// The following functions implement the \c TCPServer class.
+///
+/// The constructor
+TCPServer::TCPServer(io_service& io_service,
+                     const ip::address& addr, const uint16_t port, 
+                     const SimpleCallback* checkin,
+                     const DNSLookup* lookup,
+                     const DNSAnswer* answer) :
+    io_(io_service), done_(false),
+    checkin_callback_(checkin), lookup_callback_(lookup),
+    answer_callback_(answer)
+{
+    tcp::endpoint endpoint(addr, port);
+    acceptor_.reset(new tcp::acceptor(io_service));
+    acceptor_->open(endpoint.protocol());
+    // Set v6-only (we use a separate instantiation for v4,
+    // otherwise asio will bind to both v4 and v6
+    if (addr.is_v6()) {
+        acceptor_->set_option(ip::v6_only(true));
+    }
+    acceptor_->set_option(tcp::acceptor::reuse_address(true));
+    acceptor_->bind(endpoint);
+    acceptor_->listen();
+}
+
+void
+TCPServer::operator()(error_code ec, size_t length) {
+    /// Because the coroutine reeentry block is implemented as
+    /// a switch statement, inline variable declarations are not
+    /// permitted.  Certain variables used below can be declared here.
+    boost::array<const_buffer,2> bufs;
+    OutputBuffer lenbuf(TCP_MESSAGE_LENGTHSIZE);
+
+    CORO_REENTER (this) {
+        do {
+            /// Create a socket to listen for connections
+            socket_.reset(new tcp::socket(acceptor_->get_io_service()));
+
+            /// Wait for new connections. In the event of error,
+            /// try again
+            do {
+                CORO_YIELD acceptor_->async_accept(*socket_, *this);
+            } while (!ec);
+
+            /// Fork the coroutine by creating a copy of this one and
+            /// scheduling it on the ASIO service queue.  The parent
+            /// will continue listening for DNS connections while the
+            /// handles the one that has just arrived.
+            CORO_FORK io_.post(TCPServer(*this));
+        } while (is_parent());
+
+        /// Instantiate the data buffer that will be used by the
+        /// asynchronous read call.
+        data_.reset(new char[MAX_LENGTH]);
+
+        /// Read the message, in two parts.  First, the message length:
+        CORO_YIELD async_read(*socket_, asio::buffer(data_.get(),
+                              TCP_MESSAGE_LENGTHSIZE), *this);
+        if (ec) {
+            CORO_YIELD return;
+        }
+
+        /// Now read the message itself. (This is done in a different scope
+        /// to allow inline variable declarations.)
+        CORO_YIELD {
+            InputBuffer dnsbuffer((const void *) data_.get(), length);
+            uint16_t msglen = dnsbuffer.readUint16();
+            async_read(*socket_, asio::buffer(data_.get(), msglen), *this);
+        }
+
+        if (ec) {
+            CORO_YIELD return;
+        }
+
+        // Create an \c IOMessage object to store the query.
+        //
+        // (XXX: It would be good to write a factory function
+        // that would quickly generate an IOMessage object without
+        // all these calls to "new".)
+        peer_.reset(new TCPEndpoint(socket_->remote_endpoint()));
+        iosock_.reset(new TCPSocket(*socket_));
+        io_message_.reset(new IOMessage(data_.get(), length, *iosock_, *peer_));
+        bytes_ = length;
+
+        // Perform any necessary operations prior to processing the incoming
+        // packet (e.g., checking for queued configuration messages).
+        //
+        // (XXX: it may be a performance issue to have this called for
+        // every single incoming packet; we may wish to throttle it somehow
+        // in the future.)
+        if (checkin_callback_ != NULL) {
+            (*checkin_callback_)(*io_message_);
+        }
+
+        // If we don't have a DNS Lookup provider, there's no point in
+        // continuing; we exit the coroutine permanently.
+        if (lookup_callback_ == NULL) {
+            CORO_YIELD return;
+        }
+
+        // Reset or instantiate objects that will be needed by the
+        // DNS lookup and the write call.
+        respbuf_.reset(new OutputBuffer(0));
+        query_message_.reset(new Message(Message::PARSE));
+        answer_message_.reset(new Message(Message::RENDER));
+
+        // Schedule a DNS lookup, and yield.  When the lookup is
+        // finished, the coroutine will resume immediately after
+        // this point.
+        CORO_YIELD io_.post(AsyncLookup<TCPServer>(*this));
+
+        // The 'done_' flag indicates whether we have an answer
+        // to send back.  If not, exit the coroutine permanently.
+        if (!done_) {
+            CORO_YIELD return;
+        }
+
+        // Call the DNS answer provider to render the answer into
+        // wire format
+        (*answer_callback_)(*io_message_, query_message_,
+                            answer_message_, respbuf_);
+
+        // Set up the response, beginning with two length bytes.
+        lenbuf.writeUint16(respbuf_->getLength());
+        bufs[0] = buffer(lenbuf.getData(), lenbuf.getLength());
+        bufs[1] = buffer(respbuf_->getData(), respbuf_->getLength());
+
+        // Begin an asynchronous send, and then yield.  When the
+        // send completes, we will resume immediately after this point
+        // (though we have nothing further to do, so the coroutine
+        // will simply exit at that time).
+        CORO_YIELD async_write(*socket_, bufs, *this);
+    }
+}
+
+/// Call the DNS lookup provider.  (Expected to be called by the
+/// AsyncLookup<TCPServer> handler.)
+void
+TCPServer::asyncLookup() {
+    (*lookup_callback_)(*io_message_, query_message_,
+                        answer_message_, respbuf_, this);
+}
+
+/// Post this coroutine on the ASIO service queue so that it will
+/// resume processing where it left off.  The 'done' parameter indicates
+/// whether there is an answer to return to the client.
+void
+TCPServer::resume(const bool done) {
+    done_ = done;
+    io_.post(*this);
+}
+
+} // namespace asiolink
+
diff --git a/src/lib/asiolink/tcp_server.h b/src/lib/asiolink/tcp_server.h
new file mode 100644
index 0000000..fae9fda
--- /dev/null
+++ b/src/lib/asiolink/tcp_server.h
@@ -0,0 +1,119 @@
+// 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 __TCP_SERVER_H
+#define __TCP_SERVER_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <asiolink/asiolink.h>
+#include <asiolink/coroutine.h>
+
+
+namespace asiolink {
+
+/// \brief A TCP-specific \c DNSServer object.
+///
+/// This class inherits from both \c DNSServer and from \c coroutine,
+/// defined in coroutine.h. 
+class TCPServer : public virtual DNSServer, public virtual coroutine {
+public:
+    explicit TCPServer(asio::io_service& io_service,
+                       const asio::ip::address& addr, const uint16_t port, 
+                       const SimpleCallback* checkin = NULL,
+                       const DNSLookup* lookup = NULL,
+                       const DNSAnswer* answer = NULL);
+
+    void operator()(asio::error_code ec = asio::error_code(),
+                    size_t length = 0);
+    void asyncLookup();
+    void resume(const bool done);
+    bool hasAnswer() { return (done_); }
+    int value() { return (get_value()); }
+
+    DNSServer* clone() {
+        TCPServer* s = new TCPServer(*this);
+        return (s);
+    }
+
+private:
+    enum { MAX_LENGTH = 65535 };
+    static const size_t TCP_MESSAGE_LENGTHSIZE = 2;
+
+    // The ASIO service object
+    asio::io_service& io_;
+
+    // Class member variables which are dynamic, and changes to which
+    // need to accessible from both sides of a coroutine fork or from
+    // outside of the coroutine (i.e., from an asynchronous I/O call),
+    // should be declared here as pointers and allocated in the
+    // constructor or in the coroutine.  This allows state information
+    // to persist when an individual copy of the coroutine falls out
+    // scope while waiting for an event, *so long as* there is another
+    // object that is referencing the same data.  As a side-benefit, using
+    // pointers also reduces copy overhead for coroutine objects.
+    //
+    // Note: Currently these objects are allocated by "new" in the
+    // constructor, or in the function operator while processing a query.
+    // Repeated allocations from the heap for every incoming query is
+    // clearly a performance issue; this must be optimized in the future.
+    // The plan is to have a structure pre-allocate several "server state"
+    // objects which can be pulled off a free list and placed on an in-use
+    // list whenever a query comes in.  This will serve the dual purpose
+    // of improving performance and guaranteeing that state information
+    // will *not* be destroyed when any one instance of the coroutine
+    // falls out of scope while waiting for an event.
+    //
+    // An ASIO acceptor object to handle new connections.  Created in
+    // the constructor.
+    boost::shared_ptr<asio::ip::tcp::acceptor> acceptor_;
+
+    // Socket used to for listen for queries.  Created in the
+    // constructor and stored in a shared_ptr because socket objects
+    // are not copyable.
+    boost::shared_ptr<asio::ip::tcp::socket> socket_;
+
+    // The buffer into which the response is written
+    boost::shared_ptr<isc::dns::OutputBuffer> respbuf_;
+
+    // \c IOMessage and \c Message objects to be passed to the
+    // DNS lookup and answer providers
+    boost::shared_ptr<asiolink::IOMessage> io_message_;
+    isc::dns::MessagePtr query_message_;
+    isc::dns::MessagePtr answer_message_;
+
+    // The buffer into which the query packet is written
+    boost::shared_array<char>data_;
+
+    // State information that is entirely internal to a given instance
+    // of the coroutine can be declared here.
+    size_t bytes_;
+    bool done_;
+
+    // Callback functions provided by the caller
+    const SimpleCallback* checkin_callback_;
+    const DNSLookup* lookup_callback_;
+    const DNSAnswer* answer_callback_;
+
+    boost::shared_ptr<IOEndpoint> peer_;
+    boost::shared_ptr<IOSocket> iosock_;
+};
+
+}      // namespace asiolink
+#endif // __TCP_SERVER_H
diff --git a/src/lib/asiolink/tcp_socket.h b/src/lib/asiolink/tcp_socket.h
new file mode 100644
index 0000000..ef4f9f3
--- /dev/null
+++ b/src/lib/asiolink/tcp_socket.h
@@ -0,0 +1,52 @@
+// 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 __TCP_SOCKET_H
+#define __TCP_SOCKET_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <asiolink/iosocket.h>
+
+namespace asiolink {
+
+/// \brief The \c TCPSocket class is a concrete derived class of
+/// \c IOSocket that represents a TCP socket.
+///
+/// In the current implementation, an object of this class is always
+/// instantiated within the wrapper routines.  Applications are expected to
+/// get access to the object via the abstract base class, \c IOSocket.
+/// This design may be changed when we generalize the wrapper interface.
+class TCPSocket : public IOSocket {
+private:
+    TCPSocket(const TCPSocket& source);
+    TCPSocket& operator=(const TCPSocket& source);
+public:
+    /// \brief Constructor from an ASIO TCP socket.
+    ///
+    /// \param socket The ASIO representation of the TCP socket.
+    TCPSocket(asio::ip::tcp::socket& socket) : socket_(socket) {}
+
+    int getNative() const { return (socket_.native()); }
+    int getProtocol() const { return (IPPROTO_TCP); }
+
+private:
+    asio::ip::tcp::socket& socket_;
+};
+
+
+}      // namespace asiolink
+#endif // __TCP_SOCKET_H
diff --git a/src/lib/asiolink/tcpdns.cc b/src/lib/asiolink/tcpdns.cc
deleted file mode 100644
index c00b87a..0000000
--- a/src/lib/asiolink/tcpdns.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-// 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 <config.h>
-
-#include <unistd.h>             // for some IPC/network system calls
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include <asio.hpp>
-#include <asio/ip/address.hpp>
-
-#include <boost/array.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <dns/buffer.h>
-#include <dns/message.h>
-
-#include <asiolink.h>
-#include <internal/coroutine.h>
-#include <internal/tcpdns.h>
-
-using namespace asio;
-using asio::ip::udp;
-using asio::ip::tcp;
-
-using namespace std;
-using namespace isc::dns;
-
-namespace asiolink {
-/// The following functions implement the \c UDPServer class.
-///
-/// The constructor
-TCPServer::TCPServer(io_service& io_service,
-                     const ip::address& addr, const uint16_t port, 
-                     const SimpleCallback* checkin,
-                     const DNSLookup* lookup,
-                     const DNSAnswer* answer) :
-    io_(io_service), done_(false),
-    checkin_callback_(checkin), lookup_callback_(lookup),
-    answer_callback_(answer)
-{
-    tcp::endpoint endpoint(addr, port);
-    acceptor_.reset(new tcp::acceptor(io_service));
-    acceptor_->open(endpoint.protocol());
-    // Set v6-only (we use a separate instantiation for v4,
-    // otherwise asio will bind to both v4 and v6
-    if (addr.is_v6()) {
-        acceptor_->set_option(ip::v6_only(true));
-    }
-    acceptor_->set_option(tcp::acceptor::reuse_address(true));
-    acceptor_->bind(endpoint);
-    acceptor_->listen();
-}
-
-void
-TCPServer::operator()(error_code ec, size_t length) {
-    /// Because the coroutine reeentry block is implemented as
-    /// a switch statement, inline variable declarations are not
-    /// permitted.  Certain variables used below can be declared here.
-    boost::array<const_buffer,2> bufs;
-    OutputBuffer lenbuf(TCP_MESSAGE_LENGTHSIZE);
-
-    CORO_REENTER (this) {
-        do {
-            /// Create a socket to listen for connections
-            socket_.reset(new tcp::socket(acceptor_->get_io_service()));
-
-            /// Wait for new connections. In the event of error,
-            /// try again
-            do {
-                CORO_YIELD acceptor_->async_accept(*socket_, *this);
-            } while (!ec);
-
-            /// Fork the coroutine by creating a copy of this one and
-            /// scheduling it on the ASIO service queue.  The parent
-            /// will continue listening for DNS connections while the
-            /// handles the one that has just arrived.
-            CORO_FORK io_.post(TCPServer(*this));
-        } while (is_parent());
-
-        /// Instantiate the data buffer that will be used by the
-        /// asynchronous read call.
-        data_.reset(new char[MAX_LENGTH]);
-
-        /// Read the message, in two parts.  First, the message length:
-        CORO_YIELD async_read(*socket_, asio::buffer(data_.get(),
-                              TCP_MESSAGE_LENGTHSIZE), *this);
-        if (ec) {
-            CORO_YIELD return;
-        }
-
-        /// Now read the message itself. (This is done in a different scope
-        /// to allow inline variable declarations.)
-        CORO_YIELD {
-            InputBuffer dnsbuffer((const void *) data_.get(), length);
-            uint16_t msglen = dnsbuffer.readUint16();
-            async_read(*socket_, asio::buffer(data_.get(), msglen), *this);
-        }
-
-        if (ec) {
-            CORO_YIELD return;
-        }
-
-        // Create an \c IOMessage object to store the query.
-        //
-        // (XXX: It would be good to write a factory function
-        // that would quickly generate an IOMessage object without
-        // all these calls to "new".)
-        peer_.reset(new TCPEndpoint(socket_->remote_endpoint()));
-        iosock_.reset(new TCPSocket(*socket_));
-        io_message_.reset(new IOMessage(data_.get(), length, *iosock_, *peer_));
-        bytes_ = length;
-
-        // Perform any necessary operations prior to processing the incoming
-        // packet (e.g., checking for queued configuration messages).
-        //
-        // (XXX: it may be a performance issue to have this called for
-        // every single incoming packet; we may wish to throttle it somehow
-        // in the future.)
-        if (checkin_callback_ != NULL) {
-            (*checkin_callback_)(*io_message_);
-        }
-
-        // If we don't have a DNS Lookup provider, there's no point in
-        // continuing; we exit the coroutine permanently.
-        if (lookup_callback_ == NULL) {
-            CORO_YIELD return;
-        }
-
-        // Reset or instantiate objects that will be needed by the
-        // DNS lookup and the write call.
-        respbuf_.reset(new OutputBuffer(0));
-        query_message_.reset(new Message(Message::PARSE));
-        answer_message_.reset(new Message(Message::RENDER));
-
-        // Schedule a DNS lookup, and yield.  When the lookup is
-        // finished, the coroutine will resume immediately after
-        // this point.
-        CORO_YIELD io_.post(AsyncLookup<TCPServer>(*this));
-
-        // The 'done_' flag indicates whether we have an answer
-        // to send back.  If not, exit the coroutine permanently.
-        if (!done_) {
-            CORO_YIELD return;
-        }
-
-        // Call the DNS answer provider to render the answer into
-        // wire format
-        (*answer_callback_)(*io_message_, query_message_,
-                            answer_message_, respbuf_);
-
-        // Set up the response, beginning with two length bytes.
-        lenbuf.writeUint16(respbuf_->getLength());
-        bufs[0] = buffer(lenbuf.getData(), lenbuf.getLength());
-        bufs[1] = buffer(respbuf_->getData(), respbuf_->getLength());
-
-        // Begin an asynchronous send, and then yield.  When the
-        // send completes, we will resume immediately after this point
-        // (though we have nothing further to do, so the coroutine
-        // will simply exit at that time).
-        CORO_YIELD async_write(*socket_, bufs, *this);
-    }
-}
-
-/// Call the DNS lookup provider.  (Expected to be called by the
-/// AsyncLookup<TCPServer> handler.)
-void
-TCPServer::asyncLookup() {
-    (*lookup_callback_)(*io_message_, query_message_,
-                        answer_message_, respbuf_, this);
-}
-
-/// Post this coroutine on the ASIO service queue so that it will
-/// resume processing where it left off.  The 'done' parameter indicates
-/// whether there is an answer to return to the client.
-void
-TCPServer::resume(const bool done) {
-    done_ = done;
-    io_.post(*this);
-}
-
-}
diff --git a/src/lib/asiolink/udp_endpoint.h b/src/lib/asiolink/udp_endpoint.h
new file mode 100644
index 0000000..16ee686
--- /dev/null
+++ b/src/lib/asiolink/udp_endpoint.h
@@ -0,0 +1,89 @@
+// 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 __UDP_ENDPOINT_H
+#define __UDP_ENDPOINT_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <asiolink/ioendpoint.h>
+
+namespace asiolink {
+
+/// \brief The \c UDPEndpoint class is a concrete derived class of
+/// \c IOEndpoint that represents an endpoint of a UDP packet.
+///
+/// Other notes about \c TCPEndpoint applies to this class, too.
+class UDPEndpoint : public IOEndpoint {
+public:
+    ///
+    /// \name Constructors and Destructor.
+    ///
+    //@{
+    /// \brief Constructor from a pair of address and port.
+    ///
+    /// \param address The IP address of the endpoint.
+    /// \param port The UDP port number of the endpoint.
+    UDPEndpoint(const IOAddress& address, const unsigned short port) :
+        asio_endpoint_placeholder_(
+            new asio::ip::udp::endpoint(asio::ip::address::from_string(address.toText()),
+                              port)),
+        asio_endpoint_(*asio_endpoint_placeholder_)
+    {}
+
+    /// \brief Constructor from an ASIO UDP endpoint.
+    ///
+    /// This constructor is designed to be an efficient wrapper for the
+    /// corresponding ASIO class, \c udp::endpoint.
+    ///
+    /// \param asio_endpoint The ASIO representation of the UDP endpoint.
+    UDPEndpoint(const asio::ip::udp::endpoint& asio_endpoint) :
+        asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint)
+    {}
+
+    /// \brief The destructor.
+    ~UDPEndpoint() { delete asio_endpoint_placeholder_; }
+    //@}
+
+    inline IOAddress getAddress() const {
+        return (asio_endpoint_.address());
+    }
+
+    inline uint16_t getPort() const {
+        return (asio_endpoint_.port());
+    }
+
+    inline short getProtocol() const {
+        return (asio_endpoint_.protocol().protocol());
+    }
+
+    inline short getFamily() const {
+        return (asio_endpoint_.protocol().family());
+    }
+
+    // This is not part of the exosed IOEndpoint API but allows
+    // direct access to the ASIO implementation of the endpoint
+    inline const asio::ip::udp::endpoint& getASIOEndpoint() const {
+        return (asio_endpoint_);
+    }
+
+private:
+    const asio::ip::udp::endpoint* asio_endpoint_placeholder_;
+    const asio::ip::udp::endpoint& asio_endpoint_;
+};
+
+}      // namespace asiolink
+#endif // __UDP_ENDPOINT_H
diff --git a/src/lib/asiolink/udp_query.h b/src/lib/asiolink/udp_query.h
new file mode 100644
index 0000000..81ef554
--- /dev/null
+++ b/src/lib/asiolink/udp_query.h
@@ -0,0 +1,88 @@
+// 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 __UDP_QUERY_H
+#define __UDP_QUERY_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <dns/buffer.h>
+
+#include <asiolink/ioaddress.h>
+#include <asiolink/coroutine.h>
+
+namespace asiolink {
+
+//
+// Asynchronous UDP coroutine for upstream queries
+//
+class UDPQuery : public coroutine {
+public:
+    // TODO Maybe this should be more generic than just for UDPQuery?
+    ///
+    /// \brief Result of the query
+    ///
+    /// This is related only to contacting the remote server. If the answer
+    ///indicates error, it is still counted as SUCCESS here, if it comes back.
+    ///
+    enum Result {
+        SUCCESS,
+        TIME_OUT,
+        STOPPED
+    };
+    /// Abstract callback for the UDPQuery.
+    class Callback {
+    public:
+        virtual ~Callback() {}
+
+        /// This will be called when the UDPQuery is completed
+        virtual void operator()(Result result) = 0;
+    };
+    ///
+    /// \brief Constructor.
+    ///
+    /// It creates the query.
+    /// @param callback will be called when we terminate. It is your task to
+    ///        delete it if allocated on heap.
+    ///@param timeout in ms.
+    ///
+    explicit UDPQuery(asio::io_service& io_service,
+                      const isc::dns::Question& q,
+                      const IOAddress& addr, uint16_t port,
+                      isc::dns::OutputBufferPtr buffer,
+                      Callback* callback, int timeout = -1);
+    void operator()(asio::error_code ec = asio::error_code(),
+                    size_t length = 0);
+    /// Terminate the query.
+    void stop(Result reason = STOPPED);
+private:
+    enum { MAX_LENGTH = 4096 };
+
+    ///
+    /// \short Private data
+    ///
+    /// They are not private because of stability of the
+    /// interface (this is private class anyway), but because this class
+    /// will be copyed often (it is used as a coroutine and passed as callback
+    /// to many async_*() functions) and we want keep the same data. Some of
+    /// the data is not copyable too.
+    ///
+    struct PrivateData;
+    boost::shared_ptr<PrivateData> data_;
+};
+
+}      // namespace asiolink
+#endif // __UDP_QUERY_H
diff --git a/src/lib/asiolink/udp_server.h b/src/lib/asiolink/udp_server.h
new file mode 100644
index 0000000..a6ae32b
--- /dev/null
+++ b/src/lib/asiolink/udp_server.h
@@ -0,0 +1,102 @@
+// 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 __UDP_SERVER_H
+#define __UDP_SERVER_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <asiolink/dns_server.h>
+#include <asiolink/simple_callback.h>
+#include <asiolink/dns_lookup.h>
+#include <asiolink/dns_answer.h>
+
+#include <asiolink/coroutine.h>
+
+namespace asiolink {
+
+//
+// Asynchronous UDP server coroutine
+//
+///
+/// \brief This class implements the coroutine to handle UDP
+///        DNS query event. As such, it is both a \c DNSServer and
+///        a \c coroutine
+///
+class UDPServer : public virtual DNSServer, public virtual coroutine {
+public:
+    /// \brief Constructor
+    /// \param io_service the asio::io_service to work with
+    /// \param addr the IP address to listen for queries on
+    /// \param port the port to listen for queries on
+    /// \param checkin the callbackprovider for non-DNS events
+    /// \param lookup the callbackprovider for DNS lookup events
+    /// \param answer the callbackprovider for DNS answer events
+    explicit UDPServer(asio::io_service& io_service,
+                       const asio::ip::address& addr, const uint16_t port,
+                       SimpleCallback* checkin = NULL,
+                       DNSLookup* lookup = NULL,
+                       DNSAnswer* answer = NULL);
+
+    /// \brief The function operator
+    void operator()(asio::error_code ec = asio::error_code(),
+                    size_t length = 0);
+
+    /// \brief Calls the lookup callback
+    void asyncLookup();
+
+    /// \brief Resume operation
+    ///
+    /// \param done Set this to true if the lookup action is done and
+    ///        we have an answer
+    void resume(const bool done);
+
+    /// \brief Check if we have an answer
+    ///
+    /// \return true if we have an answer
+    bool hasAnswer();
+
+    /// \brief Returns the coroutine state value
+    ///
+    /// \return the coroutine state value
+    int value() { return (get_value()); }
+
+    /// \brief Clones the object
+    ///
+    /// \return a newly allocated copy of this object
+    DNSServer* clone() {
+        UDPServer* s = new UDPServer(*this);
+        return (s);
+    }
+
+private:
+    enum { MAX_LENGTH = 4096 };
+
+    /**
+     * \brief Internal state and data.
+     *
+     * We use the pimple design pattern, but not because we need to hide
+     * internal data. This class and whole header is for private use anyway.
+     * It turned out that UDPServer is copied a lot, because it is a coroutine.
+     * This way the overhead of copying is lower, we copy only one shared
+     * pointer instead of about 10 of them.
+     */
+    class Data;
+    boost::shared_ptr<Data> data_;
+};
+
+}      // namespace asiolink
+#endif // __UDP_SERVER_H
diff --git a/src/lib/asiolink/udp_socket.h b/src/lib/asiolink/udp_socket.h
new file mode 100644
index 0000000..253c42b
--- /dev/null
+++ b/src/lib/asiolink/udp_socket.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 __UDP_SOCKET_H
+#define __UDP_SOCKET_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <asiolink/iosocket.h>
+
+namespace asiolink {
+
+/// \brief The \c UDPSocket class is a concrete derived class of
+/// \c IOSocket that represents a UDP socket.
+///
+/// Other notes about \c TCPSocket applies to this class, too.
+class UDPSocket : public IOSocket {
+private:
+    UDPSocket(const UDPSocket& source);
+    UDPSocket& operator=(const UDPSocket& source);
+public:
+    /// \brief Constructor from an ASIO UDP socket.
+    ///
+    /// \param socket The ASIO representation of the UDP socket.
+    UDPSocket(asio::ip::udp::socket& socket) : socket_(socket) {}
+
+    virtual int getNative() const { return (socket_.native()); }
+    virtual int getProtocol() const { return (IPPROTO_UDP); }
+
+private:
+    asio::ip::udp::socket& socket_;
+};
+
+}      // namespace asiolink
+#endif // __UDP_SOCKET_H
diff --git a/src/lib/asiolink/udpdns.cc b/src/lib/asiolink/udpdns.cc
deleted file mode 100644
index 83f7b3c..0000000
--- a/src/lib/asiolink/udpdns.cc
+++ /dev/null
@@ -1,432 +0,0 @@
-// 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 <config.h>
-
-#include <unistd.h>             // for some IPC/network system calls
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include <boost/bind.hpp>
-
-#include <asio.hpp>
-#include <asio/deadline_timer.hpp>
-
-#include <memory>
-#include <boost/shared_ptr.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <dns/buffer.h>
-#include <dns/message.h>
-#include <dns/messagerenderer.h>
-#include <log/dummylog.h>
-#include <dns/opcode.h>
-#include <dns/rcode.h>
-
-#include <asiolink.h>
-#include <internal/coroutine.h>
-#include <internal/udpdns.h>
-
-using namespace asio;
-using asio::ip::udp;
-using asio::ip::tcp;
-using isc::log::dlog;
-
-using namespace std;
-using namespace isc::dns;
-
-namespace asiolink {
-
-/*
- * Some of the member variables here are shared_ptrs and some are
- * auto_ptrs. There will be one instance of Data for the lifetime
- * of packet. The variables that are state only for a single packet
- * use auto_ptr, as it is more lightweight. In the case of shared
- * configuration (eg. the callbacks, socket), we use shared_ptrs.
- */
-struct UDPServer::Data {
-    /*
-     * Constructor from parameters passed to UDPServer constructor.
-     * This instance will not be used to retrieve and answer the actual
-     * query, it will only hold parameters until we wait for the
-     * first packet. But we do initialize the socket in here.
-     */
-    Data(io_service& io_service, const ip::address& addr, const uint16_t port,
-        SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) :
-        io_(io_service), done_(false), checkin_callback_(checkin),
-        lookup_callback_(lookup), answer_callback_(answer)
-    {
-        // We must use different instantiations for v4 and v6;
-        // otherwise ASIO will bind to both
-        udp proto = addr.is_v4() ? udp::v4() : udp::v6();
-        socket_.reset(new udp::socket(io_service, proto));
-        socket_->set_option(socket_base::reuse_address(true));
-        if (addr.is_v6()) {
-            socket_->set_option(asio::ip::v6_only(true));
-        }
-        socket_->bind(udp::endpoint(addr, port));
-    }
-
-    /*
-     * Copy constructor. Default one would probably do, but it is unnecessary
-     * to copy many of the member variables every time we fork to handle
-     * another packet.
-     *
-     * We also allocate data for receiving the packet here.
-     */
-    Data(const Data& other) :
-        io_(other.io_), socket_(other.socket_), done_(false),
-        checkin_callback_(other.checkin_callback_),
-        lookup_callback_(other.lookup_callback_),
-        answer_callback_(other.answer_callback_)
-    {
-        // Instantiate the data buffer and endpoint that will
-        // be used by the asynchronous receive call.
-        data_.reset(new char[MAX_LENGTH]);
-        sender_.reset(new udp::endpoint());
-    }
-
-    // The ASIO service object
-    asio::io_service& io_;
-
-    // Class member variables which are dynamic, and changes to which
-    // need to accessible from both sides of a coroutine fork or from
-    // outside of the coroutine (i.e., from an asynchronous I/O call),
-    // should be declared here as pointers and allocated in the
-    // constructor or in the coroutine.  This allows state information
-    // to persist when an individual copy of the coroutine falls out
-    // scope while waiting for an event, *so long as* there is another
-    // object that is referencing the same data.  As a side-benefit, using
-    // pointers also reduces copy overhead for coroutine objects.
-    //
-    // Note: Currently these objects are allocated by "new" in the
-    // constructor, or in the function operator while processing a query.
-    // Repeated allocations from the heap for every incoming query is
-    // clearly a performance issue; this must be optimized in the future.
-    // The plan is to have a structure pre-allocate several "Data"
-    // objects which can be pulled off a free list and placed on an in-use
-    // list whenever a query comes in.  This will serve the dual purpose
-    // of improving performance and guaranteeing that state information
-    // will *not* be destroyed when any one instance of the coroutine
-    // falls out of scope while waiting for an event.
-    //
-    // Socket used to for listen for queries.  Created in the
-    // constructor and stored in a shared_ptr because socket objects
-    // are not copyable.
-    boost::shared_ptr<asio::ip::udp::socket> socket_;
-
-    // The ASIO-internal endpoint object representing the client
-    std::auto_ptr<asio::ip::udp::endpoint> sender_;
-
-    // \c IOMessage and \c Message objects to be passed to the
-    // DNS lookup and answer providers
-    std::auto_ptr<asiolink::IOMessage> io_message_;
-
-    // The original query as sent by the client
-    isc::dns::MessagePtr query_message_;
-
-    // The response message we are building
-    isc::dns::MessagePtr answer_message_;
-
-    // The buffer into which the response is written
-    isc::dns::OutputBufferPtr respbuf_;
-
-    // The buffer into which the query packet is written
-    boost::shared_array<char> data_;
-
-    // State information that is entirely internal to a given instance
-    // of the coroutine can be declared here.
-    size_t bytes_;
-    bool done_;
-
-    // Callback functions provided by the caller
-    const SimpleCallback* checkin_callback_;
-    const DNSLookup* lookup_callback_;
-    const DNSAnswer* answer_callback_;
-
-    std::auto_ptr<IOEndpoint> peer_;
-    std::auto_ptr<IOSocket> iosock_;
-};
-
-/// The following functions implement the \c UDPServer class.
-///
-/// The constructor. It just creates new internal state object
-/// and lets it handle the initialization.
-UDPServer::UDPServer(io_service& io_service, const ip::address& addr,
-    const uint16_t port, SimpleCallback* checkin, DNSLookup* lookup,
-    DNSAnswer* answer) :
-    data_(new Data(io_service, addr, port, checkin, lookup, answer))
-{ }
-
-/// The function operator is implemented with the "stackless coroutine"
-/// pattern; see internal/coroutine.h for details.
-void
-UDPServer::operator()(error_code ec, size_t length) {
-    /// Because the coroutine reeentry block is implemented as
-    /// a switch statement, inline variable declarations are not
-    /// permitted.  Certain variables used below can be declared here.
-
-    CORO_REENTER (this) {
-        do {
-            /*
-             * This is preparation for receiving a packet. We get a new
-             * state object for the lifetime of the next packet to come.
-             * It allocates the buffers to receive data into.
-             */
-            data_.reset(new Data(*data_));
-
-            do {
-                // Begin an asynchronous receive, then yield.
-                // When the receive event is posted, the coroutine
-                // will resume immediately after this point.
-                CORO_YIELD data_->socket_->async_receive_from(
-                    buffer(data_->data_.get(), MAX_LENGTH), *data_->sender_,
-                    *this);
-            } while (ec || length == 0);
-
-            data_->bytes_ = length;
-
-            /*
-             * We fork the coroutine now. One (the child) will keep
-             * the current state and handle the packet, then die and
-             * drop ownership of the state. The other (parent) will just
-             * go into the loop again and replace the current state with
-             * a new one for a new object.
-             *
-             * Actually, both of the coroutines will be a copy of this
-             * one, but that's just internal implementation detail.
-             */
-            CORO_FORK data_->io_.post(UDPServer(*this));
-        } while (is_parent());
-
-        // Create an \c IOMessage object to store the query.
-        //
-        // (XXX: It would be good to write a factory function
-        // that would quickly generate an IOMessage object without
-        // all these calls to "new".)
-        data_->peer_.reset(new UDPEndpoint(*data_->sender_));
-        data_->iosock_.reset(new UDPSocket(*data_->socket_));
-        data_->io_message_.reset(new IOMessage(data_->data_.get(),
-            data_->bytes_, *data_->iosock_, *data_->peer_));
-
-        // Perform any necessary operations prior to processing an incoming
-        // query (e.g., checking for queued configuration messages).
-        //
-        // (XXX: it may be a performance issue to check in for every single
-        // incoming query; we may wish to throttle this in the future.)
-        if (data_->checkin_callback_ != NULL) {
-            (*data_->checkin_callback_)(*data_->io_message_);
-        }
-
-        // If we don't have a DNS Lookup provider, there's no point in
-        // continuing; we exit the coroutine permanently.
-        if (data_->lookup_callback_ == NULL) {
-            CORO_YIELD return;
-        }
-
-        // Instantiate objects that will be needed by the
-        // asynchronous DNS lookup and/or by the send call.
-        data_->respbuf_.reset(new OutputBuffer(0));
-        data_->query_message_.reset(new Message(Message::PARSE));
-        data_->answer_message_.reset(new Message(Message::RENDER));
-
-        // Schedule a DNS lookup, and yield.  When the lookup is
-        // finished, the coroutine will resume immediately after
-        // this point.
-        CORO_YIELD data_->io_.post(AsyncLookup<UDPServer>(*this));
-
-        dlog("[XX] got an answer");
-
-        // The 'done_' flag indicates whether we have an answer
-        // to send back.  If not, exit the coroutine permanently.
-        if (!data_->done_) {
-            CORO_YIELD return;
-        }
-
-        // Call the DNS answer provider to render the answer into
-        // wire format
-        (*data_->answer_callback_)(*data_->io_message_, data_->query_message_,
-            data_->answer_message_, data_->respbuf_);
-
-        // Begin an asynchronous send, and then yield.  When the
-        // send completes, we will resume immediately after this point
-        // (though we have nothing further to do, so the coroutine
-        // will simply exit at that time).
-        CORO_YIELD data_->socket_->async_send_to(
-            buffer(data_->respbuf_->getData(), data_->respbuf_->getLength()),
-            *data_->sender_, *this);
-    }
-}
-
-/// Call the DNS lookup provider.  (Expected to be called by the
-/// AsyncLookup<UDPServer> handler.)
-void
-UDPServer::asyncLookup() {
-    (*data_->lookup_callback_)(*data_->io_message_,
-        data_->query_message_, data_->answer_message_, data_->respbuf_, this);
-}
-
-/// Post this coroutine on the ASIO service queue so that it will
-/// resume processing where it left off.  The 'done' parameter indicates
-/// whether there is an answer to return to the client.
-void
-UDPServer::resume(const bool done) {
-    data_->done_ = done;
-    data_->io_.post(*this);
-}
-
-bool
-UDPServer::hasAnswer() {
-    return (data_->done_);
-}
-
-// Private UDPQuery data (see internal/udpdns.h for reasons)
-struct UDPQuery::PrivateData {
-    // Socket we send query to and expect reply from there
-    udp::socket socket;
-    // Where was the query sent
-    udp::endpoint remote;
-    // What we ask the server
-    Question question;
-    // We will store the answer here
-    OutputBufferPtr buffer;
-    OutputBufferPtr msgbuf;
-    // Temporary buffer for answer
-    boost::shared_array<char> data;
-    // This will be called when the data arrive or timeouts
-    Callback* callback;
-    // Did we already stop operating (data arrived, we timed out, someone
-    // called stop). This can be so when we are cleaning up/there are
-    // still pointers to us.
-    bool stopped;
-    // Timer to measure timeouts.
-    deadline_timer timer;
-    // How many milliseconds are we willing to wait for answer?
-    int timeout;
-
-    PrivateData(io_service& service,
-        const udp::socket::protocol_type& protocol, const Question &q,
-        OutputBufferPtr b, Callback *c) :
-        socket(service, protocol),
-        question(q),
-        buffer(b),
-        msgbuf(new OutputBuffer(512)),
-        callback(c),
-        stopped(false),
-        timer(service)
-    { }
-};
-
-/// The following functions implement the \c UDPQuery class.
-///
-/// The constructor
-UDPQuery::UDPQuery(io_service& io_service,
-                   const Question& q, const IOAddress& addr, uint16_t port,
-                   OutputBufferPtr buffer, Callback *callback, int timeout) :
-    data_(new PrivateData(io_service,
-        addr.getFamily() == AF_INET ? udp::v4() : udp::v6(), q, buffer,
-        callback))
-{
-    data_->remote = UDPEndpoint(addr, port).getASIOEndpoint();
-    data_->timeout = timeout;
-}
-
-/// The function operator is implemented with the "stackless coroutine"
-/// pattern; see internal/coroutine.h for details.
-void
-UDPQuery::operator()(error_code ec, size_t length) {
-    if (ec || data_->stopped) {
-        return;
-    }
-
-    CORO_REENTER (this) {
-        /// Generate the upstream query and render it to wire format
-        /// This is done in a different scope to allow inline variable
-        /// declarations.
-        {
-            Message msg(Message::RENDER);
-            
-            // XXX: replace with boost::random or some other suitable PRNG
-            msg.setQid(0);
-            msg.setOpcode(Opcode::QUERY());
-            msg.setRcode(Rcode::NOERROR());
-            msg.setHeaderFlag(Message::HEADERFLAG_RD);
-            msg.addQuestion(data_->question);
-            MessageRenderer renderer(*data_->msgbuf);
-            msg.toWire(renderer);
-            dlog("Sending " + msg.toText() + " to " +
-                data_->remote.address().to_string());
-        }
-
-
-        // If we timeout, we stop, which will shutdown everything and
-        // cancel all other attempts to run inside the coroutine
-        if (data_->timeout != -1) {
-            data_->timer.expires_from_now(boost::posix_time::milliseconds(
-                data_->timeout));
-            data_->timer.async_wait(boost::bind(&UDPQuery::stop, *this,
-                TIME_OUT));
-        }
-
-        // Begin an asynchronous send, and then yield.  When the
-        // send completes, we will resume immediately after this point.
-        CORO_YIELD data_->socket.async_send_to(buffer(data_->msgbuf->getData(),
-            data_->msgbuf->getLength()), data_->remote, *this);
-
-        /// Allocate space for the response.  (XXX: This should be
-        /// optimized by maintaining a free list of pre-allocated blocks)
-        data_->data.reset(new char[MAX_LENGTH]);
-
-        /// Begin an asynchronous receive, and yield.  When the receive
-        /// completes, we will resume immediately after this point.
-        CORO_YIELD data_->socket.async_receive_from(buffer(data_->data.get(),
-            MAX_LENGTH), data_->remote, *this);
-        // The message is not rendered yet, so we can't print it easilly
-        dlog("Received response from " + data_->remote.address().to_string());
-
-        /// Copy the answer into the response buffer.  (XXX: If the
-        /// OutputBuffer object were made to meet the requirements of
-        /// a MutableBufferSequence, then it could be written to directly
-        /// by async_recieve_from() and this additional copy step would
-        /// be unnecessary.)
-        data_->buffer->writeData(data_->data.get(), length);
-
-        /// We are done
-        stop(SUCCESS);
-    }
-}
-
-void
-UDPQuery::stop(Result result) {
-    if (!data_->stopped) {
-        switch (result) {
-            case TIME_OUT:
-                dlog("Query timed out");
-                break;
-            case STOPPED:
-                dlog("Query stopped");
-                break;
-            default:;
-        }
-        data_->stopped = true;
-        data_->socket.cancel();
-        data_->socket.close();
-        data_->timer.cancel();
-        if (data_->callback) {
-            (*data_->callback)(result);
-        }
-    }
-}
-
-}




More information about the bind10-changes mailing list