[svn] commit: r3337 - in /branches/vorner-recursor-config/src/lib/asiolink: asiolink.cc asiolink.h tests/asiolink_unittest.cc

BIND 10 source code commits bind10-changes at lists.isc.org
Sat Oct 23 15:45:37 UTC 2010


Author: vorner
Date: Sat Oct 23 15:45:37 2010
New Revision: 3337

Log:
IOService can add and remove servers at runtime

However, it does not seem to close the sockets. It needs to be addressed
somehow and fixed (there's one disabled test because of that).

Modified:
    branches/vorner-recursor-config/src/lib/asiolink/asiolink.cc
    branches/vorner-recursor-config/src/lib/asiolink/asiolink.h
    branches/vorner-recursor-config/src/lib/asiolink/tests/asiolink_unittest.cc

Modified: branches/vorner-recursor-config/src/lib/asiolink/asiolink.cc
==============================================================================
--- branches/vorner-recursor-config/src/lib/asiolink/asiolink.cc (original)
+++ branches/vorner-recursor-config/src/lib/asiolink/asiolink.cc Sat Oct 23 15:45:37 2010
@@ -22,6 +22,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 
+#include <vector>
 #include <asio.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/bind.hpp>
@@ -54,10 +55,50 @@
 
     typedef boost::shared_ptr<UDPServer> UDPServerPtr;
     typedef boost::shared_ptr<TCPServer> TCPServerPtr;
-    UDPServerPtr udp4_server_;
-    UDPServerPtr udp6_server_;
-    TCPServerPtr tcp4_server_;
-    TCPServerPtr tcp6_server_;
+    typedef boost::shared_ptr<DNSServer> DNSServerPtr;
+    vector<DNSServerPtr> servers_;
+    SimpleCallback *checkin_;
+    DNSLookup *lookup_;
+    DNSAnswer *answer_;
+
+    void addServer(uint16_t port, const ip::address& address) {
+        try {
+            TCPServerPtr tcpServer(new TCPServer(io_service_, address, port,
+                checkin_, lookup_, answer_));
+            (*tcpServer)();
+            servers_.push_back(tcpServer);
+
+            UDPServerPtr udpServer(new UDPServer(io_service_, address, port,
+                checkin_, lookup_, answer_));
+            (*udpServer)();
+            servers_.push_back(udpServer);
+        }
+        catch (const asio::system_error& err) {
+            // We need to catch and convert any ASIO level exceptions.
+            // This can happen for unavailable address, binding a privilege port
+            // without the privilege, etc.
+            isc_throw(IOError, "Failed to initialize network servers: " <<
+                      err.what());
+        }
+    }
+    void addServer(const char& port, const ip::address& address) {
+        uint16_t portnum;
+        try {
+            // XXX: SunStudio with stlport4 doesn't reject some invalid
+            // representation such as "-1" by lexical_cast<uint16_t>, so
+            // we convert it into a signed integer of a larger size and perform
+            // range check ourselves.
+            const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
+            if (portnum32 < 0 || portnum32 > 65535) {
+                isc_throw(IOError, "Invalid port number '" << &port);
+            }
+            portnum = portnum32;
+        } catch (const boost::bad_lexical_cast& ex) {
+            isc_throw(IOError, "Invalid port number '" << &port << "': " <<
+                      ex.what());
+        }
+        addServer(portnum, address);
+    }
 };
 
 IOServiceImpl::IOServiceImpl(const char& port,
@@ -66,52 +107,16 @@
                              SimpleCallback* checkin,
                              DNSLookup* lookup,
                              DNSAnswer* answer) :
