mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 22:15:23 +00:00
[5317] Only a single control command connection is now allowed.
This commit is contained in:
@@ -1066,4 +1066,50 @@ TEST_F(CtrlChannelDhcpv4SrvTest, configReloadValid) {
|
|||||||
::remove("test8.json");
|
::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
|
} // End of anonymous namespace
|
||||||
|
@@ -1088,4 +1088,51 @@ TEST_F(CtrlChannelDhcpv6SrvTest, configReloadValid) {
|
|||||||
::remove("test8.json");
|
::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
|
} // End of anonymous namespace
|
||||||
|
@@ -97,6 +97,10 @@ public:
|
|||||||
connections_.clear();
|
connections_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t getConnectionsNum() const {
|
||||||
|
return (connections_.size());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::set<ConnectionPtr> connections_;
|
std::set<ConnectionPtr> connections_;
|
||||||
@@ -109,7 +113,14 @@ Connection::receiveHandler(const boost::system::error_code& ec,
|
|||||||
size_t bytes_transferred) {
|
size_t bytes_transferred) {
|
||||||
if (ec) {
|
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)
|
LOG_ERROR(command_logger, COMMAND_SOCKET_READ_FAIL)
|
||||||
.arg(ec.value()).arg(socket_->getNative());
|
.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);
|
std::string sbuf(&buf_[0], bytes_transferred);
|
||||||
cmd = Element::fromJSON(sbuf, true);
|
cmd = Element::fromJSON(sbuf, true);
|
||||||
|
|
||||||
// If successful, then process it as a command.
|
if (connection_pool_.getConnectionsNum() > 1) {
|
||||||
rsp = CommandMgr::instance().processCommand(cmd);
|
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) {
|
} catch (const Exception& ex) {
|
||||||
LOG_WARN(command_logger, COMMAND_PROCESS_ERROR1).arg(ex.what());
|
LOG_WARN(command_logger, COMMAND_PROCESS_ERROR1).arg(ex.what());
|
||||||
|
@@ -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
|
accept system call on said socket, but this call returned an error. Additional
|
||||||
information may be provided by the system as second parameter.
|
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
|
% COMMAND_SOCKET_CONNECTION_CLOSED Closed socket %1 for existing command connection
|
||||||
This is an informational message that the socket created for handling
|
This is an informational message that the socket created for handling
|
||||||
client's connection is closed. This usually means that the client disconnected,
|
client's connection is closed. This usually means that the client disconnected,
|
||||||
|
Reference in New Issue
Block a user