From: Jelte Jansen Date: Thu, 22 Dec 2011 15:23:51 +0000 (+0100) Subject: [1522] implement releaseSocket as well X-Git-Tag: trac2351_base~304^2~15^2~21 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d2fc3f36ec89c950850b1aab3b8bef5d4413aaaf;p=thirdparty%2Fkea.git [1522] implement releaseSocket as well --- diff --git a/src/lib/server_common/socket_request.cc b/src/lib/server_common/socket_request.cc index e7cba64e02..8f9fca4d67 100644 --- a/src/lib/server_common/socket_request.cc +++ b/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: " << diff --git a/src/lib/server_common/tests/socket_requestor_test.cc b/src/lib/server_common/tests/socket_requestor_test.cc index ed805e0f6a..2d60525acf 100644 --- a/src/lib/server_common/tests/socket_requestor_test.cc +++ b/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