-    udp4_server_(UDPServerPtr()), udp6_server_(UDPServerPtr()),
-    tcp4_server_(TCPServerPtr()), tcp6_server_(TCPServerPtr())
-{
-    uint16_t portnum;
-    try {
-        // XXX: SunStudio with stlport4 doesn't reject some invalid
-        // representation such as "-1" by lexical_cast<uint16_t>, so
-        // we convert it into a signed integer of a larger size and perform
-        // range check ourselves.
-        const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
-        if (portnum32 < 0 || portnum32 > 65535) {
-            isc_throw(IOError, "Invalid port number '" << &port);
-        }
-        portnum = portnum32;
-    } catch (const boost::bad_lexical_cast& ex) {
-        isc_throw(IOError, "Invalid port number '" << &port << "': " <<
-                  ex.what());
-    }
-
-    try {
-        if (v4addr != NULL) {
-            udp4_server_ = UDPServerPtr(new UDPServer(io_service_,
-                                                      *v4addr, portnum,
-                                                      checkin, lookup, answer));
-            (*udp4_server_)();
-            tcp4_server_ = TCPServerPtr(new TCPServer(io_service_,
-                                                      *v4addr, portnum,
-                                                      checkin, lookup, answer));
-            (*tcp4_server_)();
-        }
-        if (v6addr != NULL) {
-            udp6_server_ = UDPServerPtr(new UDPServer(io_service_,
-                                                      *v6addr, portnum,
-                                                      checkin, lookup, answer));
-            (*udp6_server_)();
-            tcp6_server_ = TCPServerPtr(new TCPServer(io_service_,
-                                                      *v6addr, portnum,
-                                                      checkin, lookup, answer));
-            (*tcp6_server_)();
-        }
-    } catch (const asio::system_error& err) {
-        // We need to catch and convert any ASIO level exceptions.
-        // This can happen for unavailable address, binding a privilege port
-        // without the privilege, etc.
-        isc_throw(IOError, "Failed to initialize network servers: " <<
-                  err.what());
+    checkin_(checkin),
+    lookup_(lookup),
+    answer_(answer)
+{
+
+    if (v4addr) {
+        addServer(port, *v4addr);
+    }
+    if (v6addr) {
+        addServer(port, *v6addr);
     }
 }
 
@@ -119,19 +124,9 @@
                      SimpleCallback* checkin,
                      DNSLookup* lookup,
                      DNSAnswer* answer) :
-    impl_(NULL)
-{
-    error_code err;
-    const ip::address addr = ip::address::from_string(&address, err);
-    if (err) {
-        isc_throw(IOError, "Invalid IP address '" << &address << "': "
-                  << err.message());
-    }
-
-    impl_ = new IOServiceImpl(port,
-                              addr.is_v4() ? &addr : NULL,
-                              addr.is_v6() ? &addr : NULL,
-                              checkin, lookup, answer);
+    impl_(new IOServiceImpl(port, NULL, NULL, checkin, lookup, answer))
+{
+    addServer(port, &address);
 }
 
 IOService::IOService(const char& port,
@@ -148,8 +143,46 @@
     impl_ = new IOServiceImpl(port, v4addrp, v6addrp, checkin, lookup, answer);
 }
 
+IOService::IOService(SimpleCallback* checkin, DNSLookup* lookup,
+    DNSAnswer *answer) :
+    impl_(new IOServiceImpl(*"", NULL, NULL, checkin, lookup, answer))
+{
+}
+
 IOService::~IOService() {
     delete impl_;
+}
+
+namespace {
+
+ip::address
+convertAddr(const string& address) {
+    error_code err;
+    ip::address addr = ip::address::from_string(address, err);
+    if (err) {
+        isc_throw(IOError, "Invalid IP address '" << &address << "': "
+            << err.message());
+    }
+    return addr;
+}
+
+}
+
+void
+IOService::addServer(const char& port, const string& address) {
+    impl_->addServer(port, convertAddr(address));
+}
+
+void
+IOService::addServer(uint16_t port, const string &address) {
+    impl_->addServer(port, convertAddr(address));
+}
+
+void
+IOService::clearServers() {
+    // FIXME: This does not work, it does not close the socket.
+    // How is it done?
+    impl_->servers_.clear();
 }
 
 void

Modified: branches/vorner-recursor-config/src/lib/asiolink/asiolink.h
==============================================================================
--- branches/vorner-recursor-config/src/lib/asiolink/asiolink.h (original)
+++ branches/vorner-recursor-config/src/lib/asiolink/asiolink.h Sat Oct 23 15:45:37 2010
@@ -149,9 +149,19 @@
               SimpleCallback* checkin,
               DNSLookup* lookup,
               DNSAnswer* answer);
+    /// \brief The constructor without any servers.
+    ///
+    /// Use addServer() to add some servers.
+    IOService(SimpleCallback *checkin, DNSLookup* lookup, DNSAnswer *answer);
     /// \brief The destructor.
     ~IOService();
     //@}
+
+    /// \brief Add another server to the service
+    void addServer(uint16_t port, const std::string &address);
+    void addServer(const char &port, const std::string &address);
+    /// \brief Remove all servers from the service
+    void clearServers();
 
     /// \brief Start the underlying event loop.
     ///

Modified: branches/vorner-recursor-config/src/lib/asiolink/tests/asiolink_unittest.cc
==============================================================================
--- branches/vorner-recursor-config/src/lib/asiolink/tests/asiolink_unittest.cc (original)
+++ branches/vorner-recursor-config/src/lib/asiolink/tests/asiolink_unittest.cc Sat Oct 23 15:45:37 2010
@@ -341,10 +341,18 @@
                                     NULL, NULL);
     }
 
+    // Set up an IO Service queue without any addresses
+    void setIOService() {
+        delete io_service_;
+        io_service_ = NULL;
+        callback_ = new ASIOCallBack(this);
+        io_service_ = new IOService(callback_, NULL, NULL);
+    }
+
     // Run a simple server test, on either IPv4 or IPv6, and over either
     // UDP or TCP.  Calls the sendUDP() or sendTCP() methods, which will
     // start the IO Service queue.  The UDPServer or TCPServer that was
-    // created by setIOSerice() will receive the test packet and issue a
+    // created by setIOService() will receive the test packet and issue a
     // callback, which enables us to check that the data it received
     // matches what we sent.
     void doTest(const int family, const int protocol) {
@@ -515,6 +523,30 @@
     EXPECT_THROW(sendTCP(AF_INET6), IOError);
 }
 
+TEST_F(ASIOLinkTest, v6AddServer) {
+    setIOService();
+    io_service_->addServer(*TEST_SERVER_PORT, TEST_IPV6_ADDR);
+    doTest(AF_INET6, IPPROTO_TCP);
+
+    EXPECT_THROW(sendTCP(AF_INET), IOError);
+}
+
+TEST_F(ASIOLinkTest, v4AddServer) {
+    setIOService();
+    io_service_->addServer(*TEST_SERVER_PORT, TEST_IPV4_ADDR);
+    doTest(AF_INET, IPPROTO_TCP);
+
+    EXPECT_THROW(sendTCP(AF_INET6), IOError);
+}
+
+TEST_F(ASIOLinkTest, DISABLED_clearServers) {
+    // FIXME: Enable when clearServers actually close the sockets
+    io_service_->clearServers();
+
+    EXPECT_THROW(sendTCP(AF_INET), IOError);
+    EXPECT_THROW(sendTCP(AF_INET6), IOError);
+}
+
 TEST_F(ASIOLinkTest, v6TCPOnly) {
     // Open only IPv6 TCP socket.  A subsequent attempt of establishing an
     // IPv4/TCP connection should fail.  See above for why we only test this




More information about the bind10-changes mailing list