Browse Source

[1522] implement releaseSocket as well

Jelte Jansen 13 years ago
parent
commit
d2fc3f36ec

+ 37 - 3
src/lib/server_common/socket_request.cc

@@ -45,6 +45,11 @@ static const std::string CREATOR_SOCKET_UNAVAILABLE("0");
 // respective methods)
 static const std::string REQUEST_SOCKET_COMMAND("get_socket");
 
+// The name of the ccsession command to tell boss we no longer need
+// a socket (the actual format of command and response are hardcoded
+// in their respective methods)
+static const std::string RELEASE_SOCKET_COMMAND("drop_socket");
+
 // This implementation class for SocketRequestor uses
 // a ModuleCCSession for communication with the boss process,
 // and fd_share to read out the socket(s).
@@ -64,7 +69,6 @@ public:
                                    const std::string& address,
                                    uint16_t port, ShareMode share_mode,
                                    const std::string& share_name) {
-
         isc::data::ConstElementPtr request_msg =
             createRequestSocketMessage(protocol, address, port,
                                        share_mode, share_name);
@@ -93,7 +97,28 @@ public:
     };
 
     virtual void releaseSocket(const std::string& token) {
-        (void)token;
+        isc::data::ConstElementPtr release_msg =
+            createReleaseSocketMessage(token);
+
+        // Send it to boss
+        int seq = session_.groupSendMsg(release_msg, "Boss");
+
+        // Get the answer from the boss.
+        // Just do a blocking read, we can't really do much anyway
+        isc::data::ConstElementPtr env, recv_msg;
+        if (!session_.groupRecvMsg(env, recv_msg, false, seq)) {
+            isc_throw(isc::config::CCSessionError,
+                      "Incomplete response when sending drop socket command");
+        }
+
+        // Answer should just be success
+        int rcode;
+        isc::data::ConstElementPtr error = isc::config::parseAnswer(rcode,
+                                                                    recv_msg);
+        if (rcode != 0) {
+            isc_throw(SocketError,
+                      "Error requesting release of socket: " << error->str());
+        }
     };
 
 private:
@@ -136,6 +161,14 @@ private:
         return (isc::config::createCommand(REQUEST_SOCKET_COMMAND, request));
     }
 
+    isc::data::ConstElementPtr
+    createReleaseSocketMessage(const std::string& token) {
+        isc::data::ElementPtr release = isc::data::Element::createMap();
+        release->set("token", isc::data::Element::create(token));
+
+        return (isc::config::createCommand(RELEASE_SOCKET_COMMAND, release));
+    }
+
     // Checks and parses the response receive from Boss
     // If successful, token and path will be set to the values found in the
     // answer.
@@ -145,7 +178,8 @@ private:
                                  std::string& token,
                                  std::string& path) {
         int rcode;
-        isc::data::ConstElementPtr answer = isc::config::parseAnswer(rcode, recv_msg);
+        isc::data::ConstElementPtr answer = isc::config::parseAnswer(rcode,
+                                                                     recv_msg);
         if (rcode != 0) {
             isc_throw(isc::config::CCSessionError,
                       "Error response when requesting socket: " <<

+ 56 - 6
src/lib/server_common/tests/socket_requestor_test.cc

@@ -126,11 +126,12 @@ public:
 
 // helper function to create the request packet as we expect the
 // socket requestor to send
-ConstElementPtr createExpectedRequest(const std::string& address,
-                                      int port,
-                                      const std::string& protocol,
-                                      const std::string& share_mode,
-                                      const std::string& share_name) {
+ConstElementPtr
+createExpectedRequest(const std::string& address,
+                      int port,
+                      const std::string& protocol,
+                      const std::string& share_mode,
+                      const std::string& share_name) {
     // create command arguments
     ElementPtr command_args = Element::createMap();
     command_args->set("address", Element::create(address));
@@ -149,9 +150,11 @@ ConstElementPtr createExpectedRequest(const std::string& address,
 }
 
 TEST_F(SocketRequestorTest, testSocketRequestMessages) {
-    // Should raise CCSessionError if there is no answer
+    // For each request, it will raise CCSessionError, since we don't
+    // answer here.
     // We are only testing the request messages that are sent,
     // so for this test that is no problem
+
     clearMsgQueue();
     ConstElementPtr expected_request;
 
@@ -189,6 +192,8 @@ TEST_F(SocketRequestorTest, testSocketRequestMessages) {
 }
 
 TEST_F(SocketRequestorTest, testBadRequestAnswers) {
+    // Test various scenarios where the requestor gets back bad answers
+
     // Should raise CCSessionError if there is no answer
     ASSERT_THROW(doRequest(), CCSessionError);
 
@@ -210,6 +215,51 @@ TEST_F(SocketRequestorTest, testBadRequestAnswers) {
     ASSERT_THROW(doRequest(), CCSessionError);
 }
 
+// Helper function to create the release commands as we expect
+// them to be sent by the socketrequestor class
+ConstElementPtr
+createExpectedRelease(const std::string& token) {
+    // create command arguments
+    ElementPtr command_args = Element::createMap();
+    command_args->set("token", Element::create(token));
+
+    // create the envelope
+    ElementPtr packet = Element::createList();
+    packet->add(Element::create("Boss"));
+    packet->add(Element::create("*"));
+    packet->add(createCommand("drop_socket", command_args));
+
+    return (packet);
+}
+
+TEST_F(SocketRequestorTest, testSocketReleaseMessages) {
+    ConstElementPtr expected_release;
+
+    session.getMessages()->add(createAnswer());
+
+    clearMsgQueue();
+    expected_release = createExpectedRelease("foo");
+    socketRequestor().releaseSocket("foo");
+    ASSERT_EQ(1, session.getMsgQueue()->size());
+    ASSERT_EQ(*expected_release, *(session.getMsgQueue()->get(0)));
+
+    session.getMessages()->add(createAnswer());
+    clearMsgQueue();
+    expected_release = createExpectedRelease("bar");
+    socketRequestor().releaseSocket("bar");
+    ASSERT_EQ(1, session.getMsgQueue()->size());
+    ASSERT_EQ(*expected_release, *(session.getMsgQueue()->get(0)));
+}
+
+TEST_F(SocketRequestorTest, testBadSocketReleaseAnswers) {
+    ASSERT_THROW(socketRequestor().releaseSocket("bar"),
+                 CCSessionError);
+
+    session.getMessages()->add(createAnswer(1, "error"));
+    ASSERT_THROW(socketRequestor().releaseSocket("bar"),
+                 SocketRequestor::SocketError);
+}
+
 // Helper test class that creates a random domain socket
 // When run() is called, it creates the socket, forks, and the child will
 // listen for a connection, then send all the data passed to run to that