% CTRL_AGENT_HTTP_SERVICE_REUSED reused HTTP service bound to address %1:%2
This informational message indicates that the server has reused existing
-HTTPS service on the specified address and port.
+HTTP service on the specified address and port.
% CTRL_AGENT_HTTP_SERVICE_STARTED HTTP service bound to address %1:%2
This informational message indicates that the server has started HTTP service
// Search for the specific connection and reuse the existing one if found.
auto it = sockets_.find(std::make_pair(server_address, server_port));
if (it != sockets_.end()) {
- auto listener = getHttpListener();
+ auto listener = it->second->listener_;
if (listener) {
// Reconfig keeping the same address and port.
if (listener->getTlsContext()) {
- LOG_INFO(agent_logger, CTRL_AGENT_HTTPS_SERVICE_REUSED)
- .arg(server_address.toText())
- .arg(server_port);
- } else {
+ if (ctx->getTrustAnchor().empty()) {
+ // Can not switch from HTTPS to HTTP
+ LOG_INFO(agent_logger, CTRL_AGENT_HTTPS_SERVICE_REUSED)
+ .arg(server_address.toText())
+ .arg(server_port);
+ } else {
+ // Apply TLS settings each time.
+ TlsContextPtr tls_context;
+ TlsContext::configure(tls_context,
+ TlsRole::SERVER,
+ ctx->getTrustAnchor(),
+ ctx->getCertFile(),
+ ctx->getKeyFile(),
+ ctx->getCertRequired());
+ // Overwrite the authentication setup and the http headers in the response creator config.
+ it->second->config_->setAuthConfig(ctx->getAuthConfig());
+ it->second->config_->setHttpHeaders(ctx->getHttpHeaders());
+ getIOService()->post([listener, tls_context]() { listener->setTlsContext(tls_context); });
+ }
+ } else if (!ctx->getTrustAnchor().empty()) {
+ // Can not switch from HTTP to HTTPS
LOG_INFO(agent_logger, CTRL_AGENT_HTTP_SERVICE_REUSED)
.arg(server_address.toText())
.arg(server_port);
AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
AM_CPPFLAGS += -DCFG_EXAMPLES=\"$(abs_top_srcdir)/doc/examples/agent\"
AM_CPPFLAGS += -DSYNTAX_FILE=\"$(abs_srcdir)/../agent_parser.yy\"
+AM_CPPFLAGS += -DTEST_CA_DIR=\"$(abs_top_srcdir)/src/lib/asiolink/testutils/ca\"
AM_CXXFLAGS = $(KEA_CXXFLAGS)
#include <unistd.h>
+using namespace isc::asiolink;
using namespace isc::asiolink::test;
using namespace isc::agent;
using namespace isc::data;
// Tests that it is possible to update the configuration in such a way that the
// listener configuration remains the same. The server should continue using the
// listener instance it has been using prior to the reconfiguration.
-TEST_F(CtrlAgentControllerTest, noListenerChange) {
+TEST_F(CtrlAgentControllerTest, noListenerChangeHttp) {
// This configuration should be used to override the initial configuration.
const char* second_config =
"{"
" }"
"}";
+ const HttpListener* listener_ptr = 0;
+
// This check callback is called before the shutdown.
auto check_callback = [&] {
CtrlAgentProcessPtr process = getCtrlAgentProcess();
// Check that the HTTP listener still exists after reconfiguration.
ConstHttpListenerPtr listener = process->getHttpListener();
ASSERT_TRUE(listener);
+ ASSERT_EQ(listener_ptr, listener.get());
+ ASSERT_FALSE(listener->getTlsContext());
EXPECT_TRUE(process->isListening());
EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
// Schedule SIGHUP signal to trigger reconfiguration.
TimedSignal sighup(getIOService(), SIGHUP, 200);
+ IntervalTimer timer(getIOService());
+ timer.setup([&] {
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_TRUE(listener);
+ listener_ptr = listener.get();
+ ASSERT_FALSE(listener->getTlsContext());
+ }, 50, IntervalTimer::ONE_SHOT);
+
+ // Start the server.
+ time_duration elapsed_time;
+ runWithConfig(valid_agent_config, 500,
+ static_cast<const TestCallback&>(check_callback),
+ elapsed_time);
+
+ CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
+ ASSERT_TRUE(ctx);
+
+ // The server should use a correct listener configuration.
+ EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
+ EXPECT_EQ(8081, ctx->getHttpPort());
+
+ // The forwarding configuration should have been updated.
+ testUnixSocketInfo("dhcp4", "/second/dhcp4/socket");
+ testUnixSocketInfo("dhcp6", "/second/dhcp6/socket");
+
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_FALSE(listener);
+ EXPECT_FALSE(process->isListening());
+}
+
+// Tests that it is possible to update the configuration in such a way that the
+// listener configuration remains the same. The server should continue using the
+// listener instance it has been using prior to the reconfiguration.
+TEST_F(CtrlAgentControllerTest, noListenerChangeHttps) {
+ // This configuration should be used to override the initial configuration.
+ string ca_dir(string(TEST_CA_DIR));
+ ostringstream agent_st;
+ agent_st << "{"
+ << " \"http-host\": \"127.0.0.1\","
+ << " \"http-port\": 8081,"
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << " \"control-sockets\": {"
+ << " \"dhcp4\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/first/dhcp4/socket\""
+ << " },"
+ << " \"dhcp6\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/first/dhcp6/socket\""
+ << " }"
+ << " }"
+ << "}";
+
+ ostringstream second_config_st;
+ second_config_st << "{"
+ << " \"http-host\": \"127.0.0.1\","
+ << " \"http-port\": 8081,"
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << " \"control-sockets\": {"
+ << " \"dhcp4\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/second/dhcp4/socket\""
+ << " },"
+ << " \"dhcp6\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/second/dhcp6/socket\""
+ << " }"
+ << " }"
+ << "}";
+
+ const HttpListener* listener_ptr = 0;
+ TlsContext* context = 0;
+
+ // This check callback is called before the shutdown.
+ auto check_callback = [&] {
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+
+ // Check that the HTTP listener still exists after reconfiguration.
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_TRUE(listener);
+ ASSERT_EQ(listener_ptr, listener.get());
+ ASSERT_TRUE(listener->getTlsContext());
+ // The TLS settings have been applied
+ ASSERT_NE(context, listener->getTlsContext().get());
+ EXPECT_TRUE(process->isListening());
+
+ EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
+ EXPECT_EQ(8081, listener->getLocalPort());
+ };
+
+ // Schedule reconfiguration.
+ scheduleTimedWrite(second_config_st.str(), 100);
+ // Schedule SIGHUP signal to trigger reconfiguration.
+ TimedSignal sighup(getIOService(), SIGHUP, 200);
+
+ IntervalTimer timer(getIOService());
+ timer.setup([&] {
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_TRUE(listener);
+ listener_ptr = listener.get();
+ ASSERT_TRUE(listener->getTlsContext());
+ context = listener->getTlsContext().get();
+ }, 50, IntervalTimer::ONE_SHOT);
+
+ // Start the server.
+ time_duration elapsed_time;
+ runWithConfig(agent_st.str(), 500,
+ static_cast<const TestCallback&>(check_callback),
+ elapsed_time);
+
+ CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
+ ASSERT_TRUE(ctx);
+
+ // The server should use a correct listener configuration.
+ EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
+ EXPECT_EQ(8081, ctx->getHttpPort());
+
+ // The forwarding configuration should have been updated.
+ testUnixSocketInfo("dhcp4", "/second/dhcp4/socket");
+ testUnixSocketInfo("dhcp6", "/second/dhcp6/socket");
+
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_FALSE(listener);
+ EXPECT_FALSE(process->isListening());
+}
+
+// Verify that the reload will reuse listener
+TEST_F(CtrlAgentControllerTest, ignoreHttpToHttpsSwitch) {
+ string ca_dir(string(TEST_CA_DIR));
+
+ // This configuration should be used to override the initial configuration.
+ ostringstream second_config_st;
+ second_config_st << "{"
+ << " \"http-host\": \"127.0.0.1\","
+ << " \"http-port\": 8081,"
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << " \"control-sockets\": {"
+ << " \"dhcp4\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/second/dhcp4/socket\""
+ << " },"
+ << " \"dhcp6\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/second/dhcp6/socket\""
+ << " }"
+ << " }"
+ << "}";
+
+ const HttpListener* listener_ptr = 0;
+
+ // This check callback is called before the shutdown.
+ auto check_callback = [&] {
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+
+ // Check that the HTTP listener still exists after reconfiguration.
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_TRUE(listener);
+ ASSERT_EQ(listener_ptr, listener.get());
+ ASSERT_FALSE(listener->getTlsContext());
+ EXPECT_TRUE(process->isListening());
+
+ EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
+ EXPECT_EQ(8081, listener->getLocalPort());
+ };
+
+ // Schedule reconfiguration.
+ scheduleTimedWrite(second_config_st.str(), 100);
+ // Schedule SIGHUP signal to trigger reconfiguration.
+ TimedSignal sighup(getIOService(), SIGHUP, 200);
+
+ IntervalTimer timer(getIOService());
+ timer.setup([&] {
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_TRUE(listener);
+ listener_ptr = listener.get();
+ ASSERT_FALSE(listener->getTlsContext());
+ }, 50, IntervalTimer::ONE_SHOT);
+
// Start the server.
time_duration elapsed_time;
runWithConfig(valid_agent_config, 500,
EXPECT_FALSE(process->isListening());
}
+// Verify that the reload will reuse listener
+TEST_F(CtrlAgentControllerTest, ignoreHttpsToHttpSwitch) {
+ string ca_dir(string(TEST_CA_DIR));
+ ostringstream agent_st;
+ agent_st << "{"
+ << " \"http-host\": \"127.0.0.1\","
+ << " \"http-port\": 8081,"
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << " \"control-sockets\": {"
+ << " \"dhcp4\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/first/dhcp4/socket\""
+ << " },"
+ << " \"dhcp6\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/first/dhcp6/socket\""
+ << " }"
+ << " }"
+ << "}";
+
+ // This configuration should be used to override the initial configuration.
+ ostringstream second_config_st;
+ second_config_st << "{"
+ << " \"http-host\": \"127.0.0.1\","
+ << " \"http-port\": 8081,"
+ << " \"control-sockets\": {"
+ << " \"dhcp4\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/second/dhcp4/socket\""
+ << " },"
+ << " \"dhcp6\": {"
+ << " \"socket-type\": \"unix\","
+ << " \"socket-name\": \"/second/dhcp6/socket\""
+ << " }"
+ << " }"
+ << "}";
+
+ const HttpListener* listener_ptr = 0;
+ TlsContext* context = 0;
+
+ // This check callback is called before the shutdown.
+ auto check_callback = [&] {
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+
+ // Check that the HTTP listener still exists after reconfiguration.
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_TRUE(listener);
+ ASSERT_EQ(listener_ptr, listener.get());
+ ASSERT_TRUE(listener->getTlsContext());
+ // The TLS settings have not changed
+ ASSERT_EQ(context, listener->getTlsContext().get());
+ EXPECT_TRUE(process->isListening());
+
+ EXPECT_EQ("127.0.0.1", listener->getLocalAddress().toText());
+ EXPECT_EQ(8081, listener->getLocalPort());
+ };
+
+ // Schedule reconfiguration.
+ scheduleTimedWrite(second_config_st.str(), 100);
+ // Schedule SIGHUP signal to trigger reconfiguration.
+ TimedSignal sighup(getIOService(), SIGHUP, 200);
+
+ IntervalTimer timer(getIOService());
+ timer.setup([&] {
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_TRUE(listener);
+ listener_ptr = listener.get();
+ ASSERT_TRUE(listener->getTlsContext());
+ context = listener->getTlsContext().get();
+ }, 50, IntervalTimer::ONE_SHOT);
+
+ // Start the server.
+ time_duration elapsed_time;
+ runWithConfig(agent_st.str(), 500,
+ static_cast<const TestCallback&>(check_callback),
+ elapsed_time);
+
+ CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
+ ASSERT_TRUE(ctx);
+
+ // The server should use a correct listener configuration.
+ EXPECT_EQ("127.0.0.1", ctx->getHttpHost());
+ EXPECT_EQ(8081, ctx->getHttpPort());
+
+ // The forwarding configuration should have been updated.
+ testUnixSocketInfo("dhcp4", "/second/dhcp4/socket");
+ testUnixSocketInfo("dhcp6", "/second/dhcp6/socket");
+
+ CtrlAgentProcessPtr process = getCtrlAgentProcess();
+ ASSERT_TRUE(process);
+ ConstHttpListenerPtr listener = process->getHttpListener();
+ ASSERT_FALSE(listener);
+ EXPECT_FALSE(process->isListening());
+}
+
// Tests that registerCommands actually registers anything.
TEST_F(CtrlAgentControllerTest, registeredCommands) {
ASSERT_NO_THROW(initProcess());
ConstElementPtr http_config =
getD2CfgMgr()->getHttpControlSocketInfo();
- sock_changed = (http_config && current_http_control_socket_ &&
- !http_config->equals(*current_http_control_socket_));
-
- if (!http_config || !current_http_control_socket_ || sock_changed) {
- // Open the new sockets and close old ones, keeping reused.
- if (http_config) {
- HttpCommandMgr::instance().openCommandSockets(http_config);
- } else if (current_http_control_socket_) {
- HttpCommandMgr::instance().closeCommandSockets();
- }
+ // Open the new sockets and close old ones, keeping reused.
+ if (http_config) {
+ HttpCommandMgr::instance().openCommandSockets(http_config);
+ } else if (current_http_control_socket_) {
+ HttpCommandMgr::instance().closeCommandSockets();
}
// Commit the new socket configuration.
ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
// Create a config with invalid content that should fail to parse.
- string config_test_txt =
+ string config_set_txt =
"{ \"command\": \"config-set\", \n"
" \"arguments\": { \n"
" \"DhcpDdns\": \n"
// Send the config-set command.
string response;
- sendHttpCommand(config_test_txt, response);
+ sendHttpCommand(config_set_txt, response);
// Should fail with a syntax error.
EXPECT_EQ("[ { \"result\": 1, \"text\": \"missing parameter 'name' (<string>:10:14)\" } ]",
EXPECT_EQ(1, keys->size());
// Create a valid config with two keys and no command channel.
- config_test_txt =
+ config_set_txt =
"{ \"command\": \"config-set\", \n"
" \"arguments\": { \n"
" \"DhcpDdns\": \n"
EXPECT_TRUE(HttpCommandMgr::instance().getHttpListener());
// Send the config-set command.
- sendHttpCommand(config_test_txt, response);
+ sendHttpCommand(config_set_txt, response);
// Verify the HTTP control channel socket no longer exists.
ASSERT_NO_THROW(HttpCommandMgr::instance().closeCommandSockets());
ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
// Create a config with invalid content that should fail to parse.
- string config_test_txt =
+ string config_set_txt =
"{ \"command\": \"config-set\", \n"
" \"arguments\": { \n"
" \"DhcpDdns\": \n"
// Send the config-set command.
string response;
- sendHttpCommand(config_test_txt, response);
+ sendHttpCommand(config_set_txt, response);
// Should fail with a syntax error.
EXPECT_EQ("[ { \"result\": 1, \"text\": \"missing parameter 'name' (<string>:10:14)\" } ]",
EXPECT_EQ(1, keys->size());
// Create a valid config with two keys and no command channel.
- config_test_txt =
+ config_set_txt =
"{ \"command\": \"config-set\", \n"
" \"arguments\": { \n"
" \"DhcpDdns\": \n"
EXPECT_TRUE(HttpCommandMgr::instance().getHttpListener());
// Send the config-set command.
- sendHttpCommand(config_test_txt, response);
+ sendHttpCommand(config_set_txt, response);
// Verify the HTTP control channel socket no longer exists.
ASSERT_NO_THROW(HttpCommandMgr::instance().closeCommandSockets());
testConnectionTimeoutNoData();
}
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpCtrlChannelD2Test, noListenerChange) {
+
+ string d2_cfg_txt =
+ " { \n"
+ " \"ip-address\": \"192.168.77.1\", \n"
+ " \"port\": 777, \n"
+ " \"forward-ddns\" : {}, \n"
+ " \"reverse-ddns\" : {}, \n"
+ " \"tsig-keys\": [ \n"
+ " {\"name\": \"d2_key.example.com\", \n"
+ " \"algorithm\": \"hmac-md5\", \n"
+ " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\"} \n"
+ " ], \n"
+ " \"control-socket\": { \n"
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"127.0.0.1\", \n"
+ " \"socket-port\": 18125 \n"
+ " } \n"
+ " } \n";
+
+ ASSERT_TRUE(server_);
+
+ ConstElementPtr config;
+ ASSERT_NO_THROW(config = parseDHCPDDNS(d2_cfg_txt, true));
+ ASSERT_NO_THROW(d2Controller()->initProcess());
+ D2ProcessPtr proc = d2Controller()->getProcess();
+ ASSERT_TRUE(proc);
+ ConstElementPtr answer = proc->configure(config, false);
+ ASSERT_TRUE(answer);
+ EXPECT_EQ("{ \"arguments\": { \"hash\": \"029AE1208415D6911B5651A6F82D054F55B7877D2589CFD1DCEB5BFFCD3B13A3\" }, \"result\": 0, \"text\": \"Configuration applied successfully.\" }",
+ answer->str());
+ ASSERT_NO_THROW(d2Controller()->registerCommands());
+
+ // Check that the config was indeed applied.
+ D2CfgMgrPtr cfg_mgr = proc->getD2CfgMgr();
+ ASSERT_TRUE(cfg_mgr);
+ D2CfgContextPtr d2_context = cfg_mgr->getD2CfgContext();
+ ASSERT_TRUE(d2_context);
+ TSIGKeyInfoMapPtr keys = d2_context->getKeys();
+ ASSERT_TRUE(keys);
+ EXPECT_EQ(1, keys->size());
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ // Create a config with same content that should not recreate listener.
+ string config_set_txt =
+ "{ \"command\": \"config-set\", \n"
+ " \"arguments\": { \n"
+ " \"DhcpDdns\": \n";
+
+ config_set_txt += d2_cfg_txt;
+ config_set_txt += "}} \n";
+
+ // Send the config-set command.
+ string response;
+ sendHttpCommand(config_set_txt, response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ // Verify the configuration was successful.
+ EXPECT_EQ("[ { \"arguments\": { \"hash\": \"029AE1208415D6911B5651A6F82D054F55B7877D2589CFD1DCEB5BFFCD3B13A3\" }, \"result\": 0, \"text\": \"Configuration applied successfully.\" } ]",
+ response);
+
+ // Check that the config was applied.
+ d2_context = cfg_mgr->getD2CfgContext();
+ keys = d2_context->getKeys();
+ ASSERT_TRUE(keys);
+ EXPECT_EQ(1, keys->size());
+}
+
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpsCtrlChannelD2Test, noListenerChange) {
+
+ string ca_dir(string(TEST_CA_DIR));
+ ostringstream d2_st;
+ d2_st << " { \n"
+ << " \"ip-address\": \"192.168.77.1\", \n"
+ << " \"port\": 777, \n"
+ << " \"forward-ddns\" : {}, \n"
+ << " \"reverse-ddns\" : {}, \n"
+ << " \"tsig-keys\": [ \n"
+ << " {\"name\": \"d2_key.example.com\", \n"
+ << " \"algorithm\": \"hmac-md5\", \n"
+ << " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\"} \n"
+ << " ], \n"
+ << " \"control-socket\": { \n"
+ << " \"socket-type\": \"https\", \n"
+ << " \"socket-address\": \"127.0.0.1\", \n"
+ << " \"socket-port\": 18125, \n"
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\" \n"
+ << " } \n"
+ << " } \n";
+
+ ASSERT_TRUE(server_);
+
+ ConstElementPtr config;
+ ASSERT_NO_THROW(config = parseDHCPDDNS(d2_st.str(), true));
+ ASSERT_NO_THROW(d2Controller()->initProcess());
+ D2ProcessPtr proc = d2Controller()->getProcess();
+ ASSERT_TRUE(proc);
+ ConstElementPtr answer = proc->configure(config, false);
+ ASSERT_TRUE(answer);
+ // Verify the configuration was successful. The config contains random
+ // file paths (CA directory), so the hash will be different each time.
+ // As such, we can do simplified checks:
+ // - verify the "result": 0 is there
+ // - verify the "text": "Configuration applied successfully." is there
+ string answer_txt = answer->str();
+ EXPECT_NE(answer_txt.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(answer_txt.find("\"text\": \"Configuration applied successfully.\""),
+ std::string::npos);
+ ASSERT_NO_THROW(d2Controller()->registerCommands());
+
+ // Check that the config was indeed applied.
+ D2CfgMgrPtr cfg_mgr = proc->getD2CfgMgr();
+ ASSERT_TRUE(cfg_mgr);
+ D2CfgContextPtr d2_context = cfg_mgr->getD2CfgContext();
+ ASSERT_TRUE(d2_context);
+ TSIGKeyInfoMapPtr keys = d2_context->getKeys();
+ ASSERT_TRUE(keys);
+ EXPECT_EQ(1, keys->size());
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ auto const context = HttpCommandMgr::instance().getHttpListener()->getTlsContext().get();
+
+ // Create a config with same content that should not recreate listener.
+ string config_set_txt =
+ "{ \"command\": \"config-set\", \n"
+ " \"arguments\": { \n"
+ " \"DhcpDdns\": \n";
+
+ config_set_txt += d2_st.str();
+ config_set_txt += "}} \n";
+
+ // Send the config-set command.
+ string response;
+ sendHttpCommand(config_set_txt, response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ // The TLS settings have been applied
+ EXPECT_NE(context, HttpCommandMgr::instance().getHttpListener()->getTlsContext().get());
+
+ // Verify the configuration was successful.
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration applied successfully.\""),
+ std::string::npos);
+
+ // Check that the config was applied.
+ d2_context = cfg_mgr->getD2CfgContext();
+ keys = d2_context->getKeys();
+ ASSERT_TRUE(keys);
+ EXPECT_EQ(1, keys->size());
+}
+
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpCtrlChannelD2Test, ignoreHttpToHttpsSwitch) {
+
+ string d2_cfg_txt =
+ " { \n"
+ " \"ip-address\": \"192.168.77.1\", \n"
+ " \"port\": 777, \n"
+ " \"forward-ddns\" : {}, \n"
+ " \"reverse-ddns\" : {}, \n"
+ " \"tsig-keys\": [ \n"
+ " {\"name\": \"d2_key.example.com\", \n"
+ " \"algorithm\": \"hmac-md5\", \n"
+ " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\"} \n"
+ " ], \n"
+ " \"control-socket\": { \n"
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"127.0.0.1\", \n"
+ " \"socket-port\": 18125 \n"
+ " } \n"
+ " } \n";
+
+ ASSERT_TRUE(server_);
+
+ ConstElementPtr config;
+ ASSERT_NO_THROW(config = parseDHCPDDNS(d2_cfg_txt, true));
+ ASSERT_NO_THROW(d2Controller()->initProcess());
+ D2ProcessPtr proc = d2Controller()->getProcess();
+ ASSERT_TRUE(proc);
+ ConstElementPtr answer = proc->configure(config, false);
+ ASSERT_TRUE(answer);
+ EXPECT_EQ("{ \"arguments\": { \"hash\": \"029AE1208415D6911B5651A6F82D054F55B7877D2589CFD1DCEB5BFFCD3B13A3\" }, \"result\": 0, \"text\": \"Configuration applied successfully.\" }",
+ answer->str());
+ ASSERT_NO_THROW(d2Controller()->registerCommands());
+
+ // Check that the config was indeed applied.
+ D2CfgMgrPtr cfg_mgr = proc->getD2CfgMgr();
+ ASSERT_TRUE(cfg_mgr);
+ D2CfgContextPtr d2_context = cfg_mgr->getD2CfgContext();
+ ASSERT_TRUE(d2_context);
+ TSIGKeyInfoMapPtr keys = d2_context->getKeys();
+ ASSERT_TRUE(keys);
+ EXPECT_EQ(1, keys->size());
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ string ca_dir(string(TEST_CA_DIR));
+ ostringstream d2_st;
+ d2_st << " { \n"
+ << " \"ip-address\": \"192.168.77.1\", \n"
+ << " \"port\": 777, \n"
+ << " \"forward-ddns\" : {}, \n"
+ << " \"reverse-ddns\" : {}, \n"
+ << " \"tsig-keys\": [ \n"
+ << " {\"name\": \"d2_key.example.com\", \n"
+ << " \"algorithm\": \"hmac-md5\", \n"
+ << " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\"} \n"
+ << " ], \n"
+ << " \"control-socket\": { \n"
+ << " \"socket-type\": \"https\", \n"
+ << " \"socket-address\": \"127.0.0.1\", \n"
+ << " \"socket-port\": 18125, \n"
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\" \n"
+ << " } \n"
+ << " } \n";
+
+ // Create a config with HTTPS and same content that should not recreate listener.
+ string config_set_txt =
+ "{ \"command\": \"config-set\", \n"
+ " \"arguments\": { \n"
+ " \"DhcpDdns\": \n";
+
+ config_set_txt += d2_st.str();
+ config_set_txt += "}} \n";
+
+ // Send the config-set command.
+ string response;
+ sendHttpCommand(config_set_txt, response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ // Verify the configuration was successful.
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration applied successfully.\""),
+ std::string::npos);
+
+ // Check that the config was applied.
+ d2_context = cfg_mgr->getD2CfgContext();
+ keys = d2_context->getKeys();
+ ASSERT_TRUE(keys);
+ EXPECT_EQ(1, keys->size());
+}
+
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpsCtrlChannelD2Test, ignoreHttpsToHttpSwitch) {
+
+ string ca_dir(string(TEST_CA_DIR));
+ ostringstream d2_st;
+ d2_st << " { \n"
+ << " \"ip-address\": \"192.168.77.1\", \n"
+ << " \"port\": 777, \n"
+ << " \"forward-ddns\" : {}, \n"
+ << " \"reverse-ddns\" : {}, \n"
+ << " \"tsig-keys\": [ \n"
+ << " {\"name\": \"d2_key.example.com\", \n"
+ << " \"algorithm\": \"hmac-md5\", \n"
+ << " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\"} \n"
+ << " ], \n"
+ << " \"control-socket\": { \n"
+ << " \"socket-type\": \"https\", \n"
+ << " \"socket-address\": \"127.0.0.1\", \n"
+ << " \"socket-port\": 18125, \n"
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\" \n"
+ << " } \n"
+ << " } \n";
+
+ ASSERT_TRUE(server_);
+
+ ConstElementPtr config;
+ ASSERT_NO_THROW(config = parseDHCPDDNS(d2_st.str(), true));
+ ASSERT_NO_THROW(d2Controller()->initProcess());
+ D2ProcessPtr proc = d2Controller()->getProcess();
+ ASSERT_TRUE(proc);
+ ConstElementPtr answer = proc->configure(config, false);
+ ASSERT_TRUE(answer);
+ // Verify the configuration was successful. The config contains random
+ // file paths (CA directory), so the hash will be different each time.
+ // As such, we can do simplified checks:
+ // - verify the "result": 0 is there
+ // - verify the "text": "Configuration applied successfully." is there
+ string answer_txt = answer->str();
+ EXPECT_NE(answer_txt.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(answer_txt.find("\"text\": \"Configuration applied successfully.\""),
+ std::string::npos);
+ ASSERT_NO_THROW(d2Controller()->registerCommands());
+
+ // Check that the config was indeed applied.
+ D2CfgMgrPtr cfg_mgr = proc->getD2CfgMgr();
+ ASSERT_TRUE(cfg_mgr);
+ D2CfgContextPtr d2_context = cfg_mgr->getD2CfgContext();
+ ASSERT_TRUE(d2_context);
+ TSIGKeyInfoMapPtr keys = d2_context->getKeys();
+ ASSERT_TRUE(keys);
+ EXPECT_EQ(1, keys->size());
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ auto const context = HttpCommandMgr::instance().getHttpListener()->getTlsContext().get();
+
+ string d2_cfg_txt =
+ " { \n"
+ " \"ip-address\": \"192.168.77.1\", \n"
+ " \"port\": 777, \n"
+ " \"forward-ddns\" : {}, \n"
+ " \"reverse-ddns\" : {}, \n"
+ " \"tsig-keys\": [ \n"
+ " {\"name\": \"d2_key.example.com\", \n"
+ " \"algorithm\": \"hmac-md5\", \n"
+ " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\"} \n"
+ " ], \n"
+ " \"control-socket\": { \n"
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"127.0.0.1\", \n"
+ " \"socket-port\": 18125 \n"
+ " } \n"
+ " } \n";
+
+ // Create a config with HTTP and same content that should not recreate listener.
+ string config_set_txt =
+ "{ \"command\": \"config-set\", \n"
+ " \"arguments\": { \n"
+ " \"DhcpDdns\": \n";
+
+ config_set_txt += d2_cfg_txt;
+ config_set_txt += "}} \n";
+
+ // Send the config-set command.
+ string response;
+ sendHttpCommand(config_set_txt, response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ // The TLS settings have not changed
+ EXPECT_EQ(context, HttpCommandMgr::instance().getHttpListener()->getTlsContext().get());
+
+ // Verify the configuration was successful.
+ EXPECT_EQ("[ { \"arguments\": { \"hash\": \"029AE1208415D6911B5651A6F82D054F55B7877D2589CFD1DCEB5BFFCD3B13A3\" }, \"result\": 0, \"text\": \"Configuration applied successfully.\" } ]",
+ response);
+
+ // Check that the config was applied.
+ d2_context = cfg_mgr->getD2CfgContext();
+ keys = d2_context->getKeys();
+ ASSERT_TRUE(keys);
+ EXPECT_EQ(1, keys->size());
+}
+
} // end of anonymous namespace
ConstElementPtr current_http_config =
CfgMgr::instance().getCurrentCfg()->getHttpControlSocketInfo();
- sock_changed = (http_config && current_http_config &&
- !http_config->equals(*current_http_config));
-
- if (!http_config || !current_http_config || sock_changed) {
- if (http_config) {
- HttpCommandMgr::instance().openCommandSockets(http_config);
- } else if (current_http_config) {
- HttpCommandMgr::instance().closeCommandSockets();
- }
+ if (http_config) {
+ HttpCommandMgr::instance().openCommandSockets(http_config);
+ } else if (current_http_config) {
+ HttpCommandMgr::instance().closeCommandSockets();
}
}
// Define strings to permutate the config arguments
// (Note the line feeds makes errors easy to find)
- string set_config_txt = "{ \"command\": \"config-set\" \n";
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
string args_txt = " \"arguments\": { \n";
string dhcp4_cfg_txt =
" \"Dhcp4\": { \n"
std::ostringstream os;
// Create a valid config with all the parts should parse
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp4_cfg_txt
<< subnet1
// Create a config with malformed subnet that should fail to parse.
os.str("");
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp4_cfg_txt
<< bad_subnet
// Create a valid config with two subnets and no command channel.
// It should succeed, client should still receive the response
os.str("");
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp4_cfg_txt
<< subnet1
// Define strings to permutate the config arguments
// (Note the line feeds makes errors easy to find)
string ca_dir(string(TEST_CA_DIR));
- string set_config_txt = "{ \"command\": \"config-set\" \n";
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
string args_txt = " \"arguments\": { \n";
string dhcp4_cfg_txt =
" \"Dhcp4\": { \n"
std::ostringstream os;
// Create a valid config with all the parts should parse
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp4_cfg_txt
<< subnet1
// Create a config with malformed subnet that should fail to parse.
os.str("");
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp4_cfg_txt
<< bad_subnet
// Create a valid config with two subnets and no command channel.
// It should succeed, client should still receive the response
os.str("");
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp4_cfg_txt
<< subnet1
// Define strings to permutate the config arguments
// (Note the line feeds makes errors easy to find)
- string set_config_txt = "{ \"command\": \"config-set\" \n";
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
string config_test_txt = "{ \"command\": \"config-test\" \n";
string args_txt = " \"arguments\": { \n";
string dhcp4_cfg_txt =
std::ostringstream os;
// Create a valid config with all the parts should parse
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp4_cfg_txt
<< subnet1
// Define strings to permutate the config arguments
// (Note the line feeds makes errors easy to find)
string ca_dir(string(TEST_CA_DIR));
- string set_config_txt = "{ \"command\": \"config-set\" \n";
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
string config_test_txt = "{ \"command\": \"config-test\" \n";
string args_txt = " \"arguments\": { \n";
string dhcp4_cfg_txt =
std::ostringstream os;
// Create a valid config with all the parts should parse
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp4_cfg_txt
<< subnet1
testConnectionTimeoutNoData();
}
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpCtrlChannelDhcpv4Test, noListenerChange) {
+ createHttpChannelServer();
+
+ // Define strings to permutate the config arguments
+ // (Note the line feeds makes errors easy to find)
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
+ string args_txt = " \"arguments\": { \n";
+ string dhcp4_cfg_txt =
+ " \"Dhcp4\": { \n"
+ " \"interfaces-config\": { \n"
+ " \"interfaces\": [\"*\"] \n"
+ " }, \n"
+ " \"valid-lifetime\": 4000, \n"
+ " \"renew-timer\": 1000, \n"
+ " \"rebind-timer\": 2000, \n"
+ " \"lease-database\": { \n"
+ " \"type\": \"memfile\", \n"
+ " \"persist\":false, \n"
+ " \"lfc-interval\": 0 \n"
+ " }, \n"
+ " \"expired-leases-processing\": { \n"
+ " \"reclaim-timer-wait-time\": 0, \n"
+ " \"hold-reclaimed-time\": 0, \n"
+ " \"flush-reclaimed-timer-wait-time\": 0 \n"
+ " },"
+ " \"subnet4\": [ \n";
+ string subnet1 =
+ " {\"subnet\": \"192.2.0.0/24\", \"id\": 1, \n"
+ " \"pools\": [{ \"pool\": \"192.2.0.1-192.2.0.50\" }]}\n";
+ string subnet_footer =
+ " ] \n";
+ string option_def =
+ " ,\"option-def\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"type\": \"uint32\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"space\": \"dhcp4\",\n"
+ " \"encapsulate\": \"\"\n"
+ " }\n"
+ "]\n";
+ string option_data =
+ " ,\"option-data\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"space\": \"dhcp4\",\n"
+ " \"csv-format\": true,\n"
+ " \"data\": \"12345\"\n"
+ " }\n"
+ "]\n";
+ string control_socket =
+ " ,\"control-socket\": { \n"
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"127.0.0.1\", \n"
+ " \"socket-port\": 18124 \n"
+ " } \n";
+ string logger_txt =
+ " ,\"loggers\": [ { \n"
+ " \"name\": \"kea\", \n"
+ " \"severity\": \"FATAL\", \n"
+ " \"output-options\": [{ \n"
+ " \"output\": \"/dev/null\", \n"
+ " \"maxsize\": 0"
+ " }] \n"
+ " }] \n";
+
+ std::ostringstream os;
+
+ // Create a valid config with all the parts should parse
+ os << config_set_txt << ","
+ << args_txt
+ << dhcp4_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket
+ << logger_txt
+ << "}\n" // close dhcp4
+ << "}}";
+
+ // Send the config-set command
+ std::string response;
+ sendHttpCommand(os.str(), response);
+ EXPECT_EQ("[ { \"arguments\": { \"hash\": \"F6137301FF10D81585E041FD5FD8E91347ACADDE64F92ED03432FB100874DE02\" }, \"result\": 0, \"text\": \"Configuration successful.\" } ]",
+ response);
+
+ // Check that the config was indeed applied.
+ const Subnet4Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ OptionDefinitionPtr def =
+ LibDHCP::getRuntimeOptionDef(DHCP4_OPTION_SPACE, 163);
+ ASSERT_TRUE(def);
+
+ // Verify the HTTP control channel socket exists.
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ // Send the config-set command.
+ sendHttpCommand(os.str(), response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ EXPECT_EQ("[ { \"arguments\": { \"hash\": \"F6137301FF10D81585E041FD5FD8E91347ACADDE64F92ED03432FB100874DE02\" }, \"result\": 0, \"text\": \"Configuration successful.\" } ]",
+ response);
+
+ // Check that the config was not lost
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ // Clean up after the test.
+ CfgMgr::instance().clear();
+}
+
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpsCtrlChannelDhcpv4Test, noListenerChange) {
+ createHttpChannelServer();
+
+ // Define strings to permutate the config arguments
+ // (Note the line feeds makes errors easy to find)
+ string ca_dir(string(TEST_CA_DIR));
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
+ string args_txt = " \"arguments\": { \n";
+ string dhcp4_cfg_txt =
+ " \"Dhcp4\": { \n"
+ " \"interfaces-config\": { \n"
+ " \"interfaces\": [\"*\"] \n"
+ " }, \n"
+ " \"valid-lifetime\": 4000, \n"
+ " \"renew-timer\": 1000, \n"
+ " \"rebind-timer\": 2000, \n"
+ " \"lease-database\": { \n"
+ " \"type\": \"memfile\", \n"
+ " \"persist\":false, \n"
+ " \"lfc-interval\": 0 \n"
+ " }, \n"
+ " \"expired-leases-processing\": { \n"
+ " \"reclaim-timer-wait-time\": 0, \n"
+ " \"hold-reclaimed-time\": 0, \n"
+ " \"flush-reclaimed-timer-wait-time\": 0 \n"
+ " },"
+ " \"subnet4\": [ \n";
+ string subnet1 =
+ " {\"subnet\": \"192.2.0.0/24\", \"id\": 1, \n"
+ " \"pools\": [{ \"pool\": \"192.2.0.1-192.2.0.50\" }]}\n";
+ string subnet_footer =
+ " ] \n";
+ string option_def =
+ " ,\"option-def\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"type\": \"uint32\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"space\": \"dhcp4\",\n"
+ " \"encapsulate\": \"\"\n"
+ " }\n"
+ "]\n";
+ string option_data =
+ " ,\"option-data\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"space\": \"dhcp4\",\n"
+ " \"csv-format\": true,\n"
+ " \"data\": \"12345\"\n"
+ " }\n"
+ "]\n";
+ string control_socket_header =
+ " ,\"control-socket\": { \n";
+ string control_socket_footer =
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"127.0.0.1\", \n"
+ " \"socket-port\": 18124 \n"
+ " } \n";
+ string logger_txt =
+ " ,\"loggers\": [ { \n"
+ " \"name\": \"kea\", \n"
+ " \"severity\": \"FATAL\", \n"
+ " \"output-options\": [{ \n"
+ " \"output\": \"/dev/null\", \n"
+ " \"maxsize\": 0"
+ " }] \n"
+ " }] \n";
+
+ std::ostringstream os;
+
+ // Create a valid config with all the parts should parse
+ os << config_set_txt << ","
+ << args_txt
+ << dhcp4_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp4
+ << "}}";
+
+ // Send the config-set command
+ std::string response;
+ sendHttpCommand(os.str(), response);
+ // Verify the configuration was successful. The config contains random
+ // file paths (CA directory), so the hash will be different each time.
+ // As such, we can do simplified checks:
+ // - verify the "result": 0 is there
+ // - verify the "text": "Configuration successful." is there
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was indeed applied.
+ const Subnet4Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ OptionDefinitionPtr def =
+ LibDHCP::getRuntimeOptionDef(DHCP4_OPTION_SPACE, 163);
+ ASSERT_TRUE(def);
+
+ // Verify the HTTP control channel socket exists.
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ auto const context = HttpCommandMgr::instance().getHttpListener()->getTlsContext().get();
+
+ // Send the config-set command.
+ sendHttpCommand(os.str(), response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ // The TLS settings have been applied
+ EXPECT_NE(context, HttpCommandMgr::instance().getHttpListener()->getTlsContext().get());
+
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was not lost
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ // Clean up after the test.
+ CfgMgr::instance().clear();
+}
+
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpCtrlChannelDhcpv4Test, ignoredHttpToHttpsSwitch) {
+ createHttpChannelServer();
+
+ // Define strings to permutate the config arguments
+ // (Note the line feeds makes errors easy to find)
+ string ca_dir(string(TEST_CA_DIR));
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
+ string args_txt = " \"arguments\": { \n";
+ string dhcp4_cfg_txt =
+ " \"Dhcp4\": { \n"
+ " \"interfaces-config\": { \n"
+ " \"interfaces\": [\"*\"] \n"
+ " }, \n"
+ " \"valid-lifetime\": 4000, \n"
+ " \"renew-timer\": 1000, \n"
+ " \"rebind-timer\": 2000, \n"
+ " \"lease-database\": { \n"
+ " \"type\": \"memfile\", \n"
+ " \"persist\":false, \n"
+ " \"lfc-interval\": 0 \n"
+ " }, \n"
+ " \"expired-leases-processing\": { \n"
+ " \"reclaim-timer-wait-time\": 0, \n"
+ " \"hold-reclaimed-time\": 0, \n"
+ " \"flush-reclaimed-timer-wait-time\": 0 \n"
+ " },"
+ " \"subnet4\": [ \n";
+ string subnet1 =
+ " {\"subnet\": \"192.2.0.0/24\", \"id\": 1, \n"
+ " \"pools\": [{ \"pool\": \"192.2.0.1-192.2.0.50\" }]}\n";
+ string subnet_footer =
+ " ] \n";
+ string option_def =
+ " ,\"option-def\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"type\": \"uint32\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"space\": \"dhcp4\",\n"
+ " \"encapsulate\": \"\"\n"
+ " }\n"
+ "]\n";
+ string option_data =
+ " ,\"option-data\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"space\": \"dhcp4\",\n"
+ " \"csv-format\": true,\n"
+ " \"data\": \"12345\"\n"
+ " }\n"
+ "]\n";
+ string control_socket_header =
+ " ,\"control-socket\": { \n";
+ string control_socket_footer =
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"127.0.0.1\", \n"
+ " \"socket-port\": 18124 \n"
+ " } \n";
+ string logger_txt =
+ " ,\"loggers\": [ { \n"
+ " \"name\": \"kea\", \n"
+ " \"severity\": \"FATAL\", \n"
+ " \"output-options\": [{ \n"
+ " \"output\": \"/dev/null\", \n"
+ " \"maxsize\": 0"
+ " }] \n"
+ " }] \n";
+
+ std::ostringstream os;
+
+ // Create a valid config with all the parts should parse
+ os << config_set_txt << ","
+ << args_txt
+ << dhcp4_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp4
+ << "}}";
+
+ // Send the config-set command
+ std::string response;
+ sendHttpCommand(os.str(), response);
+ EXPECT_EQ("[ { \"arguments\": { \"hash\": \"F6137301FF10D81585E041FD5FD8E91347ACADDE64F92ED03432FB100874DE02\" }, \"result\": 0, \"text\": \"Configuration successful.\" } ]",
+ response);
+
+ // Check that the config was indeed applied.
+ const Subnet4Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ OptionDefinitionPtr def =
+ LibDHCP::getRuntimeOptionDef(DHCP4_OPTION_SPACE, 163);
+ ASSERT_TRUE(def);
+
+ // Verify the HTTP control channel socket exists.
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ std::ostringstream second_config_os;
+
+ // Create a valid config with all the parts should parse
+ second_config_os << config_set_txt << ","
+ << args_txt
+ << dhcp4_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp4
+ << "}}";
+
+ // Send the config-set command.
+ sendHttpCommand(second_config_os.str(), response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was not lost
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ // Clean up after the test.
+ CfgMgr::instance().clear();
+}
+
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpsCtrlChannelDhcpv4Test, ignoreHttpsToHttpSwitch) {
+ createHttpChannelServer();
+
+ // Define strings to permutate the config arguments
+ // (Note the line feeds makes errors easy to find)
+ string ca_dir(string(TEST_CA_DIR));
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
+ string args_txt = " \"arguments\": { \n";
+ string dhcp4_cfg_txt =
+ " \"Dhcp4\": { \n"
+ " \"interfaces-config\": { \n"
+ " \"interfaces\": [\"*\"] \n"
+ " }, \n"
+ " \"valid-lifetime\": 4000, \n"
+ " \"renew-timer\": 1000, \n"
+ " \"rebind-timer\": 2000, \n"
+ " \"lease-database\": { \n"
+ " \"type\": \"memfile\", \n"
+ " \"persist\":false, \n"
+ " \"lfc-interval\": 0 \n"
+ " }, \n"
+ " \"expired-leases-processing\": { \n"
+ " \"reclaim-timer-wait-time\": 0, \n"
+ " \"hold-reclaimed-time\": 0, \n"
+ " \"flush-reclaimed-timer-wait-time\": 0 \n"
+ " },"
+ " \"subnet4\": [ \n";
+ string subnet1 =
+ " {\"subnet\": \"192.2.0.0/24\", \"id\": 1, \n"
+ " \"pools\": [{ \"pool\": \"192.2.0.1-192.2.0.50\" }]}\n";
+ string subnet_footer =
+ " ] \n";
+ string option_def =
+ " ,\"option-def\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"type\": \"uint32\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"space\": \"dhcp4\",\n"
+ " \"encapsulate\": \"\"\n"
+ " }\n"
+ "]\n";
+ string option_data =
+ " ,\"option-data\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"space\": \"dhcp4\",\n"
+ " \"csv-format\": true,\n"
+ " \"data\": \"12345\"\n"
+ " }\n"
+ "]\n";
+ string control_socket_header =
+ " ,\"control-socket\": { \n";
+ string control_socket_footer =
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"127.0.0.1\", \n"
+ " \"socket-port\": 18124 \n"
+ " } \n";
+ string logger_txt =
+ " ,\"loggers\": [ { \n"
+ " \"name\": \"kea\", \n"
+ " \"severity\": \"FATAL\", \n"
+ " \"output-options\": [{ \n"
+ " \"output\": \"/dev/null\", \n"
+ " \"maxsize\": 0"
+ " }] \n"
+ " }] \n";
+
+ std::ostringstream os;
+
+ // Create a valid config with all the parts should parse
+ os << config_set_txt << ","
+ << args_txt
+ << dhcp4_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp4
+ << "}}";
+
+ // Send the config-set command
+ std::string response;
+ sendHttpCommand(os.str(), response);
+ // Verify the configuration was successful. The config contains random
+ // file paths (CA directory), so the hash will be different each time.
+ // As such, we can do simplified checks:
+ // - verify the "result": 0 is there
+ // - verify the "text": "Configuration successful." is there
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was indeed applied.
+ const Subnet4Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ OptionDefinitionPtr def =
+ LibDHCP::getRuntimeOptionDef(DHCP4_OPTION_SPACE, 163);
+ ASSERT_TRUE(def);
+
+ // Verify the HTTP control channel socket exists.
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ // The TLS settings have not changed
+ auto const context = HttpCommandMgr::instance().getHttpListener()->getTlsContext().get();
+
+ std::ostringstream second_config_os;
+
+ // Create a valid config with all the parts should parse
+ second_config_os << config_set_txt << ","
+ << args_txt
+ << dhcp4_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp4
+ << "}}";
+
+ // Send the config-set command.
+ sendHttpCommand(second_config_os.str(), response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ EXPECT_EQ(context, HttpCommandMgr::instance().getHttpListener()->getTlsContext().get());
+
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was not lost
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ // Clean up after the test.
+ CfgMgr::instance().clear();
+}
+
} // End of anonymous namespace
ConstElementPtr current_http_config =
CfgMgr::instance().getCurrentCfg()->getHttpControlSocketInfo();
- sock_changed = (http_config && current_http_config &&
- !http_config->equals(*current_http_config));
-
- if (!http_config || !current_http_config || sock_changed) {
- if (http_config) {
- HttpCommandMgr::instance().openCommandSockets(http_config);
- } else if (current_http_config) {
- HttpCommandMgr::instance().closeCommandSockets();
- }
+ if (http_config) {
+ HttpCommandMgr::instance().openCommandSockets(http_config);
+ } else if (current_http_config) {
+ HttpCommandMgr::instance().closeCommandSockets();
}
}
// Define strings to permutate the config arguments
// (Note the line feeds makes errors easy to find)
- string set_config_txt = "{ \"command\": \"config-set\" \n";
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
string args_txt = " \"arguments\": { \n";
string dhcp6_cfg_txt =
" \"Dhcp6\": { \n"
std::ostringstream os;
// Create a valid config with all the parts should parse
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp6_cfg_txt
<< subnet1
// Create a config with malformed subnet that should fail to parse.
os.str("");
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp6_cfg_txt
<< bad_subnet
// Create a valid config with two subnets and no command channel.
// It should succeed, client should still receive the response
os.str("");
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp6_cfg_txt
<< subnet1
// Define strings to permutate the config arguments
// (Note the line feeds makes errors easy to find)
string ca_dir(string(TEST_CA_DIR));
- string set_config_txt = "{ \"command\": \"config-set\" \n";
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
string args_txt = " \"arguments\": { \n";
string dhcp6_cfg_txt =
" \"Dhcp6\": { \n"
std::ostringstream os;
// Create a valid config with all the parts should parse
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp6_cfg_txt
<< subnet1
// Create a config with malformed subnet that should fail to parse.
os.str("");
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp6_cfg_txt
<< bad_subnet
// Create a valid config with two subnets and no command channel.
// It should succeed, client should still receive the response
os.str("");
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp6_cfg_txt
<< subnet1
// Define strings to permutate the config arguments
// (Note the line feeds makes errors easy to find)
- string set_config_txt = "{ \"command\": \"config-set\" \n";
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
string config_test_txt = "{ \"command\": \"config-test\" \n";
string args_txt = " \"arguments\": { \n";
string dhcp6_cfg_txt =
std::ostringstream os;
// Create a valid config with all the parts should parse
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp6_cfg_txt
<< subnet1
// Define strings to permutate the config arguments
// (Note the line feeds makes errors easy to find)
string ca_dir(string(TEST_CA_DIR));
- string set_config_txt = "{ \"command\": \"config-set\" \n";
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
string config_test_txt = "{ \"command\": \"config-test\" \n";
string args_txt = " \"arguments\": { \n";
string dhcp6_cfg_txt =
std::ostringstream os;
// Create a valid config with all the parts should parse
- os << set_config_txt << ","
+ os << config_set_txt << ","
<< args_txt
<< dhcp6_cfg_txt
<< subnet1
testConnectionTimeoutNoData();
}
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpCtrlChannelDhcpv6Test, noListenerChange) {
+ createHttpChannelServer();
+
+ // Define strings to permutate the config arguments
+ // (Note the line feeds makes errors easy to find)
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
+ string args_txt = " \"arguments\": { \n";
+ string dhcp6_cfg_txt =
+ " \"Dhcp6\": { \n"
+ " \"interfaces-config\": { \n"
+ " \"interfaces\": [\"*\"] \n"
+ " }, \n"
+ " \"preferred-lifetime\": 3000, \n"
+ " \"valid-lifetime\": 4000, \n"
+ " \"renew-timer\": 1000, \n"
+ " \"rebind-timer\": 2000, \n"
+ " \"lease-database\": { \n"
+ " \"type\": \"memfile\", \n"
+ " \"persist\":false, \n"
+ " \"lfc-interval\": 0 \n"
+ " }, \n"
+ " \"expired-leases-processing\": { \n"
+ " \"reclaim-timer-wait-time\": 0, \n"
+ " \"hold-reclaimed-time\": 0, \n"
+ " \"flush-reclaimed-timer-wait-time\": 0 \n"
+ " },"
+ " \"subnet6\": [ \n";
+ string subnet1 =
+ " {\"subnet\": \"3002::/64\", \"id\": 1, \n"
+ " \"pools\": [{ \"pool\": \"3002::100-3002::200\" }]}\n";
+ string subnet_footer =
+ " ] \n";
+ string option_def =
+ " ,\"option-def\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"type\": \"uint32\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"space\": \"dhcp6\",\n"
+ " \"encapsulate\": \"\"\n"
+ " }\n"
+ "]\n";
+ string option_data =
+ " ,\"option-data\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"space\": \"dhcp6\",\n"
+ " \"csv-format\": true,\n"
+ " \"data\": \"12345\"\n"
+ " }\n"
+ "]\n";
+ string control_socket =
+ " ,\"control-socket\": { \n"
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"::1\", \n"
+ " \"socket-port\": 18126 \n"
+ " } \n";
+ string logger_txt =
+ " ,\"loggers\": [ { \n"
+ " \"name\": \"kea\", \n"
+ " \"severity\": \"FATAL\", \n"
+ " \"output-options\": [{ \n"
+ " \"output\": \"/dev/null\", \n"
+ " \"maxsize\": 0"
+ " }] \n"
+ " }] \n";
+
+ std::ostringstream os;
+
+ // Create a valid config with all the parts should parse
+ os << config_set_txt << ","
+ << args_txt
+ << dhcp6_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket
+ << logger_txt
+ << "}\n" // close dhcp6
+ << "}}";
+
+ // Send the config-set command
+ std::string response;
+ sendHttpCommand(os.str(), response);
+ EXPECT_EQ("[ { \"arguments\": { \"hash\": \"BCE3D0CC68CBBB49C3F5967E3FFCB4E44E55CBFB53814761B12ADB5C7CD95C1F\" }, \"result\": 0, \"text\": \"Configuration successful.\" } ]",
+ response);
+
+ // Check that the config was indeed applied.
+ const Subnet6Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ OptionDefinitionPtr def =
+ LibDHCP::getRuntimeOptionDef(DHCP6_OPTION_SPACE, 163);
+ ASSERT_TRUE(def);
+
+ // Verify the HTTP control channel socket exists.
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ // Send the config-set command.
+ sendHttpCommand(os.str(), response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ EXPECT_EQ("[ { \"arguments\": { \"hash\": \"BCE3D0CC68CBBB49C3F5967E3FFCB4E44E55CBFB53814761B12ADB5C7CD95C1F\" }, \"result\": 0, \"text\": \"Configuration successful.\" } ]",
+ response);
+
+ // Check that the config was not lost
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ // Clean up after the test.
+ CfgMgr::instance().clear();
+}
+
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpsCtrlChannelDhcpv6Test, noListenerChange) {
+ createHttpChannelServer();
+
+ // Define strings to permutate the config arguments
+ // (Note the line feeds makes errors easy to find)
+ string ca_dir(string(TEST_CA_DIR));
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
+ string args_txt = " \"arguments\": { \n";
+ string dhcp6_cfg_txt =
+ " \"Dhcp6\": { \n"
+ " \"interfaces-config\": { \n"
+ " \"interfaces\": [\"*\"] \n"
+ " }, \n"
+ " \"preferred-lifetime\": 3000, \n"
+ " \"valid-lifetime\": 4000, \n"
+ " \"renew-timer\": 1000, \n"
+ " \"rebind-timer\": 2000, \n"
+ " \"lease-database\": { \n"
+ " \"type\": \"memfile\", \n"
+ " \"persist\":false, \n"
+ " \"lfc-interval\": 0 \n"
+ " }, \n"
+ " \"expired-leases-processing\": { \n"
+ " \"reclaim-timer-wait-time\": 0, \n"
+ " \"hold-reclaimed-time\": 0, \n"
+ " \"flush-reclaimed-timer-wait-time\": 0 \n"
+ " },"
+ " \"subnet6\": [ \n";
+ string subnet1 =
+ " {\"subnet\": \"3002::/64\", \"id\": 1, \n"
+ " \"pools\": [{ \"pool\": \"3002::100-3002::200\" }]}\n";
+ string subnet_footer =
+ " ] \n";
+ string option_def =
+ " ,\"option-def\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"type\": \"uint32\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"space\": \"dhcp6\",\n"
+ " \"encapsulate\": \"\"\n"
+ " }\n"
+ "]\n";
+ string option_data =
+ " ,\"option-data\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"space\": \"dhcp6\",\n"
+ " \"csv-format\": true,\n"
+ " \"data\": \"12345\"\n"
+ " }\n"
+ "]\n";
+ string control_socket_header =
+ " ,\"control-socket\": { \n";
+ string control_socket_footer =
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"::1\", \n"
+ " \"socket-port\": 18126 \n"
+ " } \n";
+ string logger_txt =
+ " ,\"loggers\": [ { \n"
+ " \"name\": \"kea\", \n"
+ " \"severity\": \"FATAL\", \n"
+ " \"output-options\": [{ \n"
+ " \"output\": \"/dev/null\", \n"
+ " \"maxsize\": 0"
+ " }] \n"
+ " }] \n";
+
+ std::ostringstream os;
+
+ // Create a valid config with all the parts should parse
+ os << config_set_txt << ","
+ << args_txt
+ << dhcp6_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp6
+ << "}}";
+
+ // Send the config-set command
+ std::string response;
+ sendHttpCommand(os.str(), response);
+ // Verify the configuration was successful. The config contains random
+ // file paths (CA directory), so the hash will be different each time.
+ // As such, we can do simplified checks:
+ // - verify the "result": 0 is there
+ // - verify the "text": "Configuration successful." is there
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was indeed applied.
+ const Subnet6Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ OptionDefinitionPtr def =
+ LibDHCP::getRuntimeOptionDef(DHCP6_OPTION_SPACE, 163);
+ ASSERT_TRUE(def);
+
+ // Verify the HTTP control channel socket exists.
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ auto const context = HttpCommandMgr::instance().getHttpListener()->getTlsContext().get();
+
+ // Send the config-set command.
+ sendHttpCommand(os.str(), response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ // The TLS settings have been applied
+ EXPECT_NE(context, HttpCommandMgr::instance().getHttpListener()->getTlsContext().get());
+
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was not lost
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ // Clean up after the test.
+ CfgMgr::instance().clear();
+}
+
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpCtrlChannelDhcpv6Test, ignoreHttpToHttpsSwitch) {
+ createHttpChannelServer();
+
+ // Define strings to permutate the config arguments
+ // (Note the line feeds makes errors easy to find)
+ string ca_dir(string(TEST_CA_DIR));
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
+ string args_txt = " \"arguments\": { \n";
+ string dhcp6_cfg_txt =
+ " \"Dhcp6\": { \n"
+ " \"interfaces-config\": { \n"
+ " \"interfaces\": [\"*\"] \n"
+ " }, \n"
+ " \"preferred-lifetime\": 3000, \n"
+ " \"valid-lifetime\": 4000, \n"
+ " \"renew-timer\": 1000, \n"
+ " \"rebind-timer\": 2000, \n"
+ " \"lease-database\": { \n"
+ " \"type\": \"memfile\", \n"
+ " \"persist\":false, \n"
+ " \"lfc-interval\": 0 \n"
+ " }, \n"
+ " \"expired-leases-processing\": { \n"
+ " \"reclaim-timer-wait-time\": 0, \n"
+ " \"hold-reclaimed-time\": 0, \n"
+ " \"flush-reclaimed-timer-wait-time\": 0 \n"
+ " },"
+ " \"subnet6\": [ \n";
+ string subnet1 =
+ " {\"subnet\": \"3002::/64\", \"id\": 1, \n"
+ " \"pools\": [{ \"pool\": \"3002::100-3002::200\" }]}\n";
+ string subnet_footer =
+ " ] \n";
+ string option_def =
+ " ,\"option-def\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"type\": \"uint32\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"space\": \"dhcp6\",\n"
+ " \"encapsulate\": \"\"\n"
+ " }\n"
+ "]\n";
+ string option_data =
+ " ,\"option-data\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"space\": \"dhcp6\",\n"
+ " \"csv-format\": true,\n"
+ " \"data\": \"12345\"\n"
+ " }\n"
+ "]\n";
+ string control_socket_header =
+ " ,\"control-socket\": { \n";
+ string control_socket_footer =
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"::1\", \n"
+ " \"socket-port\": 18126 \n"
+ " } \n";
+ string logger_txt =
+ " ,\"loggers\": [ { \n"
+ " \"name\": \"kea\", \n"
+ " \"severity\": \"FATAL\", \n"
+ " \"output-options\": [{ \n"
+ " \"output\": \"/dev/null\", \n"
+ " \"maxsize\": 0"
+ " }] \n"
+ " }] \n";
+
+ std::ostringstream os;
+
+ // Create a valid config with all the parts should parse
+ os << config_set_txt << ","
+ << args_txt
+ << dhcp6_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp6
+ << "}}";
+
+ // Send the config-set command
+ std::string response;
+ sendHttpCommand(os.str(), response);
+ EXPECT_EQ("[ { \"arguments\": { \"hash\": \"BCE3D0CC68CBBB49C3F5967E3FFCB4E44E55CBFB53814761B12ADB5C7CD95C1F\" }, \"result\": 0, \"text\": \"Configuration successful.\" } ]",
+ response);
+
+ // Check that the config was indeed applied.
+ const Subnet6Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ OptionDefinitionPtr def =
+ LibDHCP::getRuntimeOptionDef(DHCP6_OPTION_SPACE, 163);
+ ASSERT_TRUE(def);
+
+ // Verify the HTTP control channel socket exists.
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ std::ostringstream second_config_os;
+
+ // Create a valid config with all the parts should parse
+ second_config_os << config_set_txt << ","
+ << args_txt
+ << dhcp6_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp6
+ << "}}";
+
+ // Send the config-set command.
+ sendHttpCommand(second_config_os.str(), response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_FALSE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was not lost
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ // Clean up after the test.
+ CfgMgr::instance().clear();
+}
+
+// Verify that the "config-set" command will reuse listener
+TEST_F(HttpsCtrlChannelDhcpv6Test, ignoreHttpsToHttpSwitch) {
+ createHttpChannelServer();
+
+ // Define strings to permutate the config arguments
+ // (Note the line feeds makes errors easy to find)
+ string ca_dir(string(TEST_CA_DIR));
+ string config_set_txt = "{ \"command\": \"config-set\" \n";
+ string args_txt = " \"arguments\": { \n";
+ string dhcp6_cfg_txt =
+ " \"Dhcp6\": { \n"
+ " \"interfaces-config\": { \n"
+ " \"interfaces\": [\"*\"] \n"
+ " }, \n"
+ " \"preferred-lifetime\": 3000, \n"
+ " \"valid-lifetime\": 4000, \n"
+ " \"renew-timer\": 1000, \n"
+ " \"rebind-timer\": 2000, \n"
+ " \"lease-database\": { \n"
+ " \"type\": \"memfile\", \n"
+ " \"persist\":false, \n"
+ " \"lfc-interval\": 0 \n"
+ " }, \n"
+ " \"expired-leases-processing\": { \n"
+ " \"reclaim-timer-wait-time\": 0, \n"
+ " \"hold-reclaimed-time\": 0, \n"
+ " \"flush-reclaimed-timer-wait-time\": 0 \n"
+ " },"
+ " \"subnet6\": [ \n";
+ string subnet1 =
+ " {\"subnet\": \"3002::/64\", \"id\": 1, \n"
+ " \"pools\": [{ \"pool\": \"3002::100-3002::200\" }]}\n";
+ string subnet_footer =
+ " ] \n";
+ string option_def =
+ " ,\"option-def\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"type\": \"uint32\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"space\": \"dhcp6\",\n"
+ " \"encapsulate\": \"\"\n"
+ " }\n"
+ "]\n";
+ string option_data =
+ " ,\"option-data\": [\n"
+ " {\n"
+ " \"name\": \"foo\",\n"
+ " \"code\": 163,\n"
+ " \"space\": \"dhcp6\",\n"
+ " \"csv-format\": true,\n"
+ " \"data\": \"12345\"\n"
+ " }\n"
+ "]\n";
+ string control_socket_header =
+ " ,\"control-socket\": { \n";
+ string control_socket_footer =
+ " \"socket-type\": \"http\", \n"
+ " \"socket-address\": \"::1\", \n"
+ " \"socket-port\": 18126 \n"
+ " } \n";
+ string logger_txt =
+ " ,\"loggers\": [ { \n"
+ " \"name\": \"kea\", \n"
+ " \"severity\": \"FATAL\", \n"
+ " \"output-options\": [{ \n"
+ " \"output\": \"/dev/null\", \n"
+ " \"maxsize\": 0"
+ " }] \n"
+ " }] \n";
+
+ std::ostringstream os;
+
+ // Create a valid config with all the parts should parse
+ os << config_set_txt << ","
+ << args_txt
+ << dhcp6_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << " \"trust-anchor\": \"" << ca_dir << "/kea-ca.crt\", \n"
+ << " \"cert-file\": \"" << ca_dir << "/kea-server.crt\", \n"
+ << " \"key-file\": \"" << ca_dir << "/kea-server.key\", \n"
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp6
+ << "}}";
+
+ // Send the config-set command
+ std::string response;
+ sendHttpCommand(os.str(), response);
+ // Verify the configuration was successful. The config contains random
+ // file paths (CA directory), so the hash will be different each time.
+ // As such, we can do simplified checks:
+ // - verify the "result": 0 is there
+ // - verify the "text": "Configuration successful." is there
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was indeed applied.
+ const Subnet6Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ OptionDefinitionPtr def =
+ LibDHCP::getRuntimeOptionDef(DHCP6_OPTION_SPACE, 163);
+ ASSERT_TRUE(def);
+
+ // Verify the HTTP control channel socket exists.
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ auto const listener = HttpCommandMgr::instance().getHttpListener().get();
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ // The TLS settings have not changed
+ auto const context = HttpCommandMgr::instance().getHttpListener()->getTlsContext().get();
+
+ std::ostringstream second_config_os;
+
+ // Create a valid config with all the parts should parse
+ second_config_os << config_set_txt << ","
+ << args_txt
+ << dhcp6_cfg_txt
+ << subnet1
+ << subnet_footer
+ << option_def
+ << option_data
+ << control_socket_header
+ << control_socket_footer
+ << logger_txt
+ << "}\n" // close dhcp6
+ << "}}";
+
+ // Send the config-set command.
+ sendHttpCommand(second_config_os.str(), response);
+
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener());
+ EXPECT_EQ(listener, HttpCommandMgr::instance().getHttpListener().get());
+ ASSERT_TRUE(HttpCommandMgr::instance().getHttpListener()->getTlsContext());
+ EXPECT_EQ(context, HttpCommandMgr::instance().getHttpListener()->getTlsContext().get());
+
+ EXPECT_NE(response.find("\"result\": 0"), std::string::npos);
+ EXPECT_NE(response.find("\"text\": \"Configuration successful.\""),
+ std::string::npos);
+
+ // Check that the config was not lost
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
+ EXPECT_EQ(1, subnets->size());
+
+ // Clean up after the test.
+ CfgMgr::instance().clear();
+}
+
} // End of anonymous namespace
extern const isc::log::MessageID COMMAND_WATCH_SOCKET_CLEAR_ERROR = "COMMAND_WATCH_SOCKET_CLEAR_ERROR";
extern const isc::log::MessageID COMMAND_WATCH_SOCKET_CLOSE_ERROR = "COMMAND_WATCH_SOCKET_CLOSE_ERROR";
extern const isc::log::MessageID COMMAND_WATCH_SOCKET_MARK_READY_ERROR = "COMMAND_WATCH_SOCKET_MARK_READY_ERROR";
-extern const isc::log::MessageID HTTP_COMMAND_MGR_IGNORED_TLS_SETUP_CHANGES = "HTTP_COMMAND_MGR_IGNORED_TLS_SETUP_CHANGES";
+extern const isc::log::MessageID HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSED = "HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSED";
+extern const isc::log::MessageID HTTP_COMMAND_MGR_HTTP_SERVICE_REUSED = "HTTP_COMMAND_MGR_HTTP_SERVICE_REUSED";
extern const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STARTED = "HTTP_COMMAND_MGR_SERVICE_STARTED";
extern const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STOPPING = "HTTP_COMMAND_MGR_SERVICE_STOPPING";
extern const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STOPPING_ALL = "HTTP_COMMAND_MGR_SERVICE_STOPPING_ALL";
"COMMAND_WATCH_SOCKET_CLEAR_ERROR", "watch socket failed to clear: %1",
"COMMAND_WATCH_SOCKET_CLOSE_ERROR", "watch socket failed to close: %1",
"COMMAND_WATCH_SOCKET_MARK_READY_ERROR", "watch socket failed to mark ready: %1",
- "HTTP_COMMAND_MGR_IGNORED_TLS_SETUP_CHANGES", "ignore a change in TLS setup of the http control socket",
+ "HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSED", "reused HTTPS service bound to address %1:%2",
+ "HTTP_COMMAND_MGR_HTTP_SERVICE_REUSED", "reused HTTP service bound to address %1:%2",
"HTTP_COMMAND_MGR_SERVICE_STARTED", "started %1 service bound to address %2 port %3",
"HTTP_COMMAND_MGR_SERVICE_STOPPING", "Server is stopping %1 service %2",
"HTTP_COMMAND_MGR_SERVICE_STOPPING_ALL", "stopping %1 service %2",
extern const isc::log::MessageID COMMAND_WATCH_SOCKET_CLEAR_ERROR;
extern const isc::log::MessageID COMMAND_WATCH_SOCKET_CLOSE_ERROR;
extern const isc::log::MessageID COMMAND_WATCH_SOCKET_MARK_READY_ERROR;
-extern const isc::log::MessageID HTTP_COMMAND_MGR_IGNORED_TLS_SETUP_CHANGES;
+extern const isc::log::MessageID HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSED;
+extern const isc::log::MessageID HTTP_COMMAND_MGR_HTTP_SERVICE_REUSED;
extern const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STARTED;
extern const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STOPPING;
extern const isc::log::MessageID HTTP_COMMAND_MGR_SERVICE_STOPPING_ALL;
that should be reported. The command manager may or may not continue
to operate correctly.
-% HTTP_COMMAND_MGR_IGNORED_TLS_SETUP_CHANGES ignore a change in TLS setup of the http control socket
-The warning message is issued when the HTTP/HTTPS control socket was
-reconfigured with a different TLS setup but keeping the address and port.
-These changes are ignored because they can't be applied without opening a new
-socket which will conflict with the existing one.
+% HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSED reused HTTPS service bound to address %1:%2
+This informational message indicates that the server has reused existing
+HTTPS service on the specified address and port. Note that any change in
+the TLS setup was ignored.
+
+% HTTP_COMMAND_MGR_HTTP_SERVICE_REUSED reused HTTP service bound to address %1:%2
+This informational message indicates that the server has reused existing
+HTTP service on the specified address and port.
% HTTP_COMMAND_MGR_SERVICE_STARTED started %1 service bound to address %2 port %3
This informational message indicates that the server has started
// Search for the specific connection and reuse the existing one if found.
auto it = sockets_.find(std::make_pair(server_address, server_port));
if (it != sockets_.end()) {
- if ((cmd_config->getTrustAnchor() != it->second->config_->getTrustAnchor()) ||
- (cmd_config->getCertFile() != it->second->config_->getCertFile()) ||
- (cmd_config->getKeyFile() != it->second->config_->getKeyFile()) ||
- (cmd_config->getCertRequired() != it->second->config_->getCertRequired())) {
- LOG_WARN(command_logger, HTTP_COMMAND_MGR_IGNORED_TLS_SETUP_CHANGES);
- // Overwrite the authentication setup and the emulation flag
- // in the response creator config.
- it->second->config_->setAuthConfig(cmd_config->getAuthConfig());
- it->second->config_->setEmulateAgentResponse(cmd_config->getEmulateAgentResponse());
+ auto listener = it->second->listener_;
+ if (listener) {
+ // Reconfig keeping the same address and port.
+ if (listener->getTlsContext()) {
+ if (cmd_config->getTrustAnchor().empty()) {
+ // Can not switch from HTTPS to HTTP
+ LOG_INFO(command_logger, HTTP_COMMAND_MGR_HTTPS_SERVICE_REUSED)
+ .arg(server_address.toText())
+ .arg(server_port);
+ } else {
+ // Apply TLS settings each time.
+ TlsContextPtr tls_context;
+ TlsContext::configure(tls_context,
+ TlsRole::SERVER,
+ cmd_config->getTrustAnchor(),
+ cmd_config->getCertFile(),
+ cmd_config->getKeyFile(),
+ cmd_config->getCertRequired());
+ // Overwrite the authentication setup, the http headers and the emulation flag
+ // in the response creator config.
+ it->second->config_->setAuthConfig(cmd_config->getAuthConfig());
+ it->second->config_->setHttpHeaders(cmd_config->getHttpHeaders());
+ it->second->config_->setEmulateAgentResponse(cmd_config->getEmulateAgentResponse());
+ io_service_->post([listener, tls_context]() { listener->setTlsContext(tls_context); });
+ }
+ } else if (!cmd_config->getTrustAnchor().empty()) {
+ // Can not switch from HTTP to HTTPS
+ LOG_INFO(command_logger, HTTP_COMMAND_MGR_HTTP_SERVICE_REUSED)
+ .arg(server_address.toText())
+ .arg(server_port);
+ }
}
// If the connection can be reused, mark it as usable.
it->second->usable_ = true;
return (impl_->getTlsContext());
}
+void
+HttpListener::setTlsContext(const TlsContextPtr& context) {
+ impl_->setTlsContext(context);
+}
+
int
HttpListener::getNative() const {
return (impl_->getNative());
/// @brief Returns reference to the current TLS context.
const asiolink::TlsContextPtr& getTlsContext() const;
+ /// @brief Sets reference of the current TLS context.
+ void setTlsContext(const asiolink::TlsContextPtr& context);
+
/// @brief file descriptor of the underlying acceptor socket.
int getNative() const;
return (tls_context_);
}
+void
+HttpListenerImpl::setTlsContext(const TlsContextPtr& context) {
+ tls_context_ = context;
+}
+
int
HttpListenerImpl::getNative() const {
return (acceptor_ ? acceptor_->getNative() : -1);
/// @brief Returns reference to the current TLS context.
const asiolink::TlsContextPtr& getTlsContext() const;
+ /// @brief Sets reference of the current TLS context.
+ void setTlsContext(const asiolink::TlsContextPtr& context);
+
/// @brief file descriptor of the underlying acceptor socket.
int getNative() const;