such as <command>socat</command> and <command>curl</command>.</para>
<para>In order to control the given Kea service via unix domain socket, use
- <command>socat</command> as follows:
+ <command>socat</command> in interactive mode as follows:
<screen>
$ socat UNIX:/path/to/the/kea/socket -
+</screen>
+ or in batch mode, include the "ignoreeof" option as shown below to ensure
+ socat waits long enough for the server to respond:
+<screen>
+$ echo "{ some command...}" | socat UNIX:/path/to/the/kea/socket -,ignoreeof
</screen>
where <command>/path/to/the/kea/socket</command> is the path specified in the
<command>Dhcp4/control-socket/socket-name</command> parameter in the Kea
}
// This test verifies that the server signals timeout if the transmission
-// takes too long.
-TEST_F(CtrlChannelDhcpv4SrvTest, connectionTimeout) {
+// takes too long, after receiving a partial command.
+TEST_F(CtrlChannelDhcpv4SrvTest, connectionTimeoutPartialCommand) {
createUnixChannelServer();
// Set connection timeout to 2s to prevent long waiting time for the
th.join();
// Check that the server has signalled a timeout.
- EXPECT_EQ("{ \"result\": 1, \"text\": \"Connection over control channel"
- " timed out\" }", response);
+ EXPECT_EQ("{ \"result\": 1, \"text\": "
+ "\"Connection over control channel timed out, "
+ "discarded partial command of 19 bytes\" }" , response);
}
+// This test verifies that the server signals timeout if the transmission
+// takes too long, having received no data from the client.
+TEST_F(CtrlChannelDhcpv4SrvTest, connectionTimeoutNoData) {
+ createUnixChannelServer();
+
+ // Set connection timeout to 2s to prevent long waiting time for the
+ // timeout during this test.
+ const unsigned short timeout = 2;
+ CommandMgr::instance().setConnectionTimeout(timeout);
+
+ // Server's response will be assigned to this variable.
+ std::string response;
+
+ // It is useful to create a thread and run the server and the client
+ // at the same time and independently.
+ std::thread th([this, &response]() {
+ // IO service will be stopped automatically when this object goes
+ // out of scope and is destroyed. This is useful because we use
+ // asserts which may break the thread in various exit points.
+ IOServiceWork work(getIOService());
+ // Create the client and connect it to the server.
+ boost::scoped_ptr<UnixControlClient> client(new UnixControlClient());
+ ASSERT_TRUE(client);
+ ASSERT_TRUE(client->connectToServer(socket_path_));
+
+ // Let's wait up to 15s for the server's response. The response
+ // should arrive sooner assuming that the timeout mechanism for
+ // the server is working properly.
+ const unsigned int timeout = 15;
+ ASSERT_TRUE(client->getResponse(response, timeout));
+
+ // Explicitly close the client's connection.
+ client->disconnectFromServer();
+ });
+
+ // Run the server until stopped.
+ getIOService()->run();
+
+ // Wait for the thread to return.
+ th.join();
+
+ // Check that the server has signalled a timeout.
+ EXPECT_EQ("{ \"result\": 1, \"text\": "
+ "\"Connection over control channel timed out\" }", response);
+}
} // End of anonymous namespace
}
// This test verifies that the server signals timeout if the transmission
-// takes too long.
-TEST_F(CtrlChannelDhcpv6SrvTest, connectionTimeout) {
+// takes too long, having received a partial command.
+TEST_F(CtrlChannelDhcpv6SrvTest, connectionTimeoutPartialCommand) {
createUnixChannelServer();
// Set connection timeout to 2s to prevent long waiting time for the
th.join();
// Check that the server has signalled a timeout.
- EXPECT_EQ("{ \"result\": 1, \"text\": \"Connection over control channel"
- " timed out\" }", response);
+ EXPECT_EQ("{ \"result\": 1, \"text\": "
+ "\"Connection over control channel timed out,"
+ " discarded partial command of 19 bytes\" }", response);
}
+// This test verifies that the server signals timeout if the transmission
+// takes too long, having received no data.
+TEST_F(CtrlChannelDhcpv6SrvTest, connectionTimeoutNoData) {
+ createUnixChannelServer();
+
+ // Set connection timeout to 2s to prevent long waiting time for the
+ // timeout during this test.
+ const unsigned short timeout = 2;
+ CommandMgr::instance().setConnectionTimeout(timeout);
+
+ // Server's response will be assigned to this variable.
+ std::string response;
+
+ // It is useful to create a thread and run the server and the client
+ // at the same time and independently.
+ std::thread th([this, &response]() {
+
+ // IO service will be stopped automatically when this object goes
+ // out of scope and is destroyed. This is useful because we use
+ // asserts which may break the thread in various exit points.
+ IOServiceWork work(getIOService());
+
+ // Create the client and connect it to the server.
+ boost::scoped_ptr<UnixControlClient> client(new UnixControlClient());
+ ASSERT_TRUE(client);
+ ASSERT_TRUE(client->connectToServer(socket_path_));
+
+ // Having sent nothing let's just wait and see if Server times us out.
+ // Let's wait up to 15s for the server's response. The response
+ // should arrive sooner assuming that the timeout mechanism for
+ // the server is working properly.
+ const unsigned int timeout = 15;
+ ASSERT_TRUE(client->getResponse(response, timeout));
+
+ // Explicitly close the client's connection.
+ client->disconnectFromServer();
+ });
+
+ // Run the server until stopped.
+ getIOService()->run();
+
+ // Wait for the thread to return.
+ th.join();
+
+ // Check that the server has signalled a timeout.
+ EXPECT_EQ("{ \"result\": 1, \"text\": "
+ "\"Connection over control channel timed out\" }", response);
+}
} // End of anonymous namespace
return (error_message_);
}
+ /// @brief Returns the text parsed into the buffer.
+ std::string getProcessedText() const {
+ return (output_);
+ }
+
/// @brief Returns processed data as a structure of @ref isc::data::Element
/// objects.
///
size_t bytes_transferred) {
if (ec) {
if (ec.value() == boost::asio::error::eof) {
+ std::stringstream os;
+ if (feed_.getProcessedText().empty()) {
+ os << "no input data to discard";
+ }
+ else {
+ os << "discarding partial command of "
+ << feed_.getProcessedText().size() << " bytes";
+ }
+
// Foreign host has closed the connection. We should remove it from the
// connection pool.
LOG_INFO(command_logger, COMMAND_SOCKET_CLOSED_BY_FOREIGN_HOST)
- .arg(socket_->getNative());
-
+ .arg(socket_->getNative()).arg(os.str());
} else if (ec.value() != boost::asio::error::operation_aborted) {
LOG_ERROR(command_logger, COMMAND_SOCKET_READ_FAIL)
.arg(ec.value()).arg(socket_->getNative());
.arg(ex.what());
}
- ConstElementPtr rsp = createAnswer(CONTROL_RESULT_ERROR, "Connection over"
- " control channel timed out");
+ std::stringstream os;
+ os << "Connection over control channel timed out";
+ if (!feed_.getProcessedText().empty()) {
+ os << ", discarded partial command of "
+ << feed_.getProcessedText().size() << " bytes";
+ }
+
+ ConstElementPtr rsp = createAnswer(CONTROL_RESULT_ERROR, os.str());
response_ = rsp->str();
doSend();
}
accept system call on said socket, but this call returned an error. Additional
information may be provided by the system as second parameter.
-% COMMAND_SOCKET_CLOSED_BY_FOREIGN_HOST Closed command socket %1 by foreign host
+% COMMAND_SOCKET_CLOSED_BY_FOREIGN_HOST Closed command socket %1 by foreign host, %2
This is an information message indicating that the command connection has been
-closed by a command control client.
+closed by a command control client, and whether or not any partially read data
+was discarded.
% COMMAND_SOCKET_CONNECTION_CANCEL_FAIL Failed to cancel read operation on socket %1: %2
This error message is issued to indicate an error to cancel asynchronous read