mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-01 14:35:29 +00:00
[3880] Support for control-socket implemented in DHCPv4.
This commit is contained in:
@@ -19,9 +19,11 @@
|
|||||||
#include <hooks/hooks_manager.h>
|
#include <hooks/hooks_manager.h>
|
||||||
#include <dhcp4/json_config_parser.h>
|
#include <dhcp4/json_config_parser.h>
|
||||||
#include <dhcpsrv/cfgmgr.h>
|
#include <dhcpsrv/cfgmgr.h>
|
||||||
|
#include <config/command_mgr.h>
|
||||||
|
|
||||||
using namespace isc::data;
|
using namespace isc::data;
|
||||||
using namespace isc::hooks;
|
using namespace isc::hooks;
|
||||||
|
using namespace isc::config;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace isc {
|
namespace isc {
|
||||||
@@ -121,7 +123,6 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
|
|||||||
|
|
||||||
ConstElementPtr answer = configureDhcp4Server(*srv, config);
|
ConstElementPtr answer = configureDhcp4Server(*srv, config);
|
||||||
|
|
||||||
|
|
||||||
// Check that configuration was successful. If not, do not reopen sockets
|
// Check that configuration was successful. If not, do not reopen sockets
|
||||||
// and don't bother with DDNS stuff.
|
// and don't bother with DDNS stuff.
|
||||||
try {
|
try {
|
||||||
@@ -164,6 +165,19 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/)
|
|||||||
"There is another Dhcpv4Srv instance already.");
|
"There is another Dhcpv4Srv instance already.");
|
||||||
}
|
}
|
||||||
server_ = this; // remember this instance for later use in handlers
|
server_ = this; // remember this instance for later use in handlers
|
||||||
|
|
||||||
|
// Register supported commands in CommandMgr
|
||||||
|
CommandMgr::instance().registerCommand("shutdown",
|
||||||
|
boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, _1, _2));
|
||||||
|
|
||||||
|
/// @todo: register config-reload (see CtrlDhcpv4Srv::commandConfigReloadHandler)
|
||||||
|
/// @todo: register libreload (see CtrlDhcpv4Srv::commandLibReloadHandler)
|
||||||
|
/// @todo: register statistic-get (see StatsMgr::get(name))
|
||||||
|
/// @todo: register statistic-reset (see StatsMgr::reset(name))
|
||||||
|
/// @todo: register statistic-get-all (see StatsMgr::getAll())
|
||||||
|
/// @todo: register statistic-reset-all (see StatsMgr::resetAll())
|
||||||
|
/// @todo: register statistic-remove (see StatsMgr::del(name))
|
||||||
|
/// @todo: register statistic-remove-all (see StatsMgr::removeAll())
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlledDhcpv4Srv::shutdown() {
|
void ControlledDhcpv4Srv::shutdown() {
|
||||||
@@ -174,6 +188,12 @@ void ControlledDhcpv4Srv::shutdown() {
|
|||||||
ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
|
ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
|
// Close the command socket (if it exists).
|
||||||
|
CommandMgr::instance().closeCommandSocket();
|
||||||
|
|
||||||
|
// Deregister any registered commands
|
||||||
|
CommandMgr::instance().deregisterCommand("shutdown");
|
||||||
|
|
||||||
server_ = NULL; // forget this instance. Noone should call any handlers at
|
server_ = NULL; // forget this instance. Noone should call any handlers at
|
||||||
// this stage.
|
// this stage.
|
||||||
}
|
}
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include <dhcpsrv/parsers/host_reservation_parser.h>
|
#include <dhcpsrv/parsers/host_reservation_parser.h>
|
||||||
#include <dhcpsrv/parsers/host_reservations_list_parser.h>
|
#include <dhcpsrv/parsers/host_reservations_list_parser.h>
|
||||||
#include <dhcpsrv/parsers/ifaces_config_parser.h>
|
#include <dhcpsrv/parsers/ifaces_config_parser.h>
|
||||||
|
#include <config/command_mgr.h>
|
||||||
#include <util/encode/hex.h>
|
#include <util/encode/hex.h>
|
||||||
#include <util/strutil.h>
|
#include <util/strutil.h>
|
||||||
|
|
||||||
@@ -399,6 +400,8 @@ namespace dhcp {
|
|||||||
parser = new D2ClientConfigParser(config_id);
|
parser = new D2ClientConfigParser(config_id);
|
||||||
} else if (config_id.compare("match-client-id") == 0) {
|
} else if (config_id.compare("match-client-id") == 0) {
|
||||||
parser = new BooleanParser(config_id, globalContext()->boolean_values_);
|
parser = new BooleanParser(config_id, globalContext()->boolean_values_);
|
||||||
|
} else if (config_id.compare("control-socket") == 0) {
|
||||||
|
parser = new ControlSocketParser(config_id);
|
||||||
} else {
|
} else {
|
||||||
isc_throw(DhcpConfigError,
|
isc_throw(DhcpConfigError,
|
||||||
"unsupported global configuration parameter: "
|
"unsupported global configuration parameter: "
|
||||||
@@ -532,6 +535,26 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
|||||||
subnet_parser->build(subnet_config->second);
|
subnet_parser->build(subnet_config->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get command socket configuration from the config file.
|
||||||
|
// This code expects the following structure:
|
||||||
|
// {
|
||||||
|
// "socket-type": "unix",
|
||||||
|
// "socket-name": "/tmp/kea4.sock"
|
||||||
|
// }
|
||||||
|
ConstElementPtr sock_cfg =
|
||||||
|
CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
|
||||||
|
|
||||||
|
// Close existing socket (if any).
|
||||||
|
isc::config::CommandMgr::instance().closeCommandSocket();
|
||||||
|
if (sock_cfg) {
|
||||||
|
// This will create a control socket and will install external socket
|
||||||
|
// in IfaceMgr. That socket will be monitored when Dhcp4Srv::receivePacket()
|
||||||
|
// calls IfaceMgr::receive4() and callback in CommandMgr will be called,
|
||||||
|
// if necessary. If there were previously open command socket, it will
|
||||||
|
// be closed.
|
||||||
|
isc::config::CommandMgr::instance().openCommandSocket(sock_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
// the leases database parser is the last to be run.
|
// the leases database parser is the last to be run.
|
||||||
std::map<std::string, ConstElementPtr>::const_iterator leases_config =
|
std::map<std::string, ConstElementPtr>::const_iterator leases_config =
|
||||||
values_map.find("lease-database");
|
values_map.find("lease-database");
|
||||||
|
@@ -104,6 +104,8 @@ void configure(const std::string& file_name) {
|
|||||||
CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
|
CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
|
||||||
|
|
||||||
// Use new configuration.
|
// Use new configuration.
|
||||||
|
/// @todo: This commit should be moved to
|
||||||
|
/// CtrlDhcp4Srv::commandConfigReloadHandler.
|
||||||
CfgMgr::instance().commit();
|
CfgMgr::instance().commit();
|
||||||
|
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
@@ -171,7 +173,6 @@ ControlledDhcpv4Srv::init(const std::string& file_name) {
|
|||||||
signal_set_.reset(new isc::util::SignalSet(SIGINT, SIGHUP, SIGTERM));
|
signal_set_.reset(new isc::util::SignalSet(SIGINT, SIGHUP, SIGTERM));
|
||||||
// Set the pointer to the handler function.
|
// Set the pointer to the handler function.
|
||||||
signal_handler_ = signalHandler;
|
signal_handler_ = signalHandler;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlledDhcpv4Srv::cleanup() {
|
void ControlledDhcpv4Srv::cleanup() {
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <cc/command_interpreter.h>
|
#include <cc/command_interpreter.h>
|
||||||
|
#include <config/command_mgr.h>
|
||||||
#include <dhcp/dhcp4.h>
|
#include <dhcp/dhcp4.h>
|
||||||
#include <dhcp4/ctrl_dhcp4_srv.h>
|
#include <dhcp4/ctrl_dhcp4_srv.h>
|
||||||
#include <hooks/hooks_manager.h>
|
#include <hooks/hooks_manager.h>
|
||||||
@@ -156,4 +157,89 @@ TEST_F(CtrlDhcpv4SrvTest, libreload) {
|
|||||||
EXPECT_TRUE(checkMarkerFile(LOAD_MARKER_FILE, "1212"));
|
EXPECT_TRUE(checkMarkerFile(LOAD_MARKER_FILE, "1212"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test checks which commands are registered by the DHCPv4 server.
|
||||||
|
TEST_F(CtrlDhcpv4SrvTest, commandsRegistration) {
|
||||||
|
|
||||||
|
ConstElementPtr list_cmds = createCommand("list-commands");
|
||||||
|
ConstElementPtr answer;
|
||||||
|
|
||||||
|
// By default the list should be empty (except the standard list-commands
|
||||||
|
// supported by the CommandMgr itself)
|
||||||
|
EXPECT_NO_THROW(answer = CommandMgr::instance().processCommand(list_cmds));
|
||||||
|
ASSERT_TRUE(answer);
|
||||||
|
ASSERT_TRUE(answer->get("arguments"));
|
||||||
|
EXPECT_EQ("[ \"list-commands\" ]", answer->get("arguments")->str());
|
||||||
|
|
||||||
|
// Created server should register several additional commands.
|
||||||
|
boost::scoped_ptr<ControlledDhcpv4Srv> srv;
|
||||||
|
ASSERT_NO_THROW(
|
||||||
|
srv.reset(new ControlledDhcpv4Srv(0));
|
||||||
|
);
|
||||||
|
|
||||||
|
EXPECT_NO_THROW(answer = CommandMgr::instance().processCommand(list_cmds));
|
||||||
|
ASSERT_TRUE(answer);
|
||||||
|
ASSERT_TRUE(answer->get("arguments"));
|
||||||
|
EXPECT_EQ("[ \"list-commands\", \"shutdown\" ]", answer->get("arguments")->str());
|
||||||
|
|
||||||
|
// Ok, and now delete the server. It should deregister its commands.
|
||||||
|
srv.reset();
|
||||||
|
|
||||||
|
// The list should be (almost) empty again.
|
||||||
|
EXPECT_NO_THROW(answer = CommandMgr::instance().processCommand(list_cmds));
|
||||||
|
ASSERT_TRUE(answer);
|
||||||
|
ASSERT_TRUE(answer->get("arguments"));
|
||||||
|
EXPECT_EQ("[ \"list-commands\" ]", answer->get("arguments")->str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if the server is able to parse control socket configuration and
|
||||||
|
// configures the command socket properly.
|
||||||
|
TEST_F(CtrlDhcpv4SrvTest, commandSocketBasic) {
|
||||||
|
|
||||||
|
string socket_path = string(TEST_DATA_DIR) + "/kea4.sock";
|
||||||
|
|
||||||
|
// Just a simple config. The important part here is the socket
|
||||||
|
// location information.
|
||||||
|
std::string config_txt =
|
||||||
|
"{"
|
||||||
|
" \"interfaces-config\": {"
|
||||||
|
" \"interfaces\": [ \"*\" ]"
|
||||||
|
" },"
|
||||||
|
" \"rebind-timer\": 2000, "
|
||||||
|
" \"renew-timer\": 1000, "
|
||||||
|
" \"subnet4\": [ ],"
|
||||||
|
" \"valid-lifetime\": 4000,"
|
||||||
|
" \"control-socket\": {"
|
||||||
|
" \"socket-type\": \"unix\","
|
||||||
|
" \"socket-name\": \"" + socket_path + "\""
|
||||||
|
" }"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
boost::scoped_ptr<ControlledDhcpv4Srv> srv;
|
||||||
|
ASSERT_NO_THROW(
|
||||||
|
srv.reset(new ControlledDhcpv4Srv(0));
|
||||||
|
);
|
||||||
|
|
||||||
|
ConstElementPtr config = Element::fromJSON(config_txt);
|
||||||
|
|
||||||
|
ConstElementPtr answer = srv->processConfig(config);
|
||||||
|
ASSERT_TRUE(answer);
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
isc::config::parseAnswer(status, answer);
|
||||||
|
EXPECT_EQ(0, status);
|
||||||
|
|
||||||
|
// Now check that the socket was indeed open.
|
||||||
|
EXPECT_TRUE(isc::config::CommandMgr::instance().getControlSocketFD() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @todo: Implement system tests for the control socket.
|
||||||
|
/// It is tricky in unit-tests, as it would require running two processes
|
||||||
|
/// (one for the server itself and a second one for the test that sends
|
||||||
|
/// command and receives an aswer).
|
||||||
|
///
|
||||||
|
/// Alternatively, we could use shell tests. It would be much simpler,
|
||||||
|
/// but that requires using socat, a tool that is typically not installed.
|
||||||
|
/// So we'd need a check in configure to check if it's available and
|
||||||
|
/// fail configure process if missing (or disable the tests).
|
||||||
|
|
||||||
} // End of anonymous namespace
|
} // End of anonymous namespace
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <asiolink/io_address.h>
|
#include <asiolink/io_address.h>
|
||||||
#include <cc/command_interpreter.h>
|
#include <cc/command_interpreter.h>
|
||||||
|
#include <config/command_mgr.h>
|
||||||
#include <dhcp4/tests/dhcp4_test_utils.h>
|
#include <dhcp4/tests/dhcp4_test_utils.h>
|
||||||
#include <dhcp/tests/pkt_captures.h>
|
#include <dhcp/tests/pkt_captures.h>
|
||||||
#include <dhcp/dhcp4.h>
|
#include <dhcp/dhcp4.h>
|
||||||
@@ -56,6 +57,7 @@ using namespace isc::dhcp;
|
|||||||
using namespace isc::data;
|
using namespace isc::data;
|
||||||
using namespace isc::asiolink;
|
using namespace isc::asiolink;
|
||||||
using namespace isc::hooks;
|
using namespace isc::hooks;
|
||||||
|
using namespace isc::config;
|
||||||
using namespace isc::dhcp::test;
|
using namespace isc::dhcp::test;
|
||||||
using namespace isc::test;
|
using namespace isc::test;
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ CommandMgr::CommandMgr() {
|
|||||||
boost::bind(&CommandMgr::listCommandsHandler, this, _1, _2));
|
boost::bind(&CommandMgr::listCommandsHandler, this, _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
int CommandMgr::openCtrlSocket(const isc::data::ConstElementPtr& socket_info) {
|
int CommandMgr::openCommandSocket(const isc::data::ConstElementPtr& socket_info) {
|
||||||
if (socket_info_) {
|
if (socket_info_) {
|
||||||
isc_throw(SocketError, "There is already a control socket open");
|
isc_throw(SocketError, "There is already a control socket open");
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ int CommandMgr::openCtrlSocket(const isc::data::ConstElementPtr& socket_info) {
|
|||||||
return (socket_);
|
return (socket_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandMgr::closeCtrlSocket() {
|
void CommandMgr::closeCommandSocket() {
|
||||||
if (socket_info_) {
|
if (socket_info_) {
|
||||||
|
|
||||||
isc::dhcp::IfaceMgr::instance().deleteExternalSocket(socket_);
|
isc::dhcp::IfaceMgr::instance().deleteExternalSocket(socket_);
|
||||||
@@ -125,6 +125,10 @@ CommandMgr::connectionAcceptor(int sockfd) {
|
|||||||
isc::dhcp::IfaceMgr::instance().addExternalSocket(fd2,
|
isc::dhcp::IfaceMgr::instance().addExternalSocket(fd2,
|
||||||
boost::bind(&isc::config::CommandMgr::commandReader, fd2));
|
boost::bind(&isc::config::CommandMgr::commandReader, fd2));
|
||||||
|
|
||||||
|
// Remember this socket descriptor. It will be needed when we shut down the
|
||||||
|
// server.
|
||||||
|
instance().connections_.push_back(fd2);
|
||||||
|
|
||||||
LOG_INFO(command_logger, COMMAND_SOCKET_CONNECTION_OPENED).arg(fd2).arg(sockfd);
|
LOG_INFO(command_logger, COMMAND_SOCKET_CONNECTION_OPENED).arg(fd2).arg(sockfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +145,9 @@ CommandMgr::commandReader(int sockfd) {
|
|||||||
if (rval < 0) {
|
if (rval < 0) {
|
||||||
// Read failed
|
// Read failed
|
||||||
LOG_WARN(command_logger, COMMAND_SOCKET_READ_FAIL).arg(rval).arg(sockfd);
|
LOG_WARN(command_logger, COMMAND_SOCKET_READ_FAIL).arg(rval).arg(sockfd);
|
||||||
|
|
||||||
|
/// @todo: Should we close the connection, similar to what is already
|
||||||
|
/// being done for rval == 0?
|
||||||
return;
|
return;
|
||||||
} else if (rval == 0) {
|
} else if (rval == 0) {
|
||||||
|
|
||||||
@@ -154,6 +161,10 @@ CommandMgr::commandReader(int sockfd) {
|
|||||||
|
|
||||||
// Close the socket.
|
// Close the socket.
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
|
|
||||||
|
// Remove it from the active connections list.
|
||||||
|
instance().connections_.remove(sockfd);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -92,14 +92,17 @@ public:
|
|||||||
/// Currently supported types are:
|
/// Currently supported types are:
|
||||||
/// - unix (required parameters: socket-type: unix, socket-name:/unix/path)
|
/// - unix (required parameters: socket-type: unix, socket-name:/unix/path)
|
||||||
///
|
///
|
||||||
/// @throw CommandSocketError if socket creation fails
|
/// This method will close previously open command socket (if exists).
|
||||||
|
///
|
||||||
|
/// @throw CommandSocketError if socket creation fails.
|
||||||
|
/// @throw SocketError if command socket is already open.
|
||||||
///
|
///
|
||||||
/// @param socket_info describes control socket parameters
|
/// @param socket_info describes control socket parameters
|
||||||
/// @return socket descriptor of the socket created
|
/// @return socket descriptor of the socket created
|
||||||
int openCtrlSocket(const isc::data::ConstElementPtr& socket_info);
|
int openCommandSocket(const isc::data::ConstElementPtr& socket_info);
|
||||||
|
|
||||||
/// @brief Shuts down any open control sockets
|
/// @brief Shuts down any open control sockets
|
||||||
void closeCtrlSocket();
|
void closeCommandSocket();
|
||||||
|
|
||||||
/// @brief Registers specified command handler for a given command
|
/// @brief Registers specified command handler for a given command
|
||||||
///
|
///
|
||||||
@@ -147,6 +150,14 @@ public:
|
|||||||
/// handled at all times.
|
/// handled at all times.
|
||||||
void deregisterAll();
|
void deregisterAll();
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Returns control socket descriptor
|
||||||
|
///
|
||||||
|
/// This method should be used only in tests.
|
||||||
|
int getControlSocketFD() const {
|
||||||
|
return (socket_);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// @brief Private constructor
|
/// @brief Private constructor
|
||||||
@@ -175,6 +186,9 @@ private:
|
|||||||
|
|
||||||
/// @brief Parameters for control socket
|
/// @brief Parameters for control socket
|
||||||
isc::data::ConstElementPtr socket_info_;
|
isc::data::ConstElementPtr socket_info_;
|
||||||
|
|
||||||
|
/// @brief Socket descriptors for open connections
|
||||||
|
std::list<int> connections_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // end of isc::config namespace
|
}; // end of isc::config namespace
|
||||||
|
@@ -2,6 +2,7 @@ SUBDIRS = testdata .
|
|||||||
|
|
||||||
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
||||||
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||||
|
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
|
||||||
|
|
||||||
AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
||||||
|
|
||||||
|
@@ -32,13 +32,13 @@ public:
|
|||||||
handler_called = false;
|
handler_called = false;
|
||||||
|
|
||||||
CommandMgr::instance().deregisterAll();
|
CommandMgr::instance().deregisterAll();
|
||||||
CommandMgr::instance().closeCtrlSocket();
|
CommandMgr::instance().closeCommandSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default destructor
|
/// Default destructor
|
||||||
~CommandMgrTest() {
|
~CommandMgrTest() {
|
||||||
CommandMgr::instance().deregisterAll();
|
CommandMgr::instance().deregisterAll();
|
||||||
CommandMgr::instance().closeCtrlSocket();
|
CommandMgr::instance().closeCommandSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief A simple command handler that always returns an eror
|
/// @brief A simple command handler that always returns an eror
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#include <cc/data.h>
|
#include <cc/data.h>
|
||||||
#include <config/command_mgr.h>
|
#include <config/command_mgr.h>
|
||||||
#include <config/command_socket_factory.h>
|
#include <config/command_socket_factory.h>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
using namespace isc::config;
|
using namespace isc::config;
|
||||||
using namespace isc::data;
|
using namespace isc::data;
|
||||||
@@ -27,18 +28,22 @@ public:
|
|||||||
|
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
CommandSocketFactoryTest() {
|
CommandSocketFactoryTest() {
|
||||||
unlink(SOCKET_NAME);
|
// Remove any stale socket files
|
||||||
|
remove(SOCKET_NAME.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default destructor
|
/// Default destructor
|
||||||
~CommandSocketFactoryTest() {
|
~CommandSocketFactoryTest() {
|
||||||
unlink(SOCKET_NAME);
|
|
||||||
|
// Remove any stale socket files
|
||||||
|
remove(SOCKET_NAME.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* SOCKET_NAME;
|
static const std::string SOCKET_NAME;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* CommandSocketFactoryTest::SOCKET_NAME = "test-socket";
|
const std::string CommandSocketFactoryTest::SOCKET_NAME =
|
||||||
|
std::string(TEST_DATA_DIR) + "/test-socket";
|
||||||
|
|
||||||
TEST_F(CommandSocketFactoryTest, unixCreate) {
|
TEST_F(CommandSocketFactoryTest, unixCreate) {
|
||||||
// Null pointer is obviously a bad idea.
|
// Null pointer is obviously a bad idea.
|
||||||
@@ -67,3 +72,4 @@ TEST_F(CommandSocketFactoryTest, unixCreate) {
|
|||||||
// It should be possible to close the socket.
|
// It should be possible to close the socket.
|
||||||
EXPECT_NO_THROW(CommandSocketFactory::close(fd, socket_info));
|
EXPECT_NO_THROW(CommandSocketFactory::close(fd, socket_info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -214,6 +214,27 @@ MACSourcesListConfigParser::commit() {
|
|||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ******************** ControlSocketParser *************************
|
||||||
|
ControlSocketParser::ControlSocketParser(const std::string& param_name) {
|
||||||
|
if (param_name != "control-socket") {
|
||||||
|
isc_throw(BadValue, "Internal error. Control socket parser called "
|
||||||
|
" for wrong parameter:" << param_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSocketParser::build(isc::data::ConstElementPtr value) {
|
||||||
|
if (value->getType() != Element::map) {
|
||||||
|
isc_throw(BadValue, "Specified control-socket is expected to be a map"
|
||||||
|
", i.e. a structure defined within { }");
|
||||||
|
}
|
||||||
|
CfgMgr::instance().getStagingCfg()->setControlSocketInfo(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Does nothing.
|
||||||
|
void ControlSocketParser::commit() {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
// ******************** HooksLibrariesParser *************************
|
// ******************** HooksLibrariesParser *************************
|
||||||
|
|
||||||
HooksLibrariesParser::HooksLibrariesParser(const std::string& param_name)
|
HooksLibrariesParser::HooksLibrariesParser(const std::string& param_name)
|
||||||
|
@@ -420,6 +420,23 @@ private:
|
|||||||
ParserContextPtr global_context_;
|
ParserContextPtr global_context_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief Parser for the control-socket structure
|
||||||
|
///
|
||||||
|
/// It does not parse anything, simply stores the element in
|
||||||
|
/// the staging config.
|
||||||
|
class ControlSocketParser : public DhcpConfigParser {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ControlSocketParser(const std::string& param_name);
|
||||||
|
|
||||||
|
/// @brief Stores contents of the control-socket map in the staging config.
|
||||||
|
///
|
||||||
|
/// @param value pointer to the content of parsed values
|
||||||
|
virtual void build(isc::data::ConstElementPtr value);
|
||||||
|
|
||||||
|
/// @brief Does nothing.
|
||||||
|
virtual void commit();
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief Parser for hooks library list
|
/// @brief Parser for hooks library list
|
||||||
///
|
///
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include <dhcpsrv/cfg_subnets6.h>
|
#include <dhcpsrv/cfg_subnets6.h>
|
||||||
#include <dhcpsrv/cfg_mac_source.h>
|
#include <dhcpsrv/cfg_mac_source.h>
|
||||||
#include <dhcpsrv/logging_info.h>
|
#include <dhcpsrv/logging_info.h>
|
||||||
|
#include <cc/data.h>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -276,6 +277,18 @@ public:
|
|||||||
return (cfg_mac_source_);
|
return (cfg_mac_source_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Returns information about control socket
|
||||||
|
/// @return pointer to the Element that holds control-socket map
|
||||||
|
const isc::data::ConstElementPtr getControlSocketInfo() const {
|
||||||
|
return (control_socket_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Sets information about the control socket
|
||||||
|
/// @param control_socket Element that holds control-socket map
|
||||||
|
void setControlSocketInfo(const isc::data::ConstElementPtr& control_socket) {
|
||||||
|
control_socket_ = control_socket;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Copies the currnet configuration to a new configuration.
|
/// @brief Copies the currnet configuration to a new configuration.
|
||||||
///
|
///
|
||||||
/// This method copies the parameters stored in the configuration to
|
/// This method copies the parameters stored in the configuration to
|
||||||
@@ -396,6 +409,9 @@ private:
|
|||||||
/// This object holds a set of RSOO-enabled options. See
|
/// This object holds a set of RSOO-enabled options. See
|
||||||
/// RFC 6422 for the definition of the RSOO-enabled option.
|
/// RFC 6422 for the definition of the RSOO-enabled option.
|
||||||
CfgRSOOPtr cfg_rsoo_;
|
CfgRSOOPtr cfg_rsoo_;
|
||||||
|
|
||||||
|
/// @brief Pointer to the control-socket information
|
||||||
|
isc::data::ConstElementPtr control_socket_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @name Pointers to the @c SrvConfig object.
|
/// @name Pointers to the @c SrvConfig object.
|
||||||
|
@@ -1757,3 +1757,7 @@ TEST_F(ParseConfigTest, validRelayInfo6) {
|
|||||||
// Unparseable text that looks like IPv6 address, but has too many colons
|
// Unparseable text that looks like IPv6 address, but has too many colons
|
||||||
EXPECT_THROW(parser->build(json_bogus2), DhcpConfigError);
|
EXPECT_THROW(parser->build(json_bogus2), DhcpConfigError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There's no test for ControlSocketParser, as it is tested in the DHCPv4 code
|
||||||
|
// (see CtrlDhcpv4SrvTest.commandSocketBasic in
|
||||||
|
// src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc).
|
||||||
|
Reference in New Issue
Block a user