// 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).
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);
};
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:
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.
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: " <<
// 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));
}
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;
}
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);
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