Browse Source

missing commit for r2198

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac221@2200 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 15 years ago
parent
commit
55291537c9
3 changed files with 290 additions and 38 deletions
  1. 68 25
      src/bin/auth/asio_link.cc
  2. 220 12
      src/bin/auth/asio_link.h
  3. 2 1
      src/bin/auth/auth_srv.cc

+ 68 - 25
src/bin/auth/asio_link.cc

@@ -38,35 +38,83 @@ using namespace std;
 using namespace isc::dns;
 using namespace isc::dns;
 
 
 namespace asio_link {
 namespace asio_link {
-IOAddress::IOAddress(const string& address_str) :
+IOAddress::IOAddress(const string& address_str)
     // XXX: we cannot simply construct the address in the initialization list
     // XXX: we cannot simply construct the address in the initialization list
     // because we'd like to throw our own exception on failure.
     // because we'd like to throw our own exception on failure.
-    asio_address_placeholder_(new ip::address()),
-    asio_address_(*asio_address_placeholder_)
 {
 {
     error_code err;
     error_code err;
-    const ip::address address = ip::address::from_string(address_str, err);
+    asio_address_ = ip::address::from_string(address_str, err);
     if (err) {
     if (err) {
-        delete asio_address_placeholder_;
         isc_throw(IOError, "Failed to convert string to address '"
         isc_throw(IOError, "Failed to convert string to address '"
                   << address_str << "': " << err.message());
                   << address_str << "': " << err.message());
     }
     }
-    *asio_address_placeholder_ = address;
 }
 }
 
 
 IOAddress::IOAddress(const ip::address& asio_address) :
 IOAddress::IOAddress(const ip::address& asio_address) :
-    asio_address_placeholder_(NULL), asio_address_(asio_address)
+    asio_address_(asio_address)
 {}
 {}
 
 
-IOAddress::~IOAddress() {
-    delete asio_address_placeholder_;
-}
-
 string
 string
 IOAddress::toText() const {
 IOAddress::toText() const {
     return (asio_address_.to_string());
     return (asio_address_.to_string());
 }
 }
 
 
+class TCPEndpoint : public IOEndpoint {
+public:
+    TCPEndpoint(const IOAddress& address, const unsigned short port) :
+        asio_endpoint_placeholder_(
+            new tcp::endpoint(ip::address::from_string(address.toText()),
+                              port)),
+        asio_endpoint_(*asio_endpoint_placeholder_)
+    {}
+    TCPEndpoint(const tcp::endpoint& asio_endpoint) :
+        asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint)
+    {}
+        
+    ~TCPEndpoint() { delete asio_endpoint_placeholder_; }
+    virtual IOAddress getAddress() const {
+        return (asio_endpoint_.address());
+    }
+private:
+    const tcp::endpoint* asio_endpoint_placeholder_;
+    const tcp::endpoint& asio_endpoint_;
+};
+
+class UDPEndpoint : public IOEndpoint {
+public:
+    UDPEndpoint(const IOAddress& address, const unsigned short port) :
+        asio_endpoint_placeholder_(
+            new udp::endpoint(ip::address::from_string(address.toText()),
+                              port)),
+        asio_endpoint_(*asio_endpoint_placeholder_)
+    {}
+    UDPEndpoint(const udp::endpoint& asio_endpoint) :
+        asio_endpoint_placeholder_(NULL), asio_endpoint_(asio_endpoint)
+    {}
+    ~UDPEndpoint() { delete asio_endpoint_placeholder_; }
+    virtual IOAddress getAddress() const {
+        return (asio_endpoint_.address());
+    }
+private:
+    const udp::endpoint* asio_endpoint_placeholder_;
+    const udp::endpoint& asio_endpoint_;
+};
+
+const IOEndpoint*
+IOEndpoint::createFromAddress(const int protocol,
+                              const IOAddress& address,
+                              const unsigned short port)
+{
+    if (protocol == IPPROTO_UDP) {
+        return (new UDPEndpoint(address, port));
+    } else if (protocol == IPPROTO_TCP) {
+        return (new TCPEndpoint(address, port));
+    }
+    isc_throw(IOError,
+              "IOEndpoint creation attempt for unsupported protocol: " <<
+              protocol);
+}
+
 class TCPSocket : public IOSocket {
 class TCPSocket : public IOSocket {
 private:
 private:
     TCPSocket(const TCPSocket& source);
     TCPSocket(const TCPSocket& source);
@@ -116,15 +164,9 @@ IOSocket::getDummyTCPSocket() {
 }
 }
 
 
 IOMessage::IOMessage(const void* data, const size_t data_size,
 IOMessage::IOMessage(const void* data, const size_t data_size,
-                     IOSocket& io_socket, const ip::address& remote_address) :
+                     IOSocket& io_socket, const IOEndpoint& remote_endpoint) :
     data_(data), data_size_(data_size), io_socket_(io_socket),
     data_(data), data_size_(data_size), io_socket_(io_socket),
-    remote_io_address_(remote_address)
-{}
-
-IOMessage::IOMessage(const void* data, const size_t data_size,
-                     IOSocket& io_socket, const string& remote_address) :
-    data_(data), data_size_(data_size), io_socket_(io_socket),
-    remote_io_address_(remote_address)
+    remote_endpoint_(remote_endpoint)
 {}
 {}
 
 
 //
 //
@@ -165,7 +207,6 @@ public:
 
 
             uint16_t msglen = dnsbuffer.readUint16();
             uint16_t msglen = dnsbuffer.readUint16();
             async_read(socket_, asio::buffer(data_, msglen),
             async_read(socket_, asio::buffer(data_, msglen),
-
                        boost::bind(&TCPClient::requestRead, this,
                        boost::bind(&TCPClient::requestRead, this,
                                    placeholders::error,
                                    placeholders::error,
                                    placeholders::bytes_transferred));
                                    placeholders::bytes_transferred));
@@ -178,8 +219,9 @@ public:
                      size_t bytes_transferred)
                      size_t bytes_transferred)
     {
     {
         if (!error) {
         if (!error) {
+            const TCPEndpoint remote_endpoint(socket_.remote_endpoint());
             const IOMessage io_message(data_, bytes_transferred, io_socket_,
             const IOMessage io_message(data_, bytes_transferred, io_socket_,
-                                       socket_.remote_endpoint().address());
+                                       remote_endpoint);
             // currently, for testing purpose only
             // currently, for testing purpose only
             if (custom_callback_ != NULL) {
             if (custom_callback_ != NULL) {
                 (*custom_callback_)(io_message);
                 (*custom_callback_)(io_message);
@@ -209,9 +251,9 @@ public:
         if (!error) {
         if (!error) {
                 async_write(socket_,
                 async_write(socket_,
                             asio::buffer(response_buffer_.getData(),
                             asio::buffer(response_buffer_.getData(),
-                                                response_buffer_.getLength()),
-                        boost::bind(&TCPClient::handleWrite, this,
-                                    placeholders::error));
+                                         response_buffer_.getLength()),
+                            boost::bind(&TCPClient::handleWrite, this,
+                                        placeholders::error));
         } else {
         } else {
             delete this;
             delete this;
         }
         }
@@ -337,8 +379,9 @@ public:
             auth_server_->configSession()->checkCommand();
             auth_server_->configSession()->checkCommand();
         }
         }
         if (!error && bytes_recvd > 0) {
         if (!error && bytes_recvd > 0) {
+            const UDPEndpoint remote_endpoint(sender_endpoint_);
             const IOMessage io_message(data_, bytes_recvd, io_socket_,
             const IOMessage io_message(data_, bytes_recvd, io_socket_,
-                                       sender_endpoint_.address());
+                                       remote_endpoint);
             // currently, for testing purpose only
             // currently, for testing purpose only
             if (custom_callback_ != NULL) {
             if (custom_callback_ != NULL) {
                 (*custom_callback_)(io_message);
                 (*custom_callback_)(io_message);

+ 220 - 12
src/bin/auth/asio_link.h

@@ -17,6 +17,10 @@
 #ifndef __ASIO_LINK_H
 #ifndef __ASIO_LINK_H
 #define __ASIO_LINK_H 1
 #define __ASIO_LINK_H 1
 
 
+// IMPORTANT NOTE: No ASIO header files can be included in this file.
+// See the description of the namespace below.
+#include <asio/ip/address.hpp>
+
 #include <functional>
 #include <functional>
 #include <string>
 #include <string>
 
 
@@ -33,6 +37,44 @@ class address;
 
 
 class AuthSrv;
 class AuthSrv;
 
 
+/// \namespace asio_link
+/// \brief A wrapper interface for the ASIO library.
+///
+/// The \c asio_link namespace is used to define a set of wrapper interfaces
+/// for the ASIO library.
+/// BIND 10 uses non Boost version of ASIO because it's header only, i.e.
+/// does not require a separate library object to be linked, and thus
+/// lowers the bar for introduction.
+/// But the advantage comes with its own costs: since the header only version
+/// includes more definitions in public header files, it tends to trigger
+/// more compiler warnings for our own sources, and, depending on the
+/// compiler options, may make the build fail.
+/// We also found it may be tricky to use ASIO and standard C++ libraries
+/// in a single translation unit, i.e., a .cc file: depending on the order
+/// of including header files ASIO may or may not work on some platforms.
+/// This wrapper interfaces are intended to centralize points of these
+/// problematic issues in a single sub module.  Other BIND 10 modules should
+/// simply include \c asio_link.h and use the wrapper APIs instead of
+/// including ASIO header files and using ASIO specific classes directly.
+///
+/// This wrapper may be used for other IO libraries if and when we want to
+/// switch, but generality for that purpose is not the primary goal of
+/// this module.  The resulting interfaces are thus straightforward mapping
+/// to the ASIO counterparts.
+///
+/// Note: currently the wrapper interface is specific to the authoritative
+/// server implementation.  But the plan is to generalize it and have
+/// other modules use it.
+///
+/// Note: One obvious drawback of this approach is performance overhead
+/// due to the additional layer.  We should eventually evaluate the cost
+/// of the wrapper abstraction in benchmark tests.
+///
+/// Another drawback is that the wrapper interfaces don't provide all features
+/// of ASIO (at least for the moment).  We should also re-evaluate the
+/// maintenance overhead of providing necessary wrappers as we develop
+/// more.
+
 namespace asio_link {
 namespace asio_link {
 struct IOServiceImpl;
 struct IOServiceImpl;
 
 
@@ -45,62 +87,228 @@ public:
         isc::Exception(file, line, what) {}
         isc::Exception(file, line, what) {}
 };
 };
 
 
+/// \brief The \c IOAddress class represents an IP addresses (version
+/// agnostic)
+///
+/// This class is a wrapper for the ASIO \c ip::address class.
 class IOAddress {
 class IOAddress {
-private:
-    IOAddress(const IOAddress& source);
-    IOAddress& operator=(const IOAddress& source);
 public:
 public:
-    IOAddress(const std::string& adress_str);
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// This class is copyable.  We use default versions of copy constructor
+    /// and the assignment operator.
+    /// We use the default destructor.
+    //@{
+    /// \brief Constructor from string.
+    ///
+    /// This constructor converts a textual representation of IPv4 and IPv6
+    /// addresses into an IOAddress object.
+    /// If \c address_str is not a valid representation of any type of
+    /// address, an exception of class \c IOError will be thrown.
+    /// This constructor allocates memory for the object, and if that fails
+    /// a corresponding standard exception will be thrown.
+    ///
+    /// \param address_str Textual representation of address.
+    IOAddress(const std::string& address_str);
+
+    /// \brief Constructor from an ASIO \c ip::address object.
+    ///
+    /// This constructor is intended to be used within the wrapper
+    /// implementation; user applications of the wrapper API won't use it.
+    ///
+    /// This constructor never throws an exception.
+    ///
+    /// \param asio_address The ASIO \c ip::address to be converted.
     IOAddress(const asio::ip::address& asio_adress);
     IOAddress(const asio::ip::address& asio_adress);
+    //@}
+
+    /// \brief Convert the address to a string.
+    ///
+    /// This method is basically expected to be exception free, but
+    /// generating the string will involve resource allocation,
+    /// and if it fails the corresponding standard exception will be thrown.
+    ///
+    /// \return A string representation of the address.
     std::string toText() const;
     std::string toText() const;
-    ~IOAddress();
 private:
 private:
-    asio::ip::address* asio_address_placeholder_;
-    const asio::ip::address& asio_address_;
+    asio::ip::address asio_address_;
 };
 };
 
 
+/// \brief DESCRIPTION
+class IOEndpoint {
+private:
+    IOEndpoint(const IOEndpoint& source);
+    IOEndpoint& operator=(const IOEndpoint& source);
+protected:
+    IOEndpoint() {}
+public:
+    virtual ~IOEndpoint() {}
+    virtual IOAddress getAddress() const = 0;
+    static const IOEndpoint* createFromAddress(int protocol,
+                                               const IOAddress& address,
+                                               unsigned short port);
+};
+
+/// \brief The \c IOSocket class is an abstract base class to represent
+/// various types of network sockets.
+///
+/// This class is a wrapper for the ASIO socket classes such as
+/// \c ip::tcp::socket and \c ip::udp::socket.
+///
+/// Derived class implementations are completely hidden with the
+/// implementation.  User applications only get access to concrete
+/// \c IOSocket objects via the abstract interfaces.
 class IOSocket {
 class IOSocket {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are
+    /// intentionally defined as private, making this class non-copyable.
+    //@{
 private:
 private:
     IOSocket(const IOSocket& source);
     IOSocket(const IOSocket& source);
     IOSocket& operator=(const IOSocket& source);
     IOSocket& operator=(const IOSocket& source);
 protected:
 protected:
+    /// \brief The default constructor.
+    ///
+    /// This is intentionally defined as \c protected as this base class
+    /// should never be instantiated (except as part of a derived class).
     IOSocket() {}
     IOSocket() {}
 public:
 public:
+    /// The destructor.
     virtual ~IOSocket() {}
     virtual ~IOSocket() {}
+    //@}
+
+    /// \brief Return the "native" representation of the socket.
+    ///
+    /// In practice, this is the file descriptor of the socket for
+    /// UNIX-like systems so the current implementation simply uses
+    /// \c int as the type of the return value.
+    /// We may have to need revisit this decision later.
+    ///
+    /// In general, the application should avoid using this method;
+    /// it essentially discloses an implementation specific "handle" that
+    /// can change the internal state of the socket (e.g. consider the
+    /// application closes it, for example).
+    /// But we sometimes need to perform very low-level operations that
+    /// requires the native representation.  Passing the file descriptor
+    /// to a different process is one example.
+    /// This method is provided as a necessary evil for such limited purposes.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \return The native representation of the socket.  This is the socket
+    /// file descriptor for UNIX-like systems.
     virtual int getNative() const = 0;
     virtual int getNative() const = 0;
+
+    /// \brief Return the transport protocol of the socket.
+    ///
+    /// Currently, it returns \c IPPROTO_UDP for UDP sockets, and
+    /// \c IPPROTO_TCP for TCP sockets.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \return IPPROTO_UDP for UDP sockets
+    /// \return IPPROTO_TCP for TCP sockets
     virtual int getProtocol() const = 0;
     virtual int getProtocol() const = 0;
+
+    /// \brief Return a non-usable "dummy" UDP socket for testing.
+    ///
+    /// This is a class method that returns a "mock" of UDP socket.
+    /// This is not associated with any actual socket, and its only
+    /// responsibility is to return \c IPPROTO_UDP from \c getProtocol().
+    /// The only feasible usage of this socket is for testing so that
+    /// the test code can prepare some "UDP data" even without opening any
+    /// actual socket.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \return A reference to an \c IOSocket object whose \c getProtocol()
+    /// returns \c IPPROTO_UDP.
     static IOSocket& getDummyUDPSocket();
     static IOSocket& getDummyUDPSocket();
+
+    /// \brief Return a non-usable "dummy" TCP socket for testing.
+    ///
+    /// See \c getDummyUDPSocket().  This method is its TCP version.
+    ///
+    /// \return A reference to an \c IOSocket object whose \c getProtocol()
+    /// returns \c IPPROTO_TCP.
     static IOSocket& getDummyTCPSocket();
     static IOSocket& getDummyTCPSocket();
 };
 };
 
 
+/// \brief The \c IOMessage class encapsulates a message exchanged via
+/// the ASIO module.
+///
+/// An \c IOMessage object represents a tuple of a chunk of data
+/// (a UDP packet or some segment of TCP stream), the socket over which the
+/// data is passed, the information about the other end point of the
+/// communication, and perhaps more.
+///
+/// The current design and interfaces of this class is tentative.
+/// It only provides a minimal level of support that is necessary for
+/// the current implementation of the authoritative server.
+/// A future version of this class will definitely support more
+/// Also, it may not be efficient, involving avoidable copies for example.
+/// This should be revisited in the near future, too.
+/// (e.g., we'll need a notion of "endpoint", both for generality and for
+/// efficiency).
 class IOMessage {
 class IOMessage {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are
+    /// intentionally defined as private, making this class non-copyable.
+    //@{
 private:
 private:
     IOMessage(const IOMessage& source);
     IOMessage(const IOMessage& source);
     IOMessage& operator=(const IOMessage& source);
     IOMessage& operator=(const IOMessage& source);
 public:
 public:
+    /// \brief Constructor from message information.
+    ///
+    /// This constructor needs to handle the ASIO \c ip::address class,
+    /// and is intended to be used within this wrapper implementation.
+    /// Once the \c IOMessage object is created, the application can
+    /// get access to the information via the wrapper interface such as
+    /// \c getRemoteAddress().
+    ///
+    /// This constructor never throws an exception.
+    ///
+    /// \param data A pointer to the message data.
+    /// \param data_size The size of the message data in bytes.
+    /// \param io_socket The socket over which the data is given.
+    /// \param remote_endpoint An ASIO address object represents the other
+    /// endpoint of the socket.
     IOMessage(const void* data, size_t data_size, IOSocket& io_socket,
     IOMessage(const void* data, size_t data_size, IOSocket& io_socket,
-              const asio::ip::address& remote_address);
-    IOMessage(const void* data, size_t data_size, IOSocket& io_socket,
-              const std::string& remote_address);
+              const IOEndpoint& remote_endpoint);
+    //@}
     const void* getData() const { return (data_); }
     const void* getData() const { return (data_); }
     size_t getDataSize() const { return (data_size_); }
     size_t getDataSize() const { return (data_size_); }
     const IOSocket& getSocket() const { return (io_socket_); }
     const IOSocket& getSocket() const { return (io_socket_); }
-    const IOAddress& getRemoteAddress() const { return (remote_io_address_); }
+    const IOEndpoint& getRemoteEndpoint() const { return (remote_endpoint_); }
 private:
 private:
     const void* data_;
     const void* data_;
     const size_t data_size_;
     const size_t data_size_;
     IOSocket& io_socket_;
     IOSocket& io_socket_;
-    IOAddress remote_io_address_;
+    const IOEndpoint& remote_endpoint_;
 };
 };
 
 
 class IOService {
 class IOService {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are
+    /// intentionally defined as private, making this class non-copyable.
+    //@{
 private:
 private:
     IOService(const IOService& source);
     IOService(const IOService& source);
     IOService& operator=(const IOService& source);
     IOService& operator=(const IOService& source);
 public:
 public:
     IOService(AuthSrv* auth_server, const char* port, bool use_ipv4,
     IOService(AuthSrv* auth_server, const char* port, bool use_ipv4,
               bool use_ipv6);
               bool use_ipv6);
+    /// \brief The destructor.
     ~IOService();
     ~IOService();
+    //@}
     void run();
     void run();
     void stop();
     void stop();
     asio::io_service& get_io_service();
     asio::io_service& get_io_service();

+ 2 - 1
src/bin/auth/auth_srv.cc

@@ -349,7 +349,8 @@ AuthSrvImpl::processIxfrQuery(const IOMessage& io_message,
     tmp_session_with_xfr.establish();
     tmp_session_with_xfr.establish();
 
 
     // XXX: the following is super expensive.
     // XXX: the following is super expensive.
-    const string remote_ip_address = io_message.getRemoteAddress().toText();
+    const string remote_ip_address =
+        io_message.getRemoteEndpoint().getAddress().toText();
     ElementPtr notify_command = Element::createFromString(
     ElementPtr notify_command = Element::createFromString(
         "{\"command\": [\"notify\", {\"zone_name\" : \"" +
         "{\"command\": [\"notify\", {\"zone_name\" : \"" +
         question->getName().toText() + "\", \"master_ip\" : \"" +
         question->getName().toText() + "\", \"master_ip\" : \"" +