Browse Source

[805] Basic support to install sockcreator sockets

* They are requested and installed, instead of binding them locally
* Documentation needs update
* It'll fail in practice, since the requestor isn't initialized from
  auth and resolver.
* It needs to set the correct IPv6 flag
Michal 'vorner' Vaner 13 years ago
parent
commit
cec38f4ec0

+ 31 - 1
src/lib/server_common/portconfig.cc

@@ -14,6 +14,7 @@
 
 #include <server_common/portconfig.h>
 #include <server_common/logger.h>
+#include <server_common/socket_request.h>
 
 #include <asiolink/io_address.h>
 #include <asiodns/dns_service.h>
@@ -30,6 +31,11 @@ namespace isc {
 namespace server_common {
 namespace portconfig {
 
+// This flags disables pushing the sockets to the DNSService. It prevents
+// the clearServers() method to close the file descriptors we made up.
+// It is not presented in any header, but we use it from the tests anyway.
+bool test_mode(false);
+
 AddressList
 parseAddresses(isc::data::ConstElementPtr addresses,
                const std::string& elemName)
@@ -76,11 +82,35 @@ parseAddresses(isc::data::ConstElementPtr addresses,
 
 namespace {
 
+vector<string> current_sockets;
+
 void
 setAddresses(DNSService& service, const AddressList& addresses) {
     service.clearServers();
+    BOOST_FOREACH(const string& token, current_sockets) {
+        socketRequestor().releaseSocket(token);
+    }
+    current_sockets.clear();
     BOOST_FOREACH(const AddressPair &address, addresses) {
-        service.addServer(address.second, address.first);
+        // TODO: Support sharing somehow in future.
+        const SocketRequestor::SocketID
+            tcp(socketRequestor().requestSocket(SocketRequestor::TCP,
+                                                address.first, address.second,
+                                                SocketRequestor::DONT_SHARE,
+                                                "dummy_app"));
+        current_sockets.push_back(tcp.second);
+        if (!test_mode) {
+            service.addServerTCP(tcp.first, true); // FIXME: Correct the flag
+        }
+        const SocketRequestor::SocketID
+            udp(socketRequestor().requestSocket(SocketRequestor::UDP,
+                                                address.first, address.second,
+                                                SocketRequestor::DONT_SHARE,
+                                                "dummy_app"));
+        current_sockets.push_back(udp.second);
+        if (!test_mode) {
+            service.addServerUDP(udp.first, true); // FIXME: Correct the flag
+        }
     }
 }
 

+ 129 - 2
src/lib/server_common/tests/portconfig_unittest.cc

@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <server_common/portconfig.h>
+#include <server_common/socket_request.h>
 
 #include <cc/data.h>
 #include <exceptions/exceptions.h>
@@ -21,13 +22,25 @@
 
 #include <gtest/gtest.h>
 #include <string>
+#include <boost/lexical_cast.hpp>
 
 using namespace isc::server_common::portconfig;
+using namespace isc::server_common;
 using namespace isc::data;
 using namespace isc;
 using namespace std;
 using namespace isc::asiolink;
 using namespace isc::asiodns;
+using boost::lexical_cast;
+
+// Access the private hidden flag
+namespace isc {
+namespace server_common {
+namespace portconfig {
+extern bool test_mode;
+}
+}
+}
 
 namespace {
 
@@ -127,12 +140,15 @@ TEST_F(ParseAddresses, invalid) {
 }
 
 // Test fixture for installListenAddresses
-struct InstallListenAddresses : public ::testing::Test {
+struct InstallListenAddresses : public ::testing::Test,
+    public SocketRequestor {
     InstallListenAddresses() :
-        dnss_(ios_, NULL, NULL, NULL)
+        dnss_(ios_, NULL, NULL, NULL),
+        last_token_(0)
     {
         valid_.push_back(AddressPair("127.0.0.1", 5288));
         valid_.push_back(AddressPair("::1", 5288));
+        invalid_.push_back(AddressPair("127.0.0.1", 5288));
         invalid_.push_back(AddressPair("192.0.2.2", 1));
     }
     IOService ios_;
@@ -142,6 +158,11 @@ struct InstallListenAddresses : public ::testing::Test {
     AddressList valid_;
     // But this shouldn't work
     AddressList invalid_;
+    // Store the tokens as they go in and out
+    vector<string> released_tokens_;
+    vector<string> given_tokens_;
+    // Last token number and fd given out
+    size_t last_token_;
     // Check that the store_ addresses are the same as expected
     void checkAddresses(const AddressList& expected, const string& name) {
         SCOPED_TRACE(name);
@@ -155,20 +176,91 @@ struct InstallListenAddresses : public ::testing::Test {
             EXPECT_EQ(ei->second, si->second);
         }
     }
+    void releaseSocket(const string& token) {
+        released_tokens_.push_back(token);
+    }
+    SocketID requestSocket(Protocol protocol, const string& address,
+                           uint16_t port, ShareMode mode, const string& name)
+    {
+        if (address == "192.0.2.2") {
+            isc_throw(SocketError, "This address is not allowed");
+        }
+        const string proto(protocol == TCP ? "TCP" : "UDP");
+        size_t number = ++ last_token_;
+        EXPECT_EQ(5288, port);
+        EXPECT_EQ(DONT_SHARE, mode);
+        EXPECT_EQ("dummy_app", name);
+        const string token(proto + ":" + address + ":" +
+                           lexical_cast<string>(port) + ":" +
+                           lexical_cast<string>(number));
+        given_tokens_.push_back(token);
+        return (SocketID(number, token));
+    }
+    void SetUp() {
+        // Prepare the requestor (us) for the test
+        SocketRequestor::initTest(this);
+        // Don't manipulate the real sockets
+        test_mode = true;
+    }
+    void TearDown() {
+        // Make sure no sockets are left inside
+        AddressList list;
+        installListenAddresses(list, store_, dnss_);
+        // Don't leave invalid pointers here
+        SocketRequestor::initTest(NULL);
+        // And return the mode
+        test_mode = false;
+    }
+    // This checks the set of tokens is the same
+    void checkTokens(const char** expected, const vector<string>& real,
+                     const char* scope)
+    {
+        SCOPED_TRACE(scope);
+        size_t position(0);
+        while (expected[position]) {
+            ASSERT_LT(position, real.size());
+            EXPECT_EQ(expected[position], real[position]) << position;
+            position ++;
+        }
+        EXPECT_EQ(position, real.size());
+    }
 };
 
 // Try switching valid addresses
+// Check the sockets are correctly requested and returned
 TEST_F(InstallListenAddresses, valid) {
     // First, bind to the valid addresses
     EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_));
     checkAddresses(valid_, "Valid addresses");
+    const char* tokens1[] = {
+        "TCP:127.0.0.1:5288:1",
+        "UDP:127.0.0.1:5288:2",
+        "TCP:::1:5288:3",
+        "UDP:::1:5288:4",
+        NULL
+    };
+    const char* no_tokens[] = { NULL };
+    checkTokens(tokens1, given_tokens_, "Valid given tokens 1");
+    checkTokens(no_tokens, released_tokens_, "Valid no released tokens 1");
     // TODO Maybe some test to actually connect to them
     // Try setting it back to nothing
+    given_tokens_.clear();
     EXPECT_NO_THROW(installListenAddresses(AddressList(), store_, dnss_));
     checkAddresses(AddressList(), "No addresses");
+    checkTokens(no_tokens, given_tokens_, "Valid no given tokens");
+    checkTokens(tokens1, released_tokens_, "Valid released tokens");
     // Try switching back again
     EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_));
     checkAddresses(valid_, "Valid addresses");
+    const char* tokens2[] = {
+        "TCP:127.0.0.1:5288:5",
+        "UDP:127.0.0.1:5288:6",
+        "TCP:::1:5288:7",
+        "UDP:::1:5288:8",
+        NULL
+    };
+    checkTokens(tokens2, given_tokens_, "Valid given tokens 2");
+    checkTokens(tokens1, released_tokens_, "Valid released tokens");
 }
 
 // Try if rollback works
@@ -176,9 +268,44 @@ TEST_F(InstallListenAddresses, rollback) {
     // Set some addresses
     EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_));
     checkAddresses(valid_, "Before rollback");
+    const char* tokens1[] = {
+        "TCP:127.0.0.1:5288:1",
+        "UDP:127.0.0.1:5288:2",
+        "TCP:::1:5288:3",
+        "UDP:::1:5288:4",
+        NULL
+    };
+    const char* no_tokens[] = { NULL };
+    checkTokens(tokens1, given_tokens_, "Given before rollback");
+    checkTokens(no_tokens, released_tokens_, "Released before rollback");
+    given_tokens_.clear();
     // This should not bind them, but should leave the original addresses
     EXPECT_THROW(installListenAddresses(invalid_, store_, dnss_), exception);
     checkAddresses(valid_, "After rollback");
+    // Now, it should have requested first pair of sockets from the invalids
+    // and, as the second failed, it should have returned them right away.
+    const char* released1[] = {
+        "TCP:127.0.0.1:5288:1",
+        "UDP:127.0.0.1:5288:2",
+        "TCP:::1:5288:3",
+        "UDP:::1:5288:4",
+        "TCP:127.0.0.1:5288:5",
+        "UDP:127.0.0.1:5288:6",
+        NULL
+    };
+    // It should request the first pair of sockets, and then request the
+    // complete set of valid addresses to rollback
+    const char* tokens2[] = {
+        "TCP:127.0.0.1:5288:5",
+        "UDP:127.0.0.1:5288:6",
+        "TCP:127.0.0.1:5288:7",
+        "UDP:127.0.0.1:5288:8",
+        "TCP:::1:5288:9",
+        "UDP:::1:5288:10",
+        NULL
+    };
+    checkTokens(tokens2, given_tokens_, "Given after rollback");
+    checkTokens(released1, released_tokens_, "Released after rollback");
 }
 
 }