2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 05:27:55 +00:00

[5317] Only a single control command connection is now allowed.

This commit is contained in:
Marcin Siodelski 2017-06-22 13:39:19 +02:00
parent 2688a2a886
commit c4fb6001e7
4 changed files with 116 additions and 3 deletions

View File

@ -1066,4 +1066,50 @@ TEST_F(CtrlChannelDhcpv4SrvTest, configReloadValid) {
::remove("test8.json");
}
// Verify that server returns an error if more than one connection is established.
TEST_F(CtrlChannelDhcpv4SrvTest, concurrentConnections) {
createUnixChannelServer();
boost::scoped_ptr<UnixControlClient> client1(new UnixControlClient());
ASSERT_TRUE(client1);
boost::scoped_ptr<UnixControlClient> client2(new UnixControlClient());
ASSERT_TRUE(client1);
// Client 1 connects.
ASSERT_TRUE(client1->connectToServer(socket_path_));
ASSERT_NO_THROW(getIOService()->poll());
// Client 2 connects.
ASSERT_TRUE(client2->connectToServer(socket_path_));
ASSERT_NO_THROW(getIOService()->poll());
// Send the command while another client is connected.
ASSERT_TRUE(client2->sendCommand("{ \"command\": \"list-commands\" }"));
ASSERT_NO_THROW(getIOService()->poll());
// The server should not allow for concurrent connections and should send
// out an error message.
std::string response;
ASSERT_TRUE(client2->getResponse(response));
EXPECT_EQ("{ \"result\": 1, \"text\": \"exceeded maximum number of concurrent"
" connections\" }", response);
// Now disconnect the first server and retry.
client1->disconnectFromServer();
ASSERT_NO_THROW(getIOService()->poll());
ASSERT_TRUE(client2->connectToServer(socket_path_));
ASSERT_NO_THROW(getIOService()->poll());
ASSERT_TRUE(client2->sendCommand("{ \"command\": \"list-commands\" }"));
ASSERT_NO_THROW(getIOService()->poll());
// The server should now respond ok.
ASSERT_TRUE(client2->getResponse(response));
EXPECT_TRUE(response.find("\"result\": 0") != std::string::npos);
client2->disconnectFromServer();
}
} // End of anonymous namespace

View File

@ -1088,4 +1088,51 @@ TEST_F(CtrlChannelDhcpv6SrvTest, configReloadValid) {
::remove("test8.json");
}
// Verify that server returns an error if more than one connection is established.
TEST_F(CtrlChannelDhcpv6SrvTest, concurrentConnections) {
createUnixChannelServer();
boost::scoped_ptr<UnixControlClient> client1(new UnixControlClient());
ASSERT_TRUE(client1);
boost::scoped_ptr<UnixControlClient> client2(new UnixControlClient());
ASSERT_TRUE(client1);
// Client 1 connects.
ASSERT_TRUE(client1->connectToServer(socket_path_));
ASSERT_NO_THROW(getIOService()->poll());
// Client 2 connects.
ASSERT_TRUE(client2->connectToServer(socket_path_));
ASSERT_NO_THROW(getIOService()->poll());
// Send the command while another client is connected.
ASSERT_TRUE(client2->sendCommand("{ \"command\": \"list-commands\" }"));
ASSERT_NO_THROW(getIOService()->poll());
// The server should not allow for concurrent connections and should send
// out an error message.
std::string response;
ASSERT_TRUE(client2->getResponse(response));
EXPECT_EQ("{ \"result\": 1, \"text\": \"exceeded maximum number of concurrent"
" connections\" }", response);
// Now disconnect the first server and retry.
client1->disconnectFromServer();
ASSERT_NO_THROW(getIOService()->poll());
ASSERT_TRUE(client2->connectToServer(socket_path_));
ASSERT_NO_THROW(getIOService()->poll());
ASSERT_TRUE(client2->sendCommand("{ \"command\": \"list-commands\" }"));
ASSERT_NO_THROW(getIOService()->poll());
// The server should now respond ok.
ASSERT_TRUE(client2->getResponse(response));
EXPECT_TRUE(response.find("\"result\": 0") != std::string::npos);
client2->disconnectFromServer();
}
} // End of anonymous namespace

View File

@ -97,6 +97,10 @@ public:
connections_.clear();
}
size_t getConnectionsNum() const {
return (connections_.size());
}
private:
std::set<ConnectionPtr> connections_;
@ -109,7 +113,14 @@ Connection::receiveHandler(const boost::system::error_code& ec,
size_t bytes_transferred) {
if (ec) {
if (ec.value() != boost::asio::error::operation_aborted) {
if (ec.value() == boost::asio::error::eof) {
// 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());
connection_pool_.stop(shared_from_this());
} else if (ec.value() != boost::asio::error::operation_aborted) {
LOG_ERROR(command_logger, COMMAND_SOCKET_READ_FAIL)
.arg(ec.value()).arg(socket_->getNative());
}
@ -137,8 +148,13 @@ Connection::receiveHandler(const boost::system::error_code& ec,
std::string sbuf(&buf_[0], bytes_transferred);
cmd = Element::fromJSON(sbuf, true);
// If successful, then process it as a command.
rsp = CommandMgr::instance().processCommand(cmd);
if (connection_pool_.getConnectionsNum() > 1) {
rsp = createAnswer(CONTROL_RESULT_ERROR, "exceeded maximum number of concurrent"
" connections");
} else {
// If successful, then process it as a command.
rsp = CommandMgr::instance().processCommand(cmd);
}
} catch (const Exception& ex) {
LOG_WARN(command_logger, COMMAND_PROCESS_ERROR1).arg(ex.what());

View File

@ -55,6 +55,10 @@ This error indicates that the server detected incoming connection and executed
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
This is an information message indicating that the command connection has been
closed by a command control client.
% COMMAND_SOCKET_CONNECTION_CLOSED Closed socket %1 for existing command connection
This is an informational message that the socket created for handling
client's connection is closed. This usually means that the client disconnected,