From 133ccdfb151eaff8bbd3c41697cfa67441d17780 Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Mon, 5 Feb 2024 12:31:45 +0200 Subject: [PATCH] [#3190] fixed ASAN warnings --- src/bin/agent/ca_process.cc | 6 +- .../agent/tests/ca_controller_unittests.cc | 3 - src/bin/agent/tests/ca_process_unittests.cc | 8 +- src/bin/d2/d2_process.cc | 3 + src/bin/d2/d2_queue_mgr.cc | 2 - src/bin/d2/d2_queue_mgr.h | 7 +- src/bin/d2/tests/d2_process_unittests.cc | 18 +- src/bin/d2/tests/d2_queue_mgr_unittests.cc | 9 + src/bin/d2/tests/d2_update_mgr_unittests.cc | 37 +- src/bin/dhcp4/dhcp4_srv.cc | 5 + src/bin/dhcp4/tests/classify_unittest.cc | 9 - .../dhcp4/tests/ctrl_dhcp4_srv_unittest.cc | 7 +- src/bin/dhcp4/tests/dhcp4_srv_unittest.cc | 9 - src/bin/dhcp4/tests/dhcp4_test_utils.h | 13 + .../dhcp4/tests/kea_controller_unittest.cc | 1 + src/bin/dhcp6/dhcp6_srv.cc | 5 + .../dhcp6/tests/ctrl_dhcp6_srv_unittest.cc | 14 +- src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 9 - src/bin/dhcp6/tests/dhcp6_test_utils.h | 11 + .../dhcp6/tests/kea_controller_unittest.cc | 3 +- src/bin/netconf/http_control_socket.cc | 7 + .../netconf/tests/control_socket_unittests.cc | 24 +- .../tests/netconf_process_unittests.cc | 6 + src/bin/netconf/tests/netconf_unittests.cc | 10 +- .../high_availability/communication_state.cc | 2 + .../dhcp/high_availability/ha_service.cc | 40 ++ .../tests/ha_impl_unittest.cc | 639 +++++++++--------- .../tests/ha_service_unittest.cc | 79 ++- .../dhcp/high_availability/tests/ha_test.cc | 30 +- .../dhcp/high_availability/tests/ha_test.h | 3 + src/lib/asiodns/io_fetch.cc | 42 +- src/lib/asiodns/tests/io_fetch_unittest.cc | 91 +-- src/lib/asiolink/io_service_thread_pool.h | 2 +- src/lib/asiolink/tcp_socket.h | 22 +- src/lib/asiolink/tls_socket.h | 21 +- src/lib/asiolink/udp_socket.h | 19 +- src/lib/config/cmd_http_listener.cc | 41 +- src/lib/d2srv/d2_config.h | 18 +- src/lib/d2srv/dns_client.cc | 38 +- src/lib/d2srv/dns_client.h | 3 + src/lib/d2srv/nc_trans.cc | 2 +- src/lib/d2srv/tests/dns_client_unittests.cc | 12 +- src/lib/d2srv/testutils/nc_test_utils.cc | 17 +- src/lib/d2srv/testutils/nc_test_utils.h | 6 + src/lib/dhcp_ddns/ncr_io.cc | 3 +- src/lib/dhcp_ddns/ncr_io.h | 4 +- src/lib/dhcp_ddns/ncr_udp.cc | 9 +- src/lib/dhcp_ddns/tests/ncr_udp_unittests.cc | 3 +- .../tests/memfile_lease_mgr_unittest.cc | 6 + src/lib/http/client.cc | 39 +- src/lib/http/connection_pool.h | 1 - src/lib/http/tests/server_client_unittests.cc | 6 +- src/lib/process/d_controller.cc | 30 +- src/lib/process/d_controller.h | 14 +- src/lib/process/d_process.h | 8 +- src/lib/tcp/mt_tcp_listener_mgr.cc | 48 +- .../tests/mt_tcp_listener_mgr_unittests.cc | 2 - src/lib/util/stopwatch.cc | 1 - src/lib/util/stopwatch.h | 2 +- 59 files changed, 941 insertions(+), 588 deletions(-) diff --git a/src/bin/agent/ca_process.cc b/src/bin/agent/ca_process.cc index fd36a46e42..9559d84444 100644 --- a/src/bin/agent/ca_process.cc +++ b/src/bin/agent/ca_process.cc @@ -33,6 +33,7 @@ CtrlAgentProcess::CtrlAgentProcess(const char* name, } CtrlAgentProcess::~CtrlAgentProcess() { + garbageCollectListeners(0); } void @@ -206,7 +207,10 @@ CtrlAgentProcess::garbageCollectListeners(size_t leaving) { } // We have stopped listeners but there may be some pending handlers // related to these listeners. Need to invoke these handlers. - getIOService()->poll(); + try { + getIOService()->poll(); + } catch (...) { + } // Finally, we're ready to remove no longer used listeners. http_listeners_.erase(http_listeners_.begin(), http_listeners_.end() - leaving); diff --git a/src/bin/agent/tests/ca_controller_unittests.cc b/src/bin/agent/tests/ca_controller_unittests.cc index 1e0c58c30e..9a18c27a0a 100644 --- a/src/bin/agent/tests/ca_controller_unittests.cc +++ b/src/bin/agent/tests/ca_controller_unittests.cc @@ -188,7 +188,6 @@ TEST_F(CtrlAgentControllerTest, basicInstanceTesting) { EXPECT_FALSE(checkProcess()); } - // Tests basic command line processing. // Verifies that: // 1. Standard command line options are supported. @@ -680,7 +679,6 @@ TEST_F(CtrlAgentControllerTest, configReloadFileValid) { answer = CtrlAgentCommandMgr::instance().handleCommand("config-reload", params, cmd); - // Verify the reload was successful. string expected = "{ \"result\": 0, \"text\": " "\"Configuration applied successfully.\" }"; @@ -785,7 +783,6 @@ TEST_F(CtrlAgentControllerTest, shutdown) { ctrl->deregisterCommands(); } - TEST_F(CtrlAgentControllerTest, shutdownExitValue) { ASSERT_NO_THROW(initProcess()); EXPECT_TRUE(checkProcess()); diff --git a/src/bin/agent/tests/ca_process_unittests.cc b/src/bin/agent/tests/ca_process_unittests.cc index ecb2563188..3d708c3e43 100644 --- a/src/bin/agent/tests/ca_process_unittests.cc +++ b/src/bin/agent/tests/ca_process_unittests.cc @@ -84,7 +84,13 @@ TEST_F(CtrlAgentProcessTest, shutdown) { time_duration elapsed = stop - start; EXPECT_TRUE(elapsed.total_milliseconds() >= 100 && elapsed.total_milliseconds() <= 400); -} + timer.cancel(); + getIOService()->restart(); + try { + getIOService()->poll(); + } catch (...) { + } +} } diff --git a/src/bin/d2/d2_process.cc b/src/bin/d2/d2_process.cc index 426f95f2a9..fb96bce4bd 100644 --- a/src/bin/d2/d2_process.cc +++ b/src/bin/d2/d2_process.cc @@ -439,6 +439,9 @@ D2Process::reconfigureQueueMgr() { } D2Process::~D2Process() { + queue_mgr_->stopListening(); + auto f = [](D2QueueMgrPtr) {}; + getIOService()->post(std::bind(f, queue_mgr_)); } D2CfgMgrPtr diff --git a/src/bin/d2/d2_queue_mgr.cc b/src/bin/d2/d2_queue_mgr.cc index 12efe742e8..a598893d70 100644 --- a/src/bin/d2/d2_queue_mgr.cc +++ b/src/bin/d2/d2_queue_mgr.cc @@ -178,7 +178,6 @@ D2QueueMgr::updateStopState() { DHCP_DDNS_QUEUE_MGR_STOPPED); } - void D2QueueMgr::removeListener() { // Force our managing layer(s) to stop us properly first. @@ -224,7 +223,6 @@ D2QueueMgr::dequeueAt(const size_t index) { ncr_queue_.erase(pos); } - void D2QueueMgr::dequeue() { if (getQueueSize() == 0) { diff --git a/src/bin/d2/d2_queue_mgr.h b/src/bin/d2/d2_queue_mgr.h index bbd95ea016..4abf3c54d1 100644 --- a/src/bin/d2/d2_queue_mgr.h +++ b/src/bin/d2/d2_queue_mgr.h @@ -40,7 +40,6 @@ class D2QueueMgrReceiveError : public isc::Exception { isc::Exception(file, line, what) { }; }; - /// @brief Thrown if the request queue is full when an enqueue is attempted. /// @todo use or remove it. class D2QueueMgrQueueFull : public isc::Exception { @@ -63,7 +62,6 @@ class D2QueueMgrInvalidIndex : public isc::Exception { isc::Exception(file, line, what) { }; }; - /// @brief D2QueueMgr creates and manages a queue of DNS update requests. /// /// D2QueueMgr is a class specifically designed as an integral part of DHCP-DDNS. @@ -217,8 +215,8 @@ class D2QueueMgr : public dhcp_ddns::NameChangeListener::RequestReceiveHandler, /// @param ncr is a pointer to the newly received NameChangeRequest if /// result is NameChangeListener::SUCCESS. It is indeterminate other /// wise. - virtual void operator ()(const dhcp_ddns::NameChangeListener::Result result, - dhcp_ddns::NameChangeRequestPtr& ncr); + virtual void operator()(const dhcp_ddns::NameChangeListener::Result result, + dhcp_ddns::NameChangeRequestPtr& ncr); /// @brief Stops listening for requests. /// @@ -234,7 +232,6 @@ class D2QueueMgr : public dhcp_ddns::NameChangeListener::RequestReceiveHandler, /// @throw D2QueueMgrError if stop_state is a valid stop state. void stopListening(const State target_stop_state = STOPPED); - /// @brief Deletes the current listener /// /// This method will delete the current listener and returns the manager diff --git a/src/bin/d2/tests/d2_process_unittests.cc b/src/bin/d2/tests/d2_process_unittests.cc index bc6be18a17..8bbaf35ff6 100644 --- a/src/bin/d2/tests/d2_process_unittests.cc +++ b/src/bin/d2/tests/d2_process_unittests.cc @@ -113,9 +113,9 @@ class D2ProcessTest : public D2Process, public ConfigParseTest { const D2QueueMgrPtr& queue_mgr = getD2QueueMgr(); // If queue manager isn't in the RUNNING state, return failure. - if (D2QueueMgr::RUNNING != queue_mgr->getMgrState()) { + if (D2QueueMgr::RUNNING != queue_mgr->getMgrState()) { return (::testing::AssertionFailure(::testing::Message() << - "queue manager did not start")); + "queue manager did not start")); } // Good to go. @@ -578,6 +578,13 @@ TEST_F(D2ProcessTest, normalShutdown) { time_duration elapsed = stop - start; EXPECT_TRUE(elapsed.total_milliseconds() >= 1900 && elapsed.total_milliseconds() <= 2200); + + timer.cancel(); + getIOService()->restart(); + try { + getIOService()->poll(); + } catch (...) { + } } /// @brief Verifies that an "uncaught" exception thrown during event loop @@ -602,6 +609,13 @@ TEST_F(D2ProcessTest, fatalErrorShutdown) { time_duration elapsed = stop - start; EXPECT_TRUE(elapsed.total_milliseconds() >= 1900 && elapsed.total_milliseconds() <= 2200); + + timer.cancel(); + getIOService()->restart(); + try { + getIOService()->poll(); + } catch (...) { + } } /// @brief Used to permit visual inspection of logs to ensure diff --git a/src/bin/d2/tests/d2_queue_mgr_unittests.cc b/src/bin/d2/tests/d2_queue_mgr_unittests.cc index dbbeec807b..5da5fe040f 100644 --- a/src/bin/d2/tests/d2_queue_mgr_unittests.cc +++ b/src/bin/d2/tests/d2_queue_mgr_unittests.cc @@ -232,6 +232,15 @@ class QueueMgrUDPTest : public virtual ::testing::Test, public D2StatTest, TEST_TIMEOUT); } + virtual ~QueueMgrUDPTest() { + test_timer_.cancel(); + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } + } + void reset_results() { sent_ncrs_.clear(); received_ncrs_.clear(); diff --git a/src/bin/d2/tests/d2_update_mgr_unittests.cc b/src/bin/d2/tests/d2_update_mgr_unittests.cc index 920ccc884e..df8de60e28 100644 --- a/src/bin/d2/tests/d2_update_mgr_unittests.cc +++ b/src/bin/d2/tests/d2_update_mgr_unittests.cc @@ -71,6 +71,7 @@ class D2UpdateMgrTest : public TimedIO, public ConfigParseTest { D2UpdateMgrWrapperPtr update_mgr_; std::vector canned_ncrs_; size_t canned_count_; + boost::shared_ptr server_; D2UpdateMgrTest() { queue_mgr_.reset(new D2QueueMgr(io_service_)); @@ -82,6 +83,14 @@ class D2UpdateMgrTest : public TimedIO, public ConfigParseTest { } ~D2UpdateMgrTest() { + if (server_) { + server_->stop(); + } + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } } /// @brief Creates a list of valid NameChangeRequest. @@ -184,11 +193,11 @@ class D2UpdateMgrTest : public TimedIO, public ConfigParseTest { TransactionList::iterator it = update_mgr_->transactionListBegin(); while (it != update_mgr_->transactionListEnd()) { if (((*it).second)->isModelWaiting()) { - return true; + return (true); } } - return false; + return (false); } /// @brief Process events until all requests have been completed. @@ -692,8 +701,8 @@ TEST_F(D2UpdateMgrTest, addTransaction) { // Create a server based on the transaction's current server, and // start it listening. - FauxServer server(io_service_, *(trans->getCurrentServer())); - server.receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); + server_.reset(new FauxServer(io_service_, *(trans->getCurrentServer()))); + server_->receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); // Run sweep and IO until everything is done. processAll(); @@ -749,8 +758,8 @@ TEST_F(D2UpdateMgrTest, removeTransaction) { // Create a server based on the transaction's current server, and // start it listening. - FauxServer server(io_service_, *(trans->getCurrentServer())); - server.receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); + server_.reset(new FauxServer(io_service_, *(trans->getCurrentServer()))); + server_->receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); // Run sweep and IO until everything is done. processAll(); @@ -797,8 +806,8 @@ TEST_F(D2UpdateMgrTest, errorTransaction) { ASSERT_TRUE(trans->getCurrentServer()); // Create a server and start it listening. - FauxServer server(io_service_, *(trans->getCurrentServer())); - server.receive(FauxServer::CORRUPT_RESP); + server_.reset(new FauxServer(io_service_, *(trans->getCurrentServer()))); + server_->receive(FauxServer::CORRUPT_RESP); // Run sweep and IO until everything is done. processAll(); @@ -836,8 +845,8 @@ TEST_F(D2UpdateMgrTest, multiTransaction) { // that all of configured servers have the same address. // and start it listening. asiolink::IOAddress server_ip("127.0.0.1"); - FauxServer server(io_service_, server_ip, 5301); - server.receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); + server_.reset(new FauxServer(io_service_, server_ip, 5301)); + server_->receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); // Run sweep and IO until everything is done. processAll(); @@ -908,8 +917,8 @@ TEST_F(D2UpdateMgrTest, simpleAddTransaction) { // Create a server based on the transaction's current server, and // start it listening. - FauxServer server(io_service_, *(trans->getCurrentServer())); - server.receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); + server_.reset(new FauxServer(io_service_, *(trans->getCurrentServer()))); + server_->receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); // Run sweep and IO until everything is done. processAll(); @@ -966,8 +975,8 @@ TEST_F(D2UpdateMgrTest, simpleRemoveTransaction) { // Create a server based on the transaction's current server, and // start it listening. - FauxServer server(io_service_, *(trans->getCurrentServer())); - server.receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); + server_.reset(new FauxServer(io_service_, *(trans->getCurrentServer()))); + server_->receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR()); // Run sweep and IO until everything is done. processAll(); diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index d726322ef6..80bba69d43 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -705,6 +705,11 @@ Dhcpv4Srv::~Dhcpv4Srv() { } LOG_ERROR(dhcp4_logger, DHCP4_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg); } + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } } void diff --git a/src/bin/dhcp4/tests/classify_unittest.cc b/src/bin/dhcp4/tests/classify_unittest.cc index d759245d4a..7f81dbd172 100644 --- a/src/bin/dhcp4/tests/classify_unittest.cc +++ b/src/bin/dhcp4/tests/classify_unittest.cc @@ -521,7 +521,6 @@ class ClassifyTest : public Dhcpv4SrvTest { IfaceMgrTestConfig iface_mgr_test_config_; }; - // This test checks that an incoming DISCOVER that does not match any classes // will get the fixed fields empty. TEST_F(ClassifyTest, fixedFieldsDiscoverNoClasses) { @@ -538,7 +537,6 @@ TEST_F(ClassifyTest, fixedFieldsInformNoClasses) { testFixedFields(CONFIGS[0], DHCPINFORM, OptionPtr(), "0.0.0.0", "", ""); } - // This test checks that an incoming DISCOVER that does match a class that has // next-server specified will result in a response that has the next-server set. TEST_F(ClassifyTest, fixedFieldsDiscoverNextServer) { @@ -561,7 +559,6 @@ TEST_F(ClassifyTest, fixedFieldsInformNextServer) { testFixedFields(CONFIGS[0], DHCPINFORM, pxe, "1.2.3.4", "", ""); } - // This test checks that an incoming DISCOVER that does match a class that has // server-hostname specified will result in a response that has the sname field set. TEST_F(ClassifyTest, fixedFieldsDiscoverHostname) { @@ -584,7 +581,6 @@ TEST_F(ClassifyTest, fixedFieldsInformHostname) { testFixedFields(CONFIGS[0], DHCPINFORM, pxe, "0.0.0.0", "deneb", ""); } - // This test checks that an incoming DISCOVER that does match a class that has // boot-file-name specified will result in a response that has the filename field set. TEST_F(ClassifyTest, fixedFieldsDiscoverFile1) { @@ -607,7 +603,6 @@ TEST_F(ClassifyTest, fixedFieldsInformFile1) { testFixedFields(CONFIGS[0], DHCPDISCOVER, pxe, "0.0.0.0", "", "pxelinux.0"); } - // This test checks that an incoming DISCOVER that does match a different class that has // boot-file-name specified will result in a response that has the filename field set. TEST_F(ClassifyTest, fixedFieldsDiscoverFile2) { @@ -703,7 +698,6 @@ TEST_F(ClassifyTest, fixedFieldsInformNoClasses2) { testFixedFields(CONFIGS[2], DHCPINFORM, OptionPtr(), "0.0.0.0", "", ""); } - // This test checks that an incoming DISCOVER that does match a class that has // next-server specified will result in a response that has the next-server set. TEST_F(ClassifyTest, fixedFieldsDiscoverNextServer2) { @@ -726,7 +720,6 @@ TEST_F(ClassifyTest, fixedFieldsInformNextServer2) { testFixedFields(CONFIGS[2], DHCPINFORM, pxe, "1.2.3.4", "", ""); } - // This test checks that an incoming DISCOVER that does match a class that has // boot-file-name specified will result in a response that has the filename field set. TEST_F(ClassifyTest, fixedFieldsDiscoverFile21) { @@ -749,7 +742,6 @@ TEST_F(ClassifyTest, fixedFieldsInformFile21) { testFixedFields(CONFIGS[2], DHCPDISCOVER, pxe, "0.0.0.0", "", "pxelinux.0"); } - // This test checks that an incoming DISCOVER that does match a different class that has // boot-file-name specified will result in a response that has the filename field set. TEST_F(ClassifyTest, fixedFieldsDiscoverFile22) { @@ -800,7 +792,6 @@ TEST_F(ClassifyTest, fixedFieldsInformNextServer3) { testFixedFields(CONFIGS[3], DHCPINFORM, pxe, "0.0.0.0", "", ""); } - // Class pxe2 is only-if-required but the subnet requires its evaluation TEST_F(ClassifyTest, fixedFieldsDiscoverHostname3) { OptionPtr pxe(new OptionInt(Option::V4, 93, 0x0007)); diff --git a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc index 2f85202220..04a567baf9 100644 --- a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc @@ -135,6 +135,7 @@ class CtrlChannelDhcpv4SrvTest : public ::testing::Test { CommandMgr::instance().setConnectionTimeout(TIMEOUT_DHCP_SERVER_RECEIVE_COMMAND); server_.reset(); + reset(); IfaceMgr::instance().setTestMode(false); IfaceMgr::instance().setDetectCallback(std::bind(&IfaceMgr::checkDetectIfaces, IfaceMgr::instancePtr().get(), ph::_1)); @@ -806,7 +807,8 @@ TEST_F(CtrlChannelDhcpv4SrvTest, configSet) { " \"name\": \"kea\", \n" " \"severity\": \"FATAL\", \n" " \"output-options\": [{ \n" - " \"output\": \"/dev/null\" \n" + " \"output\": \"/dev/null\", \n" + " \"maxsize\": 0" " }] \n" " }] \n"; @@ -1021,7 +1023,8 @@ TEST_F(CtrlChannelDhcpv4SrvTest, configTest) { " \"name\": \"kea\", \n" " \"severity\": \"FATAL\", \n" " \"output-options\": [{ \n" - " \"output\": \"/dev/null\" \n" + " \"output\": \"/dev/null\", \n" + " \"maxsize\": 0" " }] \n" " }] \n"; diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc index 7063961526..73cae9b8e7 100644 --- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc @@ -2874,15 +2874,6 @@ Dhcpv4SrvTest::loadConfigFile(const string& path) { return (ConfigBackendDHCPv4Ptr()); }); - // TimerMgr uses IO service to run asynchronous timers. - TimerMgr::instance()->setIOService(srv.getIOService()); - - // CommandMgr uses IO service to run asynchronous socket operations. - CommandMgr::instance().setIOService(srv.getIOService()); - - // DatabaseConnection uses IO service to run asynchronous timers. - DatabaseConnection::setIOService(srv.getIOService()); - Parser4Context parser; ConstElementPtr json; ASSERT_NO_THROW(json = parser.parseFile(path, Parser4Context::PARSER_DHCP4)); diff --git a/src/bin/dhcp4/tests/dhcp4_test_utils.h b/src/bin/dhcp4/tests/dhcp4_test_utils.h index dce7e2ca44..2db8a1ac5a 100644 --- a/src/bin/dhcp4/tests/dhcp4_test_utils.h +++ b/src/bin/dhcp4/tests/dhcp4_test_utils.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -126,6 +127,10 @@ class NakedDhcpv4Srv: public Dhcpv4Srv { server_id_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, asiolink::IOAddress("192.0.3.1"))); db::DatabaseConnection::setIOService(getIOService()); + + dhcp::TimerMgr::instance()->setIOService(getIOService()); + + config::CommandMgr::instance().setIOService(getIOService()); } /// @brief Returns fixed server identifier assigned to the naked server @@ -199,6 +204,14 @@ class NakedDhcpv4Srv: public Dhcpv4Srv { } virtual ~NakedDhcpv4Srv() { + // Close the lease database + isc::dhcp::LeaseMgrFactory::destroy(); + + getIOService()->restart(); + try { + getIOService()->poll(); + } catch (...) { + } } /// @brief Runs processing DHCPDISCOVER. diff --git a/src/bin/dhcp4/tests/kea_controller_unittest.cc b/src/bin/dhcp4/tests/kea_controller_unittest.cc index f5877d8f36..1d76f4c581 100644 --- a/src/bin/dhcp4/tests/kea_controller_unittest.cc +++ b/src/bin/dhcp4/tests/kea_controller_unittest.cc @@ -201,6 +201,7 @@ class JSONFileBackendTest : public isc::dhcp::test::BaseServerTest { ~JSONFileBackendTest() { LeaseMgrFactory::destroy(); + isc::log::setDefaultLoggingOutput(); static_cast(remove(TEST_FILE)); static_cast(remove(TEST_INCLUDE)); }; diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 2fdbafd2fc..b4db600e5e 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -302,6 +302,11 @@ Dhcpv6Srv::~Dhcpv6Srv() { } LOG_ERROR(dhcp6_logger, DHCP6_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg); } + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } } void Dhcpv6Srv::shutdown() { diff --git a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc index a00f0c7135..1150b1f577 100644 --- a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,13 @@ class CtrlChannelDhcpv6SrvTest : public CtrlDhcpv6SrvTest { /// @brief Destructor ~CtrlChannelDhcpv6SrvTest() { + LeaseMgrFactory::destroy(); + StatsMgr::instance().removeAll(); + + CommandMgr::instance().closeCommandSocket(); + CommandMgr::instance().deregisterAll(); + CommandMgr::instance().setConnectionTimeout(TIMEOUT_DHCP_SERVER_RECEIVE_COMMAND); + server_.reset(); reset(); IfaceMgr::instance().setTestMode(false); @@ -716,7 +724,8 @@ TEST_F(CtrlChannelDhcpv6SrvTest, configSet) { " \"name\": \"kea\", \n" " \"severity\": \"FATAL\", \n" " \"output-options\": [{ \n" - " \"output\": \"/dev/null\" \n" + " \"output\": \"/dev/null\", \n" + " \"maxsize\": 0" " }] \n" " }] \n"; @@ -932,7 +941,8 @@ TEST_F(CtrlChannelDhcpv6SrvTest, configTest) { " \"name\": \"kea\", \n" " \"severity\": \"FATAL\", \n" " \"output-options\": [{ \n" - " \"output\": \"/dev/null\" \n" + " \"output\": \"/dev/null\", \n" + " \"maxsize\": 0" " }] \n" " }] \n"; diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index 13234df3a9..1cc9abf239 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -243,15 +243,6 @@ Dhcpv6SrvTest::loadConfigFile(const string& path) { return (ConfigBackendDHCPv6Ptr()); }); - // TimerMgr uses IO service to run asynchronous timers. - TimerMgr::instance()->setIOService(srv.getIOService()); - - // CommandMgr uses IO service to run asynchronous socket operations. - CommandMgr::instance().setIOService(srv.getIOService()); - - // DatabaseConnection uses IO service to run asynchronous timers. - DatabaseConnection::setIOService(srv.getIOService()); - Parser6Context parser; ConstElementPtr json; ASSERT_NO_THROW(json = parser.parseFile(path, Parser6Context::PARSER_DHCP6)); diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h index da23b936f5..57d2894bc3 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.h +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,10 @@ class NakedDhcpv6Srv: public isc::dhcp::Dhcpv6Srv { std::string memfile = "type=memfile universe=6 persist=false"; isc::dhcp::LeaseMgrFactory::create(memfile); db::DatabaseConnection::setIOService(getIOService()); + + dhcp::TimerMgr::instance()->setIOService(getIOService()); + + config::CommandMgr::instance().setIOService(getIOService()); } /// @brief fakes packet reception @@ -209,6 +214,12 @@ class NakedDhcpv6Srv: public isc::dhcp::Dhcpv6Srv { virtual ~NakedDhcpv6Srv() { // Close the lease database isc::dhcp::LeaseMgrFactory::destroy(); + + getIOService()->restart(); + try { + getIOService()->poll(); + } catch (...) { + } } /// @brief Processes incoming Solicit message. diff --git a/src/bin/dhcp6/tests/kea_controller_unittest.cc b/src/bin/dhcp6/tests/kea_controller_unittest.cc index 068fc96845..960890131d 100644 --- a/src/bin/dhcp6/tests/kea_controller_unittest.cc +++ b/src/bin/dhcp6/tests/kea_controller_unittest.cc @@ -188,8 +188,7 @@ class NakedControlledDhcpv6Srv: public ControlledDhcpv6Srv { class JSONFileBackendTest : public dhcp::test::BaseServerTest { public: - JSONFileBackendTest() - : BaseServerTest() { + JSONFileBackendTest() { } ~JSONFileBackendTest() { diff --git a/src/bin/netconf/http_control_socket.cc b/src/bin/netconf/http_control_socket.cc index 197c51916c..801cfb5b98 100644 --- a/src/bin/netconf/http_control_socket.cc +++ b/src/bin/netconf/http_control_socket.cc @@ -101,6 +101,13 @@ HttpControlSocket::sendCommand(ConstElementPtr command) { // Perform this synchronously. io_service->run(); + client.stop(); + io_service->restart(); + try { + io_service->poll(); + } catch (...) { + } + if (received_ec) { // Got an error code. isc_throw(ControlSocketError, "communication error (code): " diff --git a/src/bin/netconf/tests/control_socket_unittests.cc b/src/bin/netconf/tests/control_socket_unittests.cc index 996bcbae40..10f36f71da 100644 --- a/src/bin/netconf/tests/control_socket_unittests.cc +++ b/src/bin/netconf/tests/control_socket_unittests.cc @@ -157,11 +157,12 @@ class UnixControlSocketTest : public ThreadedTest { thread_->join(); thread_.reset(); } - // io_service must be stopped after the thread returns, - // otherwise the thread may never return if it is - // waiting for the completion of some asynchronous tasks. - io_service_->stop(); removeUnixSocketFile(); + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } } /// @brief Returns socket file path. @@ -525,10 +526,15 @@ class HttpControlSocketTest : public ThreadedTest { thread_->join(); thread_.reset(); } - // io_service must be stopped after the thread returns, - // otherwise the thread may never return if it is - // waiting for the completion of some asynchronous tasks. - io_service_->stop(); + if (listener_) { + listener_->stop(); + } + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } + listener_.reset(); } /// @brief Returns socket URL. @@ -568,7 +574,7 @@ class HttpControlSocketTest : public ThreadedTest { while (!isStopping()) { io_service_->runOne(); } - // Main thread signalled that the thread should + // Main thread signaled that the thread should // terminate. Launch any outstanding IO service // handlers. io_service_->poll(); diff --git a/src/bin/netconf/tests/netconf_process_unittests.cc b/src/bin/netconf/tests/netconf_process_unittests.cc index 3cfdbd040a..a8c85cf6f1 100644 --- a/src/bin/netconf/tests/netconf_process_unittests.cc +++ b/src/bin/netconf/tests/netconf_process_unittests.cc @@ -80,6 +80,12 @@ TEST_F(NetconfProcessTest, shutdown) { time_duration elapsed = stop - start; EXPECT_TRUE(elapsed.total_milliseconds() >= 100 && elapsed.total_milliseconds() <= 400); + timer.cancel(); + getIOService()->restart(); + try { + getIOService()->poll(); + } catch (...) { + } } } diff --git a/src/bin/netconf/tests/netconf_unittests.cc b/src/bin/netconf/tests/netconf_unittests.cc index fd3340d33c..989034028f 100644 --- a/src/bin/netconf/tests/netconf_unittests.cc +++ b/src/bin/netconf/tests/netconf_unittests.cc @@ -121,11 +121,6 @@ class NetconfAgentTest : public ThreadedTest { thread_->join(); thread_.reset(); } - // io_service must be stopped after the thread returns, - // otherwise the thread may never return if it is - // waiting for the completion of some asynchronous tasks. - io_service_->stop(); - io_service_.reset(); if (agent_) { clearYang(agent_); agent_->clear(); @@ -135,6 +130,11 @@ class NetconfAgentTest : public ThreadedTest { responses_.clear(); removeUnixSocketFile(); SysrepoSetup::cleanSharedMemory(); + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } } /// @brief Returns socket file path. diff --git a/src/hooks/dhcp/high_availability/communication_state.cc b/src/hooks/dhcp/high_availability/communication_state.cc index 38b7566df3..2e9d1beae4 100644 --- a/src/hooks/dhcp/high_availability/communication_state.cc +++ b/src/hooks/dhcp/high_availability/communication_state.cc @@ -229,6 +229,8 @@ void CommunicationState::stopHeartbeatInternal() { if (timer_) { timer_->cancel(); + auto f = [](IntervalTimerPtr) {}; + io_service_->post(std::bind(f, timer_)); timer_.reset(); interval_ = 0; heartbeat_impl_ = 0; diff --git a/src/hooks/dhcp/high_availability/ha_service.cc b/src/hooks/dhcp/high_availability/ha_service.cc index d148afa81e..3ec6d8ca15 100644 --- a/src/hooks/dhcp/high_availability/ha_service.cc +++ b/src/hooks/dhcp/high_availability/ha_service.cc @@ -2448,6 +2448,14 @@ HAService::synchronize(std::string& status_message, const std::string& server_na // End measuring duration. stopwatch.stop(); + client.stop(); + + io_service->restart(); + try { + io_service->poll(); + } catch (...) { + } + // If an error message has been recorded, return an error to the controlling // client. if (!status_message.empty()) { @@ -2586,6 +2594,14 @@ HAService::sendLeaseUpdatesFromBacklog() { // End measuring duration. stopwatch.stop(); + client.stop(); + + io_service->restart(); + try { + io_service->poll(); + } catch (...) { + } + if (updates_successful) { LOG_INFO(ha_logger, HA_LEASES_BACKLOG_SUCCESS) .arg(config_->getThisServerName()) @@ -2665,6 +2681,14 @@ HAService::sendHAReset() { // Run the IO service until it is stopped by the callback. This makes it synchronous. io_service->run(); + client.stop(); + + io_service->restart(); + try { + io_service->poll(); + } catch (...) { + } + return (reset_successful); } @@ -2824,6 +2848,14 @@ HAService::processMaintenanceStart() { // makes it synchronous. io_service->run(); + client.stop(); + + io_service->restart(); + try { + io_service->poll(); + } catch (...) { + } + // If there was a communication problem with the partner we assume that // the partner is already down while we receive this command. if (captured_ec || (captured_rcode == CONTROL_RESULT_ERROR)) { @@ -2938,6 +2970,14 @@ HAService::processMaintenanceCancel() { // makes it synchronous. io_service->run(); + client.stop(); + + io_service->restart(); + try { + io_service->poll(); + } catch (...) { + } + // There was an error in communication with the partner or the // partner was unable to revert its state. if (!error_message.empty()) { diff --git a/src/hooks/dhcp/high_availability/tests/ha_impl_unittest.cc b/src/hooks/dhcp/high_availability/tests/ha_impl_unittest.cc index 0f5c18f172..4f7eb1a5a3 100644 --- a/src/hooks/dhcp/high_availability/tests/ha_impl_unittest.cc +++ b/src/hooks/dhcp/high_availability/tests/ha_impl_unittest.cc @@ -74,6 +74,25 @@ class TestHAImpl : public HAImpl { /// @brief Test fixture class for @c HAImpl. class HAImplTest : public HATest { public: + /// @brief Constructor. + HAImplTest() { + } + + /// @brief Destructor. + ~HAImplTest() { + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } + ha_impl_.reset(); + test_ha_impl_.reset(); + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } + } /// @brief Tests handler of a ha-sync command. /// @@ -84,65 +103,85 @@ class HAImplTest : public HATest { /// @param expected_response expected text response. void testSynchronizeHandler(const std::string& ha_sync_command, const std::string& expected_response) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + io_service_.reset(new IOService); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON(ha_sync_command); CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.synchronizeHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->synchronizeHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); ASSERT_TRUE(response); checkAnswer(response, CONTROL_RESULT_ERROR, expected_response); + callout_handle.reset(); + + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } + ha_impl_.reset(); + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } } + + /// @brief HA Instance under test. + boost::shared_ptr test_ha_impl_; + + /// @brief HA Instance under test. + boost::shared_ptr ha_impl_; }; // Tests that HAService object is created for DHCPv4 service. TEST_F(HAImplTest, startServices) { // Valid configuration must be provided prior to starting the service. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); // Network state is also required. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); // Start the service for DHCPv4 server. - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // Make sure that the HA service has been created for the requested // server type. - ASSERT_TRUE(ha_impl.services_); - EXPECT_EQ(HAServerType::DHCPv4, ha_impl.services_->get()->getServerType()); + ASSERT_TRUE(test_ha_impl_->services_); + EXPECT_EQ(HAServerType::DHCPv4, test_ha_impl_->services_->get()->getServerType()); } // Tests that HAService object is created for DHCPv6 service. TEST_F(HAImplTest, startServices6) { // Valid configuration must be provided prior to starting the service. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); // Network state is also required. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); // Start the service for DHCPv4 server. - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // Make sure that the HA service has been created for the requested // server type. - ASSERT_TRUE(ha_impl.services_); - EXPECT_EQ(HAServerType::DHCPv6, ha_impl.services_->get()->getServerType()); + ASSERT_TRUE(test_ha_impl_->services_); + EXPECT_EQ(HAServerType::DHCPv6, test_ha_impl_->services_->get()->getServerType()); } // Tests for buffer4_receive callout implementation. @@ -152,17 +191,17 @@ TEST_F(HAImplTest, buffer4Receive) { ConstElementPtr ha_config = createValidJsonConfiguration(HAConfig::HOT_STANDBY); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // Initially the HA service is in the waiting state and serves no scopes. // We need to explicitly enable the scope to be served. - ha_impl.services_->get()->serveDefaultScopes(); + test_ha_impl_->services_->get()->serveDefaultScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -198,7 +237,7 @@ TEST_F(HAImplTest, buffer4Receive) { callout_handle->setArgument("query4", query4); // Invoke the buffer4_receive callout. - ASSERT_NO_THROW(ha_impl.buffer4Receive(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->buffer4Receive(*callout_handle)); // The BOOTP messages are not supported so trying to unpack the message // should trigger an error. The callout should set the next step to @@ -233,7 +272,7 @@ TEST_F(HAImplTest, buffer4Receive) { callout_handle->setArgument("query4", query4); // Invoke the callout again. - ASSERT_NO_THROW(ha_impl.buffer4Receive(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->buffer4Receive(*callout_handle)); // This time the callout should set the next step to SKIP to indicate to // the DHCP server that the message has been already parsed. @@ -259,19 +298,19 @@ TEST_F(HAImplTest, subnet4Select) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // The hub is a standby server and by default serves no scopes. Explicitly // enable the failover scopes to make this server responsible for the // received packets. - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -291,7 +330,7 @@ TEST_F(HAImplTest, subnet4Select) { callout_handle->setArgument("subnet4", subnet4); // Invoke the subnet4_select callout. - ASSERT_NO_THROW(ha_impl.subnet4Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet4Select(*callout_handle)); // Make sure that the request was not dropped. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); @@ -313,19 +352,19 @@ TEST_F(HAImplTest, subnet4SelectSharedNetwork) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // The hub is a standby server and by default serves no scopes. Explicitly // enable the failover scopes to make this server responsible for the // received packets. - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -348,7 +387,7 @@ TEST_F(HAImplTest, subnet4SelectSharedNetwork) { callout_handle->setArgument("subnet4", subnet4); // Invoke the subnet4_select callout. - ASSERT_NO_THROW(ha_impl.subnet4Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet4Select(*callout_handle)); // Make sure that the request was not dropped. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); @@ -370,13 +409,13 @@ TEST_F(HAImplTest, subnet4SelectSingleRelationship) { ConstElementPtr ha_config = createValidJsonConfiguration(HAConfig::HOT_STANDBY); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // Create callout handle to be used for passing arguments to the // callout. @@ -394,7 +433,7 @@ TEST_F(HAImplTest, subnet4SelectSingleRelationship) { callout_handle->setArgument("subnet4", subnet4); // Invoke the subnet4_select callout. - ASSERT_NO_THROW(ha_impl.subnet4Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet4Select(*callout_handle)); // The request should not be dropped and there should be no classes assigned // because the callout didn't call the HAService::inScope function. @@ -408,19 +447,19 @@ TEST_F(HAImplTest, subnet4SelectDropNoServerName) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // The hub is a standby server and by default serves no scopes. Explicitly // enable the failover scopes to make this server responsible for the // received packets. - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -437,7 +476,7 @@ TEST_F(HAImplTest, subnet4SelectDropNoServerName) { callout_handle->setArgument("subnet4", subnet4); // Invoke the subnet4_select callout. - ASSERT_NO_THROW(ha_impl.subnet4Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet4Select(*callout_handle)); // The request should be dropped and no classes assigned to it. EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, callout_handle->getStatus()); @@ -450,19 +489,19 @@ TEST_F(HAImplTest, subnet4SelectDropInvalidServerNameType) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // The hub is a standby server and by default serves no scopes. Explicitly // enable the failover scopes to make this server responsible for the // received packets. - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -483,7 +522,7 @@ TEST_F(HAImplTest, subnet4SelectDropInvalidServerNameType) { callout_handle->setArgument("subnet4", subnet4); // Invoke the subnet4_select callout. - ASSERT_NO_THROW(ha_impl.subnet4Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet4Select(*callout_handle)); // The request should be dropped and no classes assigned to it. EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, callout_handle->getStatus()); @@ -496,18 +535,18 @@ TEST_F(HAImplTest, subnet4SelectDropNotInScope) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // This server serves server1/server2 scopes but not server3/server4 scopes. // The request should be dropped because the subnet will be associated with // the server3. - ha_impl.services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -528,7 +567,7 @@ TEST_F(HAImplTest, subnet4SelectDropNotInScope) { callout_handle->setArgument("subnet4", subnet4); // Invoke the subnet4_select callout. - ASSERT_NO_THROW(ha_impl.subnet4Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet4Select(*callout_handle)); // The request should be dropped because the server is not responsible for // this scope currently. @@ -544,16 +583,16 @@ TEST_F(HAImplTest, subnet4SelectNoSubnet) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -570,7 +609,7 @@ TEST_F(HAImplTest, subnet4SelectNoSubnet) { callout_handle->setArgument("subnet4", subnet4); // Invoke the subnet4_select callout. - ASSERT_NO_THROW(ha_impl.subnet4Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet4Select(*callout_handle)); // No subnet has been selected and we have multiple relationships. We // expect that the server drops the packet. @@ -587,17 +626,17 @@ TEST_F(HAImplTest, buffer6Receive) { ConstElementPtr ha_config = createValidJsonConfiguration(HAConfig::HOT_STANDBY); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // Initially the HA service is in the waiting state and serves no scopes. // We need to explicitly enable the scope to be served. - ha_impl.services_->get()->serveDefaultScopes(); + test_ha_impl_->services_->get()->serveDefaultScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -618,7 +657,7 @@ TEST_F(HAImplTest, buffer6Receive) { callout_handle->setArgument("query6", query6); // Invoke the buffer6_receive callout. - ASSERT_NO_THROW(ha_impl.buffer6Receive(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->buffer6Receive(*callout_handle)); // Our DHCP messages contains no transaction id so it should cause // parsing error. The next step is set to DROP for malformed messages. @@ -650,7 +689,7 @@ TEST_F(HAImplTest, buffer6Receive) { callout_handle->setArgument("query6", query6); // Invoke the callout again. - ASSERT_NO_THROW(ha_impl.buffer6Receive(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->buffer6Receive(*callout_handle)); // This time the callout should set the next step to SKIP to indicate to // the DHCP server that the message has been already parsed. @@ -674,19 +713,19 @@ TEST_F(HAImplTest, subnet6Select) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // The hub is a standby server and by default serves no scopes. Explicitly // enable the failover scopes to make this server responsible for the // received packets. - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -706,7 +745,7 @@ TEST_F(HAImplTest, subnet6Select) { callout_handle->setArgument("subnet6", subnet6); // Invoke the subnet6_select callout. - ASSERT_NO_THROW(ha_impl.subnet6Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet6Select(*callout_handle)); // Make sure that the request was not dropped. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); @@ -728,19 +767,19 @@ TEST_F(HAImplTest, subnet6SelectSharedNetwork) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // The hub is a standby server and by default serves no scopes. Explicitly // enable the failover scopes to make this server responsible for the // received packets. - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -763,7 +802,7 @@ TEST_F(HAImplTest, subnet6SelectSharedNetwork) { callout_handle->setArgument("subnet6", subnet6); // Invoke the subnet6_select callout. - ASSERT_NO_THROW(ha_impl.subnet6Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet6Select(*callout_handle)); // Make sure that the request was not dropped. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); @@ -785,13 +824,13 @@ TEST_F(HAImplTest, subnet6SelectSingleRelationship) { ConstElementPtr ha_config = createValidJsonConfiguration(HAConfig::HOT_STANDBY); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // Create callout handle to be used for passing arguments to the // callout. @@ -809,7 +848,7 @@ TEST_F(HAImplTest, subnet6SelectSingleRelationship) { callout_handle->setArgument("subnet6", subnet6); // Invoke the subnet6_select callout. - ASSERT_NO_THROW(ha_impl.subnet6Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet6Select(*callout_handle)); // The request should not be dropped and there should be no classes assigned // because the callout didn't call the HAService::inScope function. @@ -823,19 +862,19 @@ TEST_F(HAImplTest, subnet6SelectDropNoServerName) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // The hub is a standby server and by default serves no scopes. Explicitly // enable the failover scopes to make this server responsible for the // received packets. - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -852,7 +891,7 @@ TEST_F(HAImplTest, subnet6SelectDropNoServerName) { callout_handle->setArgument("subnet6", subnet6); // Invoke the subnet6_select callout. - ASSERT_NO_THROW(ha_impl.subnet6Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet6Select(*callout_handle)); // The request should be dropped and no classes assigned to it. EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, callout_handle->getStatus()); @@ -865,19 +904,19 @@ TEST_F(HAImplTest, subnet6SelectDropInvalidServerNameType) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // The hub is a standby server and by default serves no scopes. Explicitly // enable the failover scopes to make this server responsible for the // received packets. - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -898,7 +937,7 @@ TEST_F(HAImplTest, subnet6SelectDropInvalidServerNameType) { callout_handle->setArgument("subnet6", subnet6); // Invoke the subnet6_select callout. - ASSERT_NO_THROW(ha_impl.subnet6Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet6Select(*callout_handle)); // The request should be dropped and no classes assigned to it. EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, callout_handle->getStatus()); @@ -911,18 +950,18 @@ TEST_F(HAImplTest, subnet6SelectDropNotInScope) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // This server serves server1/server2 scopes but not server3/server4 scopes. // The request should be dropped because the subnet will be associated with // the server3. - ha_impl.services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -943,7 +982,7 @@ TEST_F(HAImplTest, subnet6SelectDropNotInScope) { callout_handle->setArgument("subnet6", subnet6); // Invoke the subnet6_select callout. - ASSERT_NO_THROW(ha_impl.subnet6Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet6Select(*callout_handle)); // The request should be dropped because the server is not responsible for // this scope currently. @@ -959,16 +998,16 @@ TEST_F(HAImplTest, subnet6SelectNoSubnet) { ConstElementPtr ha_config = createValidHubJsonConfiguration(); // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(ha_config)); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); // Starting the service is required before any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); - ha_impl.services_->get("server2")->serveFailoverScopes(); - ha_impl.services_->get("server4")->serveFailoverScopes(); + test_ha_impl_->services_->get("server2")->serveFailoverScopes(); + test_ha_impl_->services_->get("server4")->serveFailoverScopes(); // Create callout handle to be used for passing arguments to the // callout. @@ -985,7 +1024,7 @@ TEST_F(HAImplTest, subnet6SelectNoSubnet) { callout_handle->setArgument("subnet6", subnet6); // Invoke the subnet6_select callout. - ASSERT_NO_THROW(ha_impl.subnet6Select(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->subnet6Select(*callout_handle)); // No subnet has been selected and we have multiple relationships. We // expect that the server drops the packet. @@ -998,18 +1037,18 @@ TEST_F(HAImplTest, subnet6SelectNoSubnet) { // Tests leases4_committed callout implementation. TEST_F(HAImplTest, leases4Committed) { // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // Make sure we wait for the acks from the backup server to be able to // test the case of sending lease updates even though the service is // in the state in which the lease updates are normally not sent. - ha_impl.config_->get()->setWaitBackupAck(true); + test_ha_impl_->config_->get()->setWaitBackupAck(true); // Create callout handle to be used for passing arguments to the // callout. @@ -1038,7 +1077,7 @@ TEST_F(HAImplTest, leases4Committed) { HooksManager::park("leases4_committed", query4, []{}); // There are no leases so the callout should return. - ASSERT_NO_THROW(ha_impl.leases4Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases4Committed(*callout_handle)); // No updates are generated so the default status should not be modified. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); @@ -1053,27 +1092,27 @@ TEST_F(HAImplTest, leases4Committed) { leases4->push_back(lease4); callout_handle->setArgument("leases4", leases4); - ha_impl.config_->get()->setSendLeaseUpdates(false); + test_ha_impl_->config_->get()->setSendLeaseUpdates(false); // Park the packet. HooksManager::park("leases4_committed", query4, []{}); // Run the callout again. - ASSERT_NO_THROW(ha_impl.leases4Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases4Committed(*callout_handle)); // No updates are generated so the default status should not be modified. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); EXPECT_TRUE(callout_handle->getParkingLotHandlePtr()->drop(query4)); // Enable updates and retry. - ha_impl.config_->get()->setSendLeaseUpdates(true); + test_ha_impl_->config_->get()->setSendLeaseUpdates(true); callout_handle->setArgument("leases4", leases4); // Park the packet. HooksManager::park("leases4_committed", query4, []{}); // Run the callout again. - ASSERT_NO_THROW(ha_impl.leases4Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases4Committed(*callout_handle)); // This time the lease update should be generated and the status should // be set to "park". @@ -1084,18 +1123,18 @@ TEST_F(HAImplTest, leases4Committed) { // Tests leases4_committed callout implementation for multiple relationships. TEST_F(HAImplTest, leases4CommittedMultipleRelationships) { // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidHubJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); // Starting the service is required before running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // By enabling this setting we ensure that the lease updates are always // scheduled and the packet is parked because it is independent of a // server state. - ha_impl.config_->get("server2")->setWaitBackupAck(true); + test_ha_impl_->config_->get("server2")->setWaitBackupAck(true); // Create callout handle to be used for passing arguments to the // callout. @@ -1128,7 +1167,7 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationships) { HooksManager::park("leases4_committed", query4, []{}); // Run the callout. - ASSERT_NO_THROW(ha_impl.leases4Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases4Committed(*callout_handle)); // Make sure the callout completed successfully. The "park" status means // there was no error during the callout. @@ -1140,18 +1179,18 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationships) { // the relationship is not found. TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsNoServerName) { // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidHubJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); // Starting the service is required before running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // By enabling this setting we ensure that the lease updates are always // scheduled and the packet is parked because it is independent of a // server state. - ha_impl.config_->get("server2")->setWaitBackupAck(true); + test_ha_impl_->config_->get("server2")->setWaitBackupAck(true); // Create callout handle to be used for passing arguments to the // callout. @@ -1181,7 +1220,7 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsNoServerName) { HooksManager::park("leases4_committed", query4, []{}); // Run the callout. - ASSERT_NO_THROW(ha_impl.leases4Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases4Committed(*callout_handle)); // The relationship was not found so the packet should be dropped. EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, callout_handle->getStatus()); @@ -1192,18 +1231,18 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsNoServerName) { // the relationship name is invalid. TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsInvalidServerName) { // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidHubJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); // Starting the service is required before running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // By enabling this setting we ensure that the lease updates are always // scheduled and the packet is parked because it is independent of a // server state. - ha_impl.config_->get("server2")->setWaitBackupAck(true); + test_ha_impl_->config_->get("server2")->setWaitBackupAck(true); // Create callout handle to be used for passing arguments to the // callout. @@ -1236,7 +1275,7 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsInvalidServerName) { HooksManager::park("leases4_committed", query4, []{}); // Run the callout. - ASSERT_NO_THROW(ha_impl.leases4Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases4Committed(*callout_handle)); // The relationship was not found so the packet should be dropped. EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, callout_handle->getStatus()); @@ -1246,18 +1285,18 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsInvalidServerName) { // Tests leases6_committed callout implementation. TEST_F(HAImplTest, leases6Committed) { // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // Make sure we wait for the acks from the backup server to be able to // test the case of sending lease updates even though the service is // in the state in which the lease updates are normally not sent. - ha_impl.config_->get()->setWaitBackupAck(true); + test_ha_impl_->config_->get()->setWaitBackupAck(true); // Create callout handle to be used for passing arguments to the // callout. @@ -1286,7 +1325,7 @@ TEST_F(HAImplTest, leases6Committed) { HooksManager::park("leases6_committed", query6, []{}); // There are no leases so the callout should return. - ASSERT_NO_THROW(ha_impl.leases6Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases6Committed(*callout_handle)); // No updates are generated so the default status should not be modified. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); @@ -1300,27 +1339,27 @@ TEST_F(HAImplTest, leases6Committed) { leases6->push_back(lease6); callout_handle->setArgument("leases6", leases6); - ha_impl.config_->get()->setSendLeaseUpdates(false); + test_ha_impl_->config_->get()->setSendLeaseUpdates(false); // Park the packet. HooksManager::park("leases6_committed", query6, []{}); // Run the callout again. - ASSERT_NO_THROW(ha_impl.leases6Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases6Committed(*callout_handle)); // No updates are generated so the default status should not be modified. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); EXPECT_TRUE(callout_handle->getParkingLotHandlePtr()->drop(query6)); // Enable updates and retry. - ha_impl.config_->get()->setSendLeaseUpdates(true); + test_ha_impl_->config_->get()->setSendLeaseUpdates(true); callout_handle->setArgument("leases6", leases6); // Park the packet. HooksManager::park("leases6_committed", query6, []{}); // Run the callout again. - ASSERT_NO_THROW(ha_impl.leases6Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases6Committed(*callout_handle)); // This time the lease update should be generated and the status should // be set to "park". @@ -1331,18 +1370,18 @@ TEST_F(HAImplTest, leases6Committed) { // Tests leases6_committed callout implementation for multiple relationships. TEST_F(HAImplTest, leases6CommittedMultipleRelationships) { // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidHubJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); // Starting the service is required before running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // By enabling this setting we ensure that the lease updates are always // scheduled and the packet is parked because it is independent of a // server state. - ha_impl.config_->get("server2")->setWaitBackupAck(true); + test_ha_impl_->config_->get("server2")->setWaitBackupAck(true); // Create callout handle to be used for passing arguments to the // callout. @@ -1374,7 +1413,7 @@ TEST_F(HAImplTest, leases6CommittedMultipleRelationships) { HooksManager::park("leases6_committed", query6, []{}); // Run the callout. - ASSERT_NO_THROW(ha_impl.leases6Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases6Committed(*callout_handle)); // Make sure the callout completed successfully. The "park" status means // there was no error during the callout. @@ -1386,18 +1425,18 @@ TEST_F(HAImplTest, leases6CommittedMultipleRelationships) { // the relationship is not found. TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsNoServerName) { // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidHubJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); // Starting the service is required before running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // By enabling this setting we ensure that the lease updates are always // scheduled and the packet is parked because it is independent of a // server state. - ha_impl.config_->get("server2")->setWaitBackupAck(true); + test_ha_impl_->config_->get("server2")->setWaitBackupAck(true); // Create callout handle to be used for passing arguments to the // callout. @@ -1426,7 +1465,7 @@ TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsNoServerName) { HooksManager::park("leases6_committed", query6, []{}); // Run the callout. - ASSERT_NO_THROW(ha_impl.leases6Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases6Committed(*callout_handle)); // The relationship was not found so the packet should be dropped. EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, callout_handle->getStatus()); @@ -1437,18 +1476,18 @@ TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsNoServerName) { // the relationship name is invalid. TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsInvalidServerName) { // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidHubJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); // Starting the service is required before running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv6)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv6)); // By enabling this setting we ensure that the lease updates are always // scheduled and the packet is parked because it is independent of a // server state. - ha_impl.config_->get("server2")->setWaitBackupAck(true); + test_ha_impl_->config_->get("server2")->setWaitBackupAck(true); // Create callout handle to be used for passing arguments to the // callout. @@ -1480,7 +1519,7 @@ TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsInvalidServerName) { HooksManager::park("leases6_committed", query6, []{}); // Run the callout. - ASSERT_NO_THROW(ha_impl.leases6Committed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->leases6Committed(*callout_handle)); // The relationship was not found so the packet should be dropped. EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, callout_handle->getStatus()); @@ -1568,13 +1607,13 @@ TEST_F(HAImplTest, synchronizeHandler) { // Tests ha-continue command handler with a specified server name. TEST_F(HAImplTest, continueHandler) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON("{" "\"command\": \"ha-continue\"," @@ -1586,7 +1625,7 @@ TEST_F(HAImplTest, continueHandler) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.continueHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->continueHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -1597,20 +1636,20 @@ TEST_F(HAImplTest, continueHandler) { // Tests ha-continue command handler without a server name. TEST_F(HAImplTest, continueHandlerWithNoServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON("{ \"command\": \"ha-continue\" }"); CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.continueHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->continueHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -1621,13 +1660,13 @@ TEST_F(HAImplTest, continueHandlerWithNoServerName) { // Tests ha-continue command handler with wrong server name. TEST_F(HAImplTest, continueHandlerWithWrongServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON("{" "\"command\": \"ha-continue\"," @@ -1639,7 +1678,7 @@ TEST_F(HAImplTest, continueHandlerWithWrongServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.continueHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->continueHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -1650,13 +1689,13 @@ TEST_F(HAImplTest, continueHandlerWithWrongServerName) { // Tests status-get command processed handler. TEST_F(HAImplTest, statusGet) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); std::string name = "status-get"; ConstElementPtr response = @@ -1667,7 +1706,7 @@ TEST_F(HAImplTest, statusGet) { callout_handle->setArgument("name", name); callout_handle->setArgument("response", response); - ASSERT_NO_THROW(ha_impl.commandProcessed(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->commandProcessed(*callout_handle)); ConstElementPtr got; callout_handle->getArgument("response", got); @@ -1711,14 +1750,14 @@ TEST_F(HAImplTest, statusGet) { // Tests status-get command processed handler for backup server. TEST_F(HAImplTest, statusGetBackupServer) { - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); - ha_impl.config_->get()->setThisServerName("server3"); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); + test_ha_impl_->config_->get()->setThisServerName("server3"); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); std::string name = "status-get"; ConstElementPtr response = @@ -1729,7 +1768,7 @@ TEST_F(HAImplTest, statusGetBackupServer) { callout_handle->setArgument("name", name); callout_handle->setArgument("response", response); - ASSERT_NO_THROW(ha_impl.commandProcessed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->commandProcessed(*callout_handle)); ConstElementPtr got; callout_handle->getArgument("response", got); @@ -1761,13 +1800,13 @@ TEST_F(HAImplTest, statusGetBackupServer) { // Tests status-get command processed handler for primary server being in the // passive-backup state. TEST_F(HAImplTest, statusGetPassiveBackup) { - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidPassiveBackupJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidPassiveBackupJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); std::string name = "status-get"; ConstElementPtr response = @@ -1778,7 +1817,7 @@ TEST_F(HAImplTest, statusGetPassiveBackup) { callout_handle->setArgument("name", name); callout_handle->setArgument("response", response); - ASSERT_NO_THROW(ha_impl.commandProcessed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->commandProcessed(*callout_handle)); ConstElementPtr got; callout_handle->getArgument("response", got); @@ -1810,13 +1849,13 @@ TEST_F(HAImplTest, statusGetPassiveBackup) { // Tests status-get command processed handler for standby server in the // hub-and-spoke mode. TEST_F(HAImplTest, statusGetHubAndSpoke) { - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidHubJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); std::string name = "status-get"; ConstElementPtr response = @@ -1827,7 +1866,7 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) { callout_handle->setArgument("name", name); callout_handle->setArgument("response", response); - ASSERT_NO_THROW(ha_impl.commandProcessed(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->commandProcessed(*callout_handle)); ConstElementPtr got; callout_handle->getArgument("response", got); @@ -1895,13 +1934,13 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) { // Test ha-maintenance-notify command handler with server name. TEST_F(HAImplTest, maintenanceNotify) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -1916,7 +1955,7 @@ TEST_F(HAImplTest, maintenanceNotify) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.maintenanceNotifyHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->maintenanceNotifyHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -1927,13 +1966,13 @@ TEST_F(HAImplTest, maintenanceNotify) { // Test ha-maintenance-notify command handler without server name. TEST_F(HAImplTest, maintenanceNotifyNoServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -1947,7 +1986,7 @@ TEST_F(HAImplTest, maintenanceNotifyNoServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.maintenanceNotifyHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->maintenanceNotifyHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -1958,13 +1997,13 @@ TEST_F(HAImplTest, maintenanceNotifyNoServerName) { // Test ha-maintenance-notify command handler without server name. TEST_F(HAImplTest, maintenanceNotifyBadServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -1979,7 +2018,7 @@ TEST_F(HAImplTest, maintenanceNotifyBadServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.maintenanceNotifyHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->maintenanceNotifyHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -1988,16 +2027,15 @@ TEST_F(HAImplTest, maintenanceNotifyBadServerName) { checkAnswer(response, CONTROL_RESULT_ERROR, "server5 matches no configured 'server-name'"); } - // Test ha-reset command handler with a specified server name. TEST_F(HAImplTest, haReset) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2011,7 +2049,7 @@ TEST_F(HAImplTest, haReset) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.haResetHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->haResetHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2022,13 +2060,13 @@ TEST_F(HAImplTest, haReset) { // Test ha-reset command handler without a specified server name. TEST_F(HAImplTest, haResetNoServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2039,7 +2077,7 @@ TEST_F(HAImplTest, haResetNoServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.haResetHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->haResetHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2050,14 +2088,13 @@ TEST_F(HAImplTest, haResetNoServerName) { // Test ha-reset command handler with a wrong server name. TEST_F(HAImplTest, haResetBadServerName) { - HAImpl ha_impl; - - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2071,7 +2108,7 @@ TEST_F(HAImplTest, haResetBadServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.haResetHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->haResetHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2082,13 +2119,13 @@ TEST_F(HAImplTest, haResetBadServerName) { // Test ha-heartbeat command handler with a specified server name. TEST_F(HAImplTest, haHeartbeat) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2102,7 +2139,7 @@ TEST_F(HAImplTest, haHeartbeat) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.heartbeatHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->heartbeatHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2113,13 +2150,13 @@ TEST_F(HAImplTest, haHeartbeat) { // Test ha-heartbeat command handler without a specified server name. TEST_F(HAImplTest, haHeartbeatNoServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2130,7 +2167,7 @@ TEST_F(HAImplTest, haHeartbeatNoServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.heartbeatHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->heartbeatHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2141,13 +2178,13 @@ TEST_F(HAImplTest, haHeartbeatNoServerName) { // Test ha-heartbeat command handler with a wrong server name. TEST_F(HAImplTest, haHeartbeatBadServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2161,7 +2198,7 @@ TEST_F(HAImplTest, haHeartbeatBadServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.heartbeatHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->heartbeatHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2172,13 +2209,13 @@ TEST_F(HAImplTest, haHeartbeatBadServerName) { // Test ha-sync-complete-notify command handler with a specified server name. TEST_F(HAImplTest, haSyncCompleteNotify) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2192,7 +2229,7 @@ TEST_F(HAImplTest, haSyncCompleteNotify) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.syncCompleteNotifyHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->syncCompleteNotifyHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2204,13 +2241,13 @@ TEST_F(HAImplTest, haSyncCompleteNotify) { // Test ha-sync-complete-notify command handler without a specified server name. TEST_F(HAImplTest, haSyncCompleteNotifyNoServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2221,7 +2258,7 @@ TEST_F(HAImplTest, haSyncCompleteNotifyNoServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.syncCompleteNotifyHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->syncCompleteNotifyHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2233,13 +2270,13 @@ TEST_F(HAImplTest, haSyncCompleteNotifyNoServerName) { // Test ha-sync-complete-notify command handler with a wrong server name. TEST_F(HAImplTest, haSyncCompleteNotifyBadServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2253,7 +2290,7 @@ TEST_F(HAImplTest, haSyncCompleteNotifyBadServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.syncCompleteNotifyHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->syncCompleteNotifyHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2264,13 +2301,13 @@ TEST_F(HAImplTest, haSyncCompleteNotifyBadServerName) { // Test ha-scopes command handler with a specified server name. TEST_F(HAImplTest, haScopes) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2285,7 +2322,7 @@ TEST_F(HAImplTest, haScopes) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.scopesHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->scopesHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2296,13 +2333,13 @@ TEST_F(HAImplTest, haScopes) { // Test ha-scopes command handler without a specified server name. TEST_F(HAImplTest, haScopesNoServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2316,7 +2353,7 @@ TEST_F(HAImplTest, haScopesNoServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.scopesHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->scopesHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2327,13 +2364,13 @@ TEST_F(HAImplTest, haScopesNoServerName) { // Test ha-scopes command handler with a wrong server name. TEST_F(HAImplTest, haScopesBadServerName) { - HAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + ha_impl_.reset(new HAImpl()); + ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( "{" @@ -2348,7 +2385,7 @@ TEST_F(HAImplTest, haScopesBadServerName) { CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle(); callout_handle->setArgument("command", command); - ASSERT_NO_THROW(ha_impl.scopesHandler(*callout_handle)); + ASSERT_NO_THROW(ha_impl_->scopesHandler(*callout_handle)); ConstElementPtr response; callout_handle->getArgument("response", response); @@ -2360,18 +2397,18 @@ TEST_F(HAImplTest, haScopesBadServerName) { // Tests lease4_server_decline callout implementation. TEST_F(HAImplTest, lease4ServerDecline) { // Create implementation object and configure it. - TestHAImpl ha_impl; - ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration())); + test_ha_impl_.reset(new TestHAImpl()); + ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); // Starting the service is required prior to running any callouts. NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); - ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state, - HAServerType::DHCPv4)); + ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, + HAServerType::DHCPv4)); // Make sure we wait for the acks from the backup server to be able to // test the case of sending lease updates even though the service is // in the state in which the lease updates are normally not sent. - ha_impl.config_->get()->setWaitBackupAck(true); + test_ha_impl_->config_->get()->setWaitBackupAck(true); // Create callout handle to be used for passing arguments to the // callout. @@ -2396,10 +2433,10 @@ TEST_F(HAImplTest, lease4ServerDecline) { // Set initial status. callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE); - ha_impl.config_->get()->setSendLeaseUpdates(false); + test_ha_impl_->config_->get()->setSendLeaseUpdates(false); // Run the callout. - ASSERT_NO_THROW(ha_impl.lease4ServerDecline(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->lease4ServerDecline(*callout_handle)); // Status should be continue. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); @@ -2409,11 +2446,11 @@ TEST_F(HAImplTest, lease4ServerDecline) { EXPECT_EQ(peers_to_update, 0); // Enable updates and retry. - ha_impl.config_->get()->setSendLeaseUpdates(true); + test_ha_impl_->config_->get()->setSendLeaseUpdates(true); callout_handle->setArgument("lease4", lease4); // Run the callout again. - ASSERT_NO_THROW(ha_impl.lease4ServerDecline(*callout_handle)); + ASSERT_NO_THROW(test_ha_impl_->lease4ServerDecline(*callout_handle)); // Status should be continue. EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, callout_handle->getStatus()); diff --git a/src/hooks/dhcp/high_availability/tests/ha_service_unittest.cc b/src/hooks/dhcp/high_availability/tests/ha_service_unittest.cc index 2840f58065..e3278814a4 100644 --- a/src/hooks/dhcp/high_availability/tests/ha_service_unittest.cc +++ b/src/hooks/dhcp/high_availability/tests/ha_service_unittest.cc @@ -626,7 +626,10 @@ class HAServiceTest : public HATest { listener2_->stop(); listener3_->stop(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } MultiThreadingMgr::instance().setMode(false); CfgMgr::instance().clear(); } @@ -1509,6 +1512,12 @@ class HAServiceTest : public HATest { // Change the partner's response to success. factory2_->getResponseCreator()->setControlResult(CONTROL_RESULT_SUCCESS); + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } + // Try sending the lease updates again. The previously rejected lease should // now be accepted and the counter should be 0. bool unpark_called = false; @@ -2083,7 +2092,10 @@ class HAServiceTest : public HATest { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } } /// @brief Runs HAService::processSynchronize for the DHCPv6 server @@ -2133,7 +2145,10 @@ class HAServiceTest : public HATest { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } } /// @brief Tests scenarios when a single lease update is sent to a partner while @@ -4871,7 +4886,10 @@ TEST_F(HAServiceTest, processMaintenanceStartSuccess) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } // The partner of our server is online and should have responded with // the success status. Therefore, this server should have transitioned @@ -4923,7 +4941,10 @@ TEST_F(HAServiceTest, processMaintenanceStartSuccessAuthorized) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } // The partner of our server is online and should have responded with // the success status. Therefore, this server should have transitioned @@ -4966,7 +4987,10 @@ TEST_F(HAServiceTest, processMaintenanceStartPartnerDown) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } // The partner of our server is online and should have responded with // the success status. Therefore, this server should have transitioned @@ -5010,7 +5034,10 @@ TEST_F(HAServiceTest, processMaintenanceStartPartnerError) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } ASSERT_TRUE(rsp); checkAnswer(rsp, CONTROL_RESULT_SUCCESS, @@ -5052,7 +5079,10 @@ TEST_F(HAServiceTest, processMaintenanceStartPartnerUnauthorized) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } ASSERT_TRUE(rsp); checkAnswer(rsp, CONTROL_RESULT_SUCCESS, @@ -5095,7 +5125,10 @@ TEST_F(HAServiceTest, processMaintenanceStartNotAllowed) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } ASSERT_TRUE(rsp); checkAnswer(rsp, CONTROL_RESULT_ERROR, @@ -5139,7 +5172,10 @@ TEST_F(HAServiceTest, processMaintenanceCancelSuccess) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } // The partner of our server is online and should have responded with // the success status. Therefore, this server should have transitioned @@ -5190,7 +5226,10 @@ TEST_F(HAServiceTest, processMaintenanceCancelSuccessAuthorized) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } // The partner of our server is online and should have responded with // the success status. Therefore, this server should have transitioned @@ -5233,7 +5272,10 @@ TEST_F(HAServiceTest, processMaintenanceCancelPartnerError) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } // The partner should have responded with an error. ASSERT_TRUE(rsp); @@ -5279,7 +5321,10 @@ TEST_F(HAServiceTest, processMaintenanceCancelPartnerUnauthorized) { io_service_->stop(); thread->join(); io_service_->restart(); - io_service_->poll(); + try { + io_service_->poll(); + } catch (...) { + } // The partner should have responded with an error. ASSERT_TRUE(rsp); @@ -5562,6 +5607,14 @@ class HAServiceStateMachineTest : public HAServiceTest { partner_(new HAPartner(listener2_, factory2_)) { } + ~HAServiceStateMachineTest() { + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } + } + /// @brief Creates common HA service instance from the provided configuration. /// /// The custom @c state_ object is created and it replaces the default diff --git a/src/hooks/dhcp/high_availability/tests/ha_test.cc b/src/hooks/dhcp/high_availability/tests/ha_test.cc index b7c43fea49..ea0d78f995 100644 --- a/src/hooks/dhcp/high_availability/tests/ha_test.cc +++ b/src/hooks/dhcp/high_availability/tests/ha_test.cc @@ -56,6 +56,14 @@ HATest::HATest() } HATest::~HATest() { + if (timer_) { + timer_->cancel(); + } + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } } void @@ -72,26 +80,32 @@ HATest::startHAService() { void HATest::runIOService(long ms) { io_service_->restart(); - IntervalTimer timer(io_service_); - timer.setup(std::bind(&IOService::stop, io_service_), ms, - IntervalTimer::ONE_SHOT); + timer_.reset(new IntervalTimer(io_service_)); + timer_->setup(std::bind(&IOService::stop, io_service_), ms, + IntervalTimer::ONE_SHOT); + io_service_->run(); - timer.cancel(); + + timer_->cancel(); + auto f = [](IntervalTimerPtr) {}; + io_service_->post(std::bind(f, timer_)); } void HATest::runIOService(long ms, std::function stop_condition) { io_service_->restart(); - IntervalTimer timer(io_service_); + timer_.reset(new IntervalTimer(io_service_)); bool timeout = false; - timer.setup(std::bind(&HATest::stopIOServiceHandler, this, std::ref(timeout)), - ms, IntervalTimer::ONE_SHOT); + timer_->setup(std::bind(&HATest::stopIOServiceHandler, this, std::ref(timeout)), + ms, IntervalTimer::ONE_SHOT); while (!stop_condition() && !timeout) { io_service_->runOne(); } - timer.cancel(); + timer_->cancel(); + auto f = [](IntervalTimerPtr) {}; + io_service_->post(std::bind(f, timer_)); } boost::shared_ptr diff --git a/src/hooks/dhcp/high_availability/tests/ha_test.h b/src/hooks/dhcp/high_availability/tests/ha_test.h index b001dc5e63..8f52190fc0 100644 --- a/src/hooks/dhcp/high_availability/tests/ha_test.h +++ b/src/hooks/dhcp/high_availability/tests/ha_test.h @@ -309,6 +309,9 @@ class HATest : public ::testing::Test { /// @brief Object holding a state of the DHCP service. dhcp::NetworkStatePtr network_state_; + + /// @brief Test timer. + isc::asiolink::IntervalTimerPtr timer_; }; } // end of namespace isc::ha::test diff --git a/src/lib/asiodns/io_fetch.cc b/src/lib/asiodns/io_fetch.cc index df8cf18565..b0c3b46d1b 100644 --- a/src/lib/asiodns/io_fetch.cc +++ b/src/lib/asiodns/io_fetch.cc @@ -54,27 +54,26 @@ const int DBG_ALL = DBGLVL_TRACE_DETAIL + 20; /// as a coroutine and passed as callback to many async_*() functions) and we /// want keep the same data). Organising the data in this way keeps copying to /// a minimum. -struct IOFetchData { - IOServicePtr io_service_; ///< The IO service +struct IOFetchData : boost::noncopyable { + IOServicePtr io_service_; ///< The IO service // The first two members are shared pointers to a base class because what is // actually instantiated depends on whether the fetch is over UDP or TCP, // which is not known until construction of the IOFetch. Use of a shared // pointer here is merely to ensure deletion when the data object is deleted. - boost::scoped_ptr> socket; - ///< Socket to use for I/O - boost::scoped_ptr remote_snd;///< Where the fetch is sent - boost::scoped_ptr remote_rcv;///< Where the response came from - OutputBufferPtr msgbuf; ///< Wire buffer for question - OutputBufferPtr received; ///< Received data put here - IOFetch::Callback* callback; ///< Called on I/O Completion - boost::asio::deadline_timer timer; ///< Timer to measure timeouts - IOFetch::Protocol protocol; ///< Protocol being used - size_t cumulative; ///< Cumulative received amount - size_t expected; ///< Expected amount of data - size_t offset; ///< Offset to receive data - bool stopped; ///< Have we stopped running? - int timeout; ///< Timeout in ms - bool packet; ///< true if packet was supplied + boost::scoped_ptr> socket; ///< Socket to use for I/O + boost::scoped_ptr remote_snd; ///< Where the fetch is sent + boost::scoped_ptr remote_rcv; ///< Where the response came from + OutputBufferPtr msgbuf; ///< Wire buffer for question + OutputBufferPtr received; ///< Received data put here + IOFetch::Callback* callback; ///< Called on I/O Completion + boost::asio::deadline_timer timer; ///< Timer to measure timeouts + IOFetch::Protocol protocol; ///< Protocol being used + size_t cumulative; ///< Cumulative received amount + size_t expected; ///< Expected amount of data + size_t offset; ///< Offset to receive data + bool stopped; ///< Have we stopped running? + int timeout; ///< Timeout in ms + bool packet; ///< true if packet was supplied // In case we need to log an error, the origin of the last asynchronous // I/O is recorded. To save time and simplify the code, this is recorded @@ -133,8 +132,13 @@ struct IOFetchData { packet(false), origin(ASIODNS_UNKNOWN_ORIGIN), staging(), - qid(QidGenerator::getInstance().generateQid()) - {} + qid(QidGenerator::getInstance().generateQid()) { + } + + /// \brief Destructor + ~IOFetchData() { + timer.cancel(); + } // Checks if the response we received was ok; // - data contains the buffer we read, as well as the address diff --git a/src/lib/asiodns/tests/io_fetch_unittest.cc b/src/lib/asiodns/tests/io_fetch_unittest.cc index 59bbe566b7..1001807ccd 100644 --- a/src/lib/asiodns/tests/io_fetch_unittest.cc +++ b/src/lib/asiodns/tests/io_fetch_unittest.cc @@ -52,42 +52,42 @@ const size_t MAX_SIZE = 64 * 1024; // Should be able to take 64kB const bool DEBUG = false; /// \brief Test fixture for the asiolink::IOFetch. -class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Callback -{ +class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Callback { public: - IOServicePtr service_; ///< Service to run the query - IOFetch::Result expected_; ///< Expected result of the callback - bool run_; ///< Did the callback run already? - Question question_; ///< What to ask - OutputBufferPtr result_buff_; ///< Buffer to hold result of fetch - OutputBufferPtr msgbuf_; ///< Buffer corresponding to known question - IOFetch udp_fetch_; ///< For UDP query test - IOFetch tcp_fetch_; ///< For TCP query test - IOFetch::Protocol protocol_; ///< Protocol being tested - size_t cumulative_; ///< Cumulative data received by "server". - deadline_timer timer_; ///< Timer to measure timeouts + IOServicePtr service_; ///< Service to run the query + IOFetch::Result expected_; ///< Expected result of the callback + bool run_; ///< Did the callback run already? + Question question_; ///< What to ask + OutputBufferPtr result_buff_; ///< Buffer to hold result of fetch + OutputBufferPtr msgbuf_; ///< Buffer corresponding to known question + IOFetch udp_fetch_; ///< For UDP query test + IOFetch tcp_fetch_; ///< For TCP query test + IOFetch::Protocol protocol_; ///< Protocol being tested + size_t cumulative_; ///< Cumulative data received by "server". + deadline_timer timer_; ///< Timer to measure timeouts // The next member is the buffer in which the "server" (implemented by the // response handler methods in this class) receives the question sent by the // fetch object. - uint8_t receive_buffer_[MAX_SIZE]; ///< Server receive buffer - OutputBufferPtr expected_buffer_; ///< Data we expect to receive - vector send_buffer_; ///< Server send buffer - uint16_t send_cumulative_; ///< Data sent so far + uint8_t receive_buffer_[MAX_SIZE]; ///< Server receive buffer + OutputBufferPtr expected_buffer_; ///< Data we expect to receive + vector send_buffer_; ///< Server send buffer + uint16_t send_cumulative_; ///< Data sent so far // Other data. - string return_data_; ///< Data returned by server - string test_data_; ///< Large string - here for convenience - bool debug_; ///< true to enable debug output - size_t tcp_send_size_; ///< Max size of TCP send - uint8_t qid_0; ///< First octet of qid - uint8_t qid_1; ///< Second octet of qid - - bool tcp_short_send_; ///< If set to true, we do not send - /// all data in the tcp response - boost::shared_ptr udp_socket_; - boost::shared_ptr tcp_socket_; + string return_data_; ///< Data returned by server + string test_data_; ///< Large string - here for convenience + bool debug_; ///< true to enable debug output + size_t tcp_send_size_; ///< Max size of TCP send + uint8_t qid_0; ///< First octet of qid + uint8_t qid_1; ///< Second octet of qid + + bool tcp_short_send_; ///< If set to true, we do not send + /// all data in the tcp response + boost::shared_ptr udp_socket_; + boost::shared_ptr tcp_socket_; boost::shared_ptr tcp_acceptor_; + bool shutdown_; /// \brief Constructor IOFetchTest() : @@ -115,8 +115,8 @@ class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Call tcp_send_size_(0), qid_0(0), qid_1(0), - tcp_short_send_(false) - { + tcp_short_send_(false), + shutdown_(false) { // Construct the data buffer for question we expect to receive. Message msg(Message::RENDER); msg.setQid(0); @@ -153,6 +153,8 @@ class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Call } virtual ~IOFetchTest() { + shutdown_ = true; + timer_.cancel(); service_->restart(); try { service_->poll(); @@ -178,8 +180,10 @@ class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Call void udpReceiveHandler(udp::endpoint* remote, udp::socket* socket, boost::system::error_code ec = boost::system::error_code(), size_t length = 0, bool bad_qid = false, - bool second_send = false) - { + bool second_send = false) { + if (shutdown_) { + return; + } if (debug_) { cout << "udpReceiveHandler(): error = " << ec.value() << ", length = " << length << endl; @@ -228,8 +232,10 @@ class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Call /// \param socket Socket on which data will be received /// \param ec Boost error code, value should be zero. void tcpAcceptHandler(tcp::socket* socket, - boost::system::error_code ec = boost::system::error_code()) - { + boost::system::error_code ec = boost::system::error_code()) { + if (shutdown_) { + return; + } if (debug_) { cout << "tcpAcceptHandler(): error = " << ec.value() << endl; } @@ -269,8 +275,10 @@ class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Call /// \param length Amount of data received. void tcpReceiveHandler(tcp::socket* socket, boost::system::error_code ec = boost::system::error_code(), - size_t length = 0) - { + size_t length = 0) { + if (shutdown_) { + return; + } if (debug_) { cout << "tcpReceiveHandler(): error = " << ec.value() << ", length = " << length << endl; @@ -337,6 +345,9 @@ class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Call /// /// \param socket Socket over which send should take place void tcpSendData(tcp::socket* socket) { + if (shutdown_) { + return; + } if (debug_) { cout << "tcpSendData()" << endl; } @@ -402,8 +413,10 @@ class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Call /// \param length Number of bytes sent. void tcpSendHandler(size_t expected, tcp::socket* socket, boost::system::error_code ec = boost::system::error_code(), - size_t length = 0) - { + size_t length = 0) { + if (shutdown_) { + return; + } if (debug_) { cout << "tcpSendHandler(): error = " << ec.value() << ", length = " << length << endl; @@ -511,8 +524,8 @@ class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Call // Stop before it is started fetch.stop(); - service_->post(fetch); + service_->post(fetch); service_->run(); EXPECT_TRUE(run_); } diff --git a/src/lib/asiolink/io_service_thread_pool.h b/src/lib/asiolink/io_service_thread_pool.h index 68c4e21b96..9397088ec0 100644 --- a/src/lib/asiolink/io_service_thread_pool.h +++ b/src/lib/asiolink/io_service_thread_pool.h @@ -41,7 +41,7 @@ class IoServiceThreadPool { /// state post construction is STOPPED. If false, the constructor will /// invoke run() to transition the pool into the RUNNING state. IoServiceThreadPool(asiolink::IOServicePtr io_service, size_t pool_size, - bool defer_start = false); + bool defer_start = false); /// @brief Destructor /// diff --git a/src/lib/asiolink/tcp_socket.h b/src/lib/asiolink/tcp_socket.h index c2e70fcfe9..44e83057a2 100644 --- a/src/lib/asiolink/tcp_socket.h +++ b/src/lib/asiolink/tcp_socket.h @@ -258,8 +258,7 @@ class TCPSocket : public IOAsioSocket { template TCPSocket::TCPSocket(boost::asio::ip::tcp::socket& socket) : - socket_ptr_(), socket_(socket), send_buffer_() -{ + socket_ptr_(), socket_(socket), send_buffer_() { } // Constructor - create socket on the fly @@ -267,15 +266,14 @@ TCPSocket::TCPSocket(boost::asio::ip::tcp::socket& socket) : template TCPSocket::TCPSocket(const IOServicePtr& io_service) : io_service_(io_service), socket_ptr_(new boost::asio::ip::tcp::socket(io_service_->getInternalIOService())), - socket_(*socket_ptr_) -{ + socket_(*socket_ptr_) { } // Destructor. template -TCPSocket::~TCPSocket() -{ +TCPSocket::~TCPSocket() { + close(); } // Open the socket. @@ -322,8 +320,7 @@ TCPSocket::open(const IOEndpoint* endpoint, C& callback) { // an exception if this is the case. template void -TCPSocket::asyncSend(const void* data, size_t length, C& callback) -{ +TCPSocket::asyncSend(const void* data, size_t length, C& callback) { if (socket_.is_open()) { try { @@ -347,8 +344,7 @@ TCPSocket::asyncSend(const void* data, size_t length, C& callback) template void TCPSocket::asyncSend(const void* data, size_t length, - const IOEndpoint*, C& callback) -{ + const IOEndpoint*, C& callback) { if (socket_.is_open()) { /// Need to copy the data into a temporary buffer and precede it with @@ -382,8 +378,7 @@ TCPSocket::asyncSend(const void* data, size_t length, // caller to initialize the data to zero template void TCPSocket::asyncReceive(void* data, size_t length, size_t offset, - IOEndpoint* endpoint, C& callback) -{ + IOEndpoint* endpoint, C& callback) { if (socket_.is_open()) { // Upconvert to a TCPEndpoint. We need to do this because although // IOEndpoint is the base class of UDPEndpoint and TCPEndpoint, it @@ -424,8 +419,7 @@ template bool TCPSocket::processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, - isc::util::OutputBufferPtr& outbuff) -{ + isc::util::OutputBufferPtr& outbuff) { // Point to the data in the staging buffer and note how much there is. const uint8_t* data = static_cast(staging); size_t data_length = length; diff --git a/src/lib/asiolink/tls_socket.h b/src/lib/asiolink/tls_socket.h index 179952d98f..13e32037f9 100644 --- a/src/lib/asiolink/tls_socket.h +++ b/src/lib/asiolink/tls_socket.h @@ -45,7 +45,7 @@ class TLSSocket : public IOAsioSocket, private boost::noncopyable { TLSSocket(const IOServicePtr& service, TlsContextPtr context); /// @brief Destructor. - virtual ~TLSSocket() { } + virtual ~TLSSocket(); /// @brief Return file descriptor of underlying socket. virtual int getNative() const { @@ -275,6 +275,13 @@ TLSSocket::TLSSocket(const IOServicePtr& io_service, TlsContextPtr context) stream_(*stream_ptr_), socket_(stream_.lowest_layer()), send_buffer_() { } +// Destructor. + +template +TLSSocket::~TLSSocket() { + close(); +} + // Open the socket. template void @@ -325,8 +332,7 @@ TLSSocket::handshake(C& callback) { // an exception if this is the case. template void -TLSSocket::asyncSend(const void* data, size_t length, C& callback) -{ +TLSSocket::asyncSend(const void* data, size_t length, C& callback) { if (!socket_.is_open()) { isc_throw(SocketNotOpen, "attempt to send on a TLS socket that is not open"); @@ -349,8 +355,7 @@ TLSSocket::asyncSend(const void* data, size_t length, C& callback) template void TLSSocket::asyncSend(const void* data, size_t length, - const IOEndpoint*, C& callback) -{ + const IOEndpoint*, C& callback) { if (!socket_.is_open()) { isc_throw(SocketNotOpen, "attempt to send on a TLS socket that is not open"); @@ -384,8 +389,7 @@ TLSSocket::asyncSend(const void* data, size_t length, // caller to initialize the data to zero template void TLSSocket::asyncReceive(void* data, size_t length, size_t offset, - IOEndpoint* endpoint, C& callback) -{ + IOEndpoint* endpoint, C& callback) { if (!socket_.is_open()) { isc_throw(SocketNotOpen, "attempt to receive from a TLS socket that is not open"); @@ -427,8 +431,7 @@ template bool TLSSocket::processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, - isc::util::OutputBufferPtr& outbuff) -{ + isc::util::OutputBufferPtr& outbuff) { // Point to the data in the staging buffer and note how much there is. const uint8_t* data = static_cast(staging); size_t data_length = length; diff --git a/src/lib/asiolink/udp_socket.h b/src/lib/asiolink/udp_socket.h index 17afd28085..bda7276fdc 100644 --- a/src/lib/asiolink/udp_socket.h +++ b/src/lib/asiolink/udp_socket.h @@ -168,8 +168,7 @@ class UDPSocket : public IOAsioSocket { template UDPSocket::UDPSocket(boost::asio::ip::udp::socket& socket) : - socket_ptr_(), socket_(socket), isopen_(true) -{ + socket_ptr_(), socket_(socket), isopen_(true) { } // Constructor - create socket on the fly @@ -177,15 +176,14 @@ UDPSocket::UDPSocket(boost::asio::ip::udp::socket& socket) : template UDPSocket::UDPSocket(const IOServicePtr& io_service) : io_service_(io_service), socket_ptr_(new boost::asio::ip::udp::socket(io_service_->getInternalIOService())), - socket_(*socket_ptr_), isopen_(false) -{ + socket_(*socket_ptr_), isopen_(false) { } // Destructor. template -UDPSocket::~UDPSocket() -{ +UDPSocket::~UDPSocket() { + close(); } // Open the socket. @@ -228,8 +226,7 @@ UDPSocket::open(const IOEndpoint* endpoint, C&) { template void UDPSocket::asyncSend(const void* data, size_t length, - const IOEndpoint* endpoint, C& callback) -{ + const IOEndpoint* endpoint, C& callback) { if (isopen_) { // Upconvert to a UDPEndpoint. We need to do this because although @@ -255,8 +252,7 @@ UDPSocket::asyncSend(const void* data, size_t length, template void UDPSocket::asyncReceive(void* data, size_t length, size_t offset, - IOEndpoint* endpoint, C& callback) -{ + IOEndpoint* endpoint, C& callback) { if (isopen_) { // Upconvert the endpoint again. @@ -286,8 +282,7 @@ template bool UDPSocket::processReceivedData(const void* staging, size_t length, size_t& cumulative, size_t& offset, size_t& expected, - isc::util::OutputBufferPtr& outbuff) -{ + isc::util::OutputBufferPtr& outbuff) { // Set return values to what we should expect. cumulative = length; expected = length; diff --git a/src/lib/config/cmd_http_listener.cc b/src/lib/config/cmd_http_listener.cc index 66dc705e10..c8fec0cd4e 100644 --- a/src/lib/config/cmd_http_listener.cc +++ b/src/lib/config/cmd_http_listener.cc @@ -81,14 +81,33 @@ CmdHttpListener::start() { .arg(port_) .arg(tls_context_ ? "true" : "false"); } catch (const std::exception& ex) { + if (thread_pool_) { + // Stop the thread pool. + thread_pool_->stop(); + } + + if (http_listener_) { + // Stop the listener. + http_listener_->stop(); + } + + if (thread_io_service_) { + thread_io_service_->restart(); + try { + thread_io_service_->poll(); + } catch (...) { + } + } + + // Get rid of the thread pool. thread_pool_.reset(); + + // Get rid of the listener. http_listener_.reset(); - thread_io_service_->restart(); - try { - thread_io_service_->poll(); - } catch(...) { - } + + // Ditch the IOService. thread_io_service_.reset(); + isc_throw(Unexpected, "CmdHttpListener::run failed: " << ex.what()); } } @@ -128,15 +147,21 @@ CmdHttpListener::stop() { // Stop the thread pool. thread_pool_->stop(); - // Get rid of the listener. - http_listener_.reset(); + // Stop the listener. + http_listener_->stop(); thread_io_service_->restart(); try { thread_io_service_->poll(); - } catch(...) { + } catch (...) { } + // Get rid of the thread pool. + thread_pool_.reset(); + + // Get rid of the listener. + http_listener_.reset(); + // Ditch the IOService. thread_io_service_.reset(); diff --git a/src/lib/d2srv/d2_config.h b/src/lib/d2srv/d2_config.h index c08952979e..0abf6f2dd2 100644 --- a/src/lib/d2srv/d2_config.h +++ b/src/lib/d2srv/d2_config.h @@ -156,10 +156,10 @@ class D2Params { /// -# ncr_protocol is invalid, currently only NCR_UDP is supported /// -# ncr_format is invalid, currently only FMT_JSON is supported D2Params(const isc::asiolink::IOAddress& ip_address, - const size_t port, - const size_t dns_server_timeout, - const dhcp_ddns::NameChangeProtocol& ncr_protocol, - const dhcp_ddns::NameChangeFormat& ncr_format); + const size_t port, + const size_t dns_server_timeout, + const dhcp_ddns::NameChangeProtocol& ncr_protocol, + const dhcp_ddns::NameChangeFormat& ncr_format); /// @brief Default constructor /// The default constructor creates an instance that has updates disabled. @@ -170,27 +170,27 @@ class D2Params { /// @brief Return the IP address D2 listens on. const isc::asiolink::IOAddress& getIpAddress() const { - return(ip_address_); + return (ip_address_); } /// @brief Return the TCP/UPD port D2 listens on. size_t getPort() const { - return(port_); + return (port_); } /// @brief Return the DNS server timeout value. size_t getDnsServerTimeout() const { - return(dns_server_timeout_); + return (dns_server_timeout_); } /// @brief Return the socket protocol in use. const dhcp_ddns::NameChangeProtocol& getNcrProtocol() const { - return(ncr_protocol_); + return (ncr_protocol_); } /// @brief Return the expected format of inbound requests (NCRs). const dhcp_ddns::NameChangeFormat& getNcrFormat() const { - return(ncr_format_); + return (ncr_format_); } /// @brief Return summary of the configuration used by D2. diff --git a/src/lib/d2srv/dns_client.cc b/src/lib/d2srv/dns_client.cc index 4467577dc2..43236c3a24 100644 --- a/src/lib/d2srv/dns_client.cc +++ b/src/lib/d2srv/dns_client.cc @@ -66,6 +66,12 @@ class DNSClientImpl : public asiodns::IOFetch::Callback { /// @brief TSIG key name for stats. std::string tsig_key_name_; + /// @brief Flag which indicates that the client has been stopped. + bool stopped_; + + /// @brief The list of IOFetch objects. + std::list io_fetch_list_; + /// @brief Constructor. /// /// @param response_placeholder Message object pointer which will be updated @@ -119,13 +125,17 @@ class DNSClientImpl : public asiodns::IOFetch::Callback { /// @param update_key The flag indicating if the key statistics should also /// be updated. void incrStats(const std::string& stat, bool update_key = true); + + /// @brief This function stops the IOFetch objects. + void stop(); }; DNSClientImpl::DNSClientImpl(D2UpdateMessagePtr& response_placeholder, DNSClient::Callback* callback, const DNSClient::Protocol proto) : in_buf_(new OutputBuffer(DEFAULT_BUFFER_SIZE)), - response_(response_placeholder), callback_(callback), proto_(proto) { + response_(response_placeholder), callback_(callback), proto_(proto), + stopped_(false) { // Response should be an empty pointer. It gets populated by the // operator() method. @@ -158,11 +168,21 @@ DNSClientImpl::DNSClientImpl(D2UpdateMessagePtr& response_placeholder, } } +void DNSClientImpl::stop() { + stopped_ = true; + for (auto const& io_fetch : io_fetch_list_) { + io_fetch->stop(); + } +} + DNSClientImpl::~DNSClientImpl() { } void DNSClientImpl::operator()(asiodns::IOFetch::Result result) { + if (stopped_) { + return; + } // Get the status from IO. If no success, we just call user's callback // and pass the status code. DNSClient::Status status = getStatus(result); @@ -228,6 +248,9 @@ DNSClientImpl::doUpdate(const asiolink::IOServicePtr& io_service, D2UpdateMessage& update, const unsigned int wait, const D2TsigKeyPtr& tsig_key) { + if (stopped_) { + return; + } // The underlying implementation which we use to send DNS Updates uses // signed integers for timeout. If we want to avoid overflows we need to // respect this limitation here. @@ -270,12 +293,13 @@ DNSClientImpl::doUpdate(const asiolink::IOServicePtr& io_service, // Timeout value is explicitly cast to the int type to avoid warnings about // overflows when doing implicit cast. It should have been checked by the // caller that the unsigned timeout value will fit into int. - IOFetch io_fetch(IOFetch::UDP, io_service, msg_buf, ns_addr, ns_port, - in_buf_, this, static_cast(wait)); + IOFetchPtr io_fetch(new IOFetch(IOFetch::UDP, io_service, msg_buf, ns_addr, ns_port, + in_buf_, this, static_cast(wait))); + io_fetch_list_.push_back(io_fetch); // Post the task to the task queue in the IO service. Caller will actually // run these tasks by executing IOService::run. - io_service->post(io_fetch); + io_service->post(*io_fetch); // Update sent statistics. incrStats("update-sent"); @@ -302,6 +326,12 @@ DNSClient::DNSClient(D2UpdateMessagePtr& response_placeholder, } DNSClient::~DNSClient() { + stop(); +} + +void +DNSClient::stop() { + impl_->stop(); } unsigned int diff --git a/src/lib/d2srv/dns_client.h b/src/lib/d2srv/dns_client.h index 63a2c5c16a..e736d4d9d5 100644 --- a/src/lib/d2srv/dns_client.h +++ b/src/lib/d2srv/dns_client.h @@ -96,6 +96,9 @@ class DNSClient { /// @brief Virtual destructor, does nothing. ~DNSClient(); + /// @brief Stop the client. + void stop(); + /// /// @name Copy constructor and assignment operator /// diff --git a/src/lib/d2srv/nc_trans.cc b/src/lib/d2srv/nc_trans.cc index edfd3fdaa7..bb13726bca 100644 --- a/src/lib/d2srv/nc_trans.cc +++ b/src/lib/d2srv/nc_trans.cc @@ -103,7 +103,7 @@ NameChangeTransaction(asiolink::IOServicePtr& io_service, } } -NameChangeTransaction::~NameChangeTransaction(){ +NameChangeTransaction::~NameChangeTransaction() { } void diff --git a/src/lib/d2srv/tests/dns_client_unittests.cc b/src/lib/d2srv/tests/dns_client_unittests.cc index 4ec19cd484..4209bae642 100644 --- a/src/lib/d2srv/tests/dns_client_unittests.cc +++ b/src/lib/d2srv/tests/dns_client_unittests.cc @@ -126,6 +126,7 @@ class DNSClientTest : public ::testing::Test, DNSClient::Callback, /// Sets the asiodns logging level back to DEBUG. virtual ~DNSClientTest() { test_timer_.cancel(); + dns_client_->stop(); service_->restart(); try { service_->poll(); @@ -320,17 +321,18 @@ class DNSClientTest : public ::testing::Test, DNSClient::Callback, void runInvalidTimeoutTest() { expect_response_ = false; - // Create inbound message. Simply set the required message fields: + // Create outbound message. Simply set the required message fields: // error code and Zone section. This is enough to create on-wire format // of this message and send it. - D2UpdateMessage message(D2UpdateMessage::INBOUND); + D2UpdateMessage message(D2UpdateMessage::OUTBOUND); + ASSERT_NO_THROW(message.setRcode(Rcode(Rcode::NOERROR_CODE))); + ASSERT_NO_THROW(message.setZone(Name("example.com"), RRClass::IN())); // Start with a valid timeout equal to maximal allowed. This way we will // ensure that doUpdate doesn't throw an exception for valid timeouts. unsigned int timeout = DNSClient::getMaxTimeout(); - EXPECT_THROW(dns_client_->doUpdate(service_, IOAddress(TEST_ADDRESS), - TEST_PORT, message, timeout), - isc::d2::InvalidZoneSection); + EXPECT_NO_THROW(dns_client_->doUpdate(service_, IOAddress(TEST_ADDRESS), + TEST_PORT, message, timeout)); // Cross the limit and expect that exception is thrown this time. timeout = DNSClient::getMaxTimeout() + 1; diff --git a/src/lib/d2srv/testutils/nc_test_utils.cc b/src/lib/d2srv/testutils/nc_test_utils.cc index 1aceb6acbc..c9b8a671d8 100644 --- a/src/lib/d2srv/testutils/nc_test_utils.cc +++ b/src/lib/d2srv/testutils/nc_test_utils.cc @@ -59,7 +59,7 @@ FauxServer::FauxServer(asiolink::IOServicePtr& io_service, asiolink::IOAddress& address, size_t port) : io_service_(io_service), address_(address), port_(port), server_socket_(), receive_pending_(false), perpetual_receive_(true), - tsig_key_() { + tsig_key_(), stopped_(false) { server_socket_.reset(new boost::asio::ip::udp::socket(io_service_->getInternalIOService(), boost::asio::ip::udp::v4())); @@ -73,7 +73,7 @@ FauxServer::FauxServer(asiolink::IOServicePtr& io_service, DnsServerInfo& server) : io_service_(io_service), address_(server.getIpAddress()), port_(server.getPort()), server_socket_(), receive_pending_(false), - perpetual_receive_(true), tsig_key_() { + perpetual_receive_(true), tsig_key_(), stopped_(false) { server_socket_.reset(new boost::asio::ip::udp::socket(io_service_->getInternalIOService(), boost::asio::ip::udp::v4())); server_socket_->set_option(boost::asio::socket_base::reuse_address(true)); @@ -82,11 +82,17 @@ FauxServer::FauxServer(asiolink::IOServicePtr& io_service, } FauxServer::~FauxServer() { + stop(); +} + +void FauxServer::stop() { + stopped_ = true; + server_socket_->close(); } void -FauxServer::receive (const ResponseMode& response_mode, - const dns::Rcode& response_rcode) { +FauxServer::receive(const ResponseMode& response_mode, + const dns::Rcode& response_rcode) { if (receive_pending_) { return; } @@ -106,6 +112,9 @@ FauxServer::requestHandler(const boost::system::error_code& error, std::size_t bytes_recvd, const ResponseMode& response_mode, const dns::Rcode& response_rcode) { + if (stopped_) { + return; + } receive_pending_ = false; // If we encountered an error or received no data then fail. // We expect the client to send good requests. diff --git a/src/lib/d2srv/testutils/nc_test_utils.h b/src/lib/d2srv/testutils/nc_test_utils.h index cb30995747..e89bc5a0e5 100644 --- a/src/lib/d2srv/testutils/nc_test_utils.h +++ b/src/lib/d2srv/testutils/nc_test_utils.h @@ -72,6 +72,9 @@ class FauxServer { /// NULL TSIG is not used. D2TsigKeyPtr tsig_key_; + /// @brief Flag which indicated that the server has been stopped. + bool stopped_; + /// @brief Constructor /// /// @param io_service IOService to be used for socket IO. @@ -90,6 +93,9 @@ class FauxServer { /// @brief Destructor virtual ~FauxServer(); + /// @brief Stop the server + void stop(); + /// @brief Initiates an asynchronous receive /// /// Starts the server listening for requests. Upon completion of the diff --git a/src/lib/dhcp_ddns/ncr_io.cc b/src/lib/dhcp_ddns/ncr_io.cc index 1179c74adb..48f220f052 100644 --- a/src/lib/dhcp_ddns/ncr_io.cc +++ b/src/lib/dhcp_ddns/ncr_io.cc @@ -51,8 +51,7 @@ std::string ncrProtocolToString(NameChangeProtocol protocol) { //************************** NameChangeListener *************************** -NameChangeListener::NameChangeListener(RequestReceiveHandler& - recv_handler) +NameChangeListener::NameChangeListener(RequestReceiveHandler& recv_handler) : listening_(false), io_pending_(false), recv_handler_(recv_handler) { }; diff --git a/src/lib/dhcp_ddns/ncr_io.h b/src/lib/dhcp_ddns/ncr_io.h index 54633df625..db6000c702 100644 --- a/src/lib/dhcp_ddns/ncr_io.h +++ b/src/lib/dhcp_ddns/ncr_io.h @@ -194,8 +194,8 @@ class NameChangeListener { /// wise. /// /// @throw This method MUST NOT throw. - virtual void operator ()(const Result result, - NameChangeRequestPtr& ncr) = 0; + virtual void operator()(const Result result, + NameChangeRequestPtr& ncr) = 0; virtual ~RequestReceiveHandler() { } diff --git a/src/lib/dhcp_ddns/ncr_udp.cc b/src/lib/dhcp_ddns/ncr_udp.cc index f32404cb54..c6ca025db8 100644 --- a/src/lib/dhcp_ddns/ncr_udp.cc +++ b/src/lib/dhcp_ddns/ncr_udp.cc @@ -61,7 +61,6 @@ UDPCallback::putData(const uint8_t* src, size_t len) { data_->put_len_ = len; } - //*************************** NameChangeUDPListener *********************** NameChangeUDPListener:: NameChangeUDPListener(const isc::asiolink::IOAddress& ip_address, @@ -116,7 +115,6 @@ NameChangeUDPListener::open(const isc::asiolink::IOServicePtr& io_service) { socket_.reset(new NameChangeUDPSocket(*asio_socket_)); } - void NameChangeUDPListener::doReceive() { // Call the socket's asynchronous receiving, passing ourself in as callback. @@ -149,6 +147,9 @@ NameChangeUDPListener::close() { asio_socket_.reset(); } + if (socket_) { + socket_->close(); + } socket_.reset(); io_service_.reset(); } @@ -200,7 +201,6 @@ NameChangeUDPListener::receiveCompletionHandler(const bool successful, invokeRecvHandler(result, ncr); } - //*************************** NameChangeUDPSender *********************** NameChangeUDPSender:: @@ -292,6 +292,9 @@ NameChangeUDPSender::close() { asio_socket_.reset(); } + if (socket_) { + socket_->close(); + } socket_.reset(); closeWatchSocket(); diff --git a/src/lib/dhcp_ddns/tests/ncr_udp_unittests.cc b/src/lib/dhcp_ddns/tests/ncr_udp_unittests.cc index ea074ba672..84036533ce 100644 --- a/src/lib/dhcp_ddns/tests/ncr_udp_unittests.cc +++ b/src/lib/dhcp_ddns/tests/ncr_udp_unittests.cc @@ -213,8 +213,7 @@ class NameChangeUDPListenerTest : public virtual ::testing::Test, // Note this uses a synchronous send so it ships immediately. // If listener isn't in listening mode, it will get missed. udp_socket.send_to(boost::asio::buffer(ncr_buffer.getData(), - ncr_buffer.getLength()), - listener_endpoint); + ncr_buffer.getLength()), listener_endpoint); } /// @brief RequestReceiveHandler operator implementation for receiving NCRs. diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc index bca014b60e..89d6790204 100644 --- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc @@ -164,6 +164,12 @@ class MemfileLeaseMgrTest : public GenericLeaseMgrTest { setExtendedInfoSanityCheck(CfgConsistency::EXTENDED_INFO_CHECK_FIX); // Disable multi-threading. MultiThreadingMgr::instance().setMode(false); + + getIOService()->restart(); + try { + getIOService()->poll(); + } catch(...) { + } } /// @brief Remove files being products of Lease File Cleanup. diff --git a/src/lib/http/client.cc b/src/lib/http/client.cc index 66ab6490e0..853e7a2131 100644 --- a/src/lib/http/client.cc +++ b/src/lib/http/client.cc @@ -402,6 +402,9 @@ class Connection : public boost::enable_shared_from_this { /// after invocation. Defaults to false. void closeCallback(const bool clear = false); + /// @brief A reference to the IOService that drives socket IO. + IOServicePtr io_service_; + /// @brief Pointer to the connection pool owning this connection. /// /// This is a weak pointer to avoid circular dependency between the @@ -415,13 +418,13 @@ class Connection : public boost::enable_shared_from_this { TlsContextPtr tls_context_; /// @brief TCP socket to be used for this connection. - std::unique_ptr > tcp_socket_; + std::shared_ptr> tcp_socket_; /// @brief TLS socket to be used for this connection. - std::unique_ptr > tls_socket_; + std::shared_ptr> tls_socket_; /// @brief Interval timer used for detecting request timeouts. - IntervalTimer timer_; + IntervalTimerPtr timer_; /// @brief Holds currently sent request. HttpRequestPtr current_request_; @@ -1105,7 +1108,7 @@ class ConnectionPool : public boost::enable_shared_from_this { } } - /// @brief A reference to the IOService that drives socket IO. + /// @brief A pointer to the IOService that drives socket IO. IOServicePtr io_service_; /// @brief Map of Destinations by URL and TLS context. @@ -1122,12 +1125,12 @@ Connection::Connection(const IOServicePtr& io_service, const TlsContextPtr& tls_context, const ConnectionPoolPtr& conn_pool, const Url& url) - : conn_pool_(conn_pool), url_(url), tls_context_(tls_context), - tcp_socket_(), tls_socket_(), timer_(io_service), - current_request_(), current_response_(), parser_(), - current_callback_(), buf_(), input_buf_(), current_transid_(0), - close_callback_(), started_(false), need_handshake_(false), - closed_(false) { + : io_service_(io_service), conn_pool_(conn_pool), url_(url), + tls_context_(tls_context), tcp_socket_(), tls_socket_(), + timer_(new IntervalTimer(io_service)), current_request_(), + current_response_(), parser_(), current_callback_(), buf_(), input_buf_(), + current_transid_(0), close_callback_(), started_(false), + need_handshake_(false), closed_(false) { if (!tls_context) { tcp_socket_.reset(new asiolink::TCPSocket(io_service)); } else { @@ -1316,7 +1319,7 @@ Connection::closeInternal() { closeCallback(true); closed_ = true; - timer_.cancel(); + timer_->cancel(); if (tcp_socket_) { tcp_socket_->close(); } @@ -1324,6 +1327,10 @@ Connection::closeInternal() { tls_socket_->close(); } + auto f = [](IntervalTimerPtr, std::shared_ptr>, + std::shared_ptr>) {}; + io_service_->post(std::bind(f, timer_, tcp_socket_, tls_socket_)); + resetState(); } @@ -1384,7 +1391,7 @@ Connection::terminateInternal(const boost::system::error_code& ec, HttpResponsePtr response; if (isTransactionOngoing()) { - timer_.cancel(); + timer_->cancel(); if (tcp_socket_) { tcp_socket_->cancel(); } @@ -1461,8 +1468,8 @@ Connection::terminateInternal(const boost::system::error_code& ec, void Connection::scheduleTimer(const long request_timeout) { if (request_timeout > 0) { - timer_.setup(std::bind(&Connection::timerCallback, this), request_timeout, - IntervalTimer::ONE_SHOT); + timer_->setup(std::bind(&Connection::timerCallback, this), request_timeout, + IntervalTimer::ONE_SHOT); } } @@ -1649,7 +1656,7 @@ Connection::sendCallback(const uint64_t transid, } // Sending is in progress, so push back the timeout. - scheduleTimer(timer_.getInterval()); + scheduleTimer(timer_->getInterval()); // If any data have been sent, remove it from the buffer and only leave the // portion that still has to be sent. @@ -1695,7 +1702,7 @@ Connection::receiveCallback(const uint64_t transid, } // Receiving is in progress, so push back the timeout. - scheduleTimer(timer_.getInterval()); + scheduleTimer(timer_->getInterval()); if (runParser(ec, length)) { doReceive(transid); diff --git a/src/lib/http/connection_pool.h b/src/lib/http/connection_pool.h index a9110bceaf..9c86b5558f 100644 --- a/src/lib/http/connection_pool.h +++ b/src/lib/http/connection_pool.h @@ -75,4 +75,3 @@ class HttpConnectionPool { } #endif - diff --git a/src/lib/http/tests/server_client_unittests.cc b/src/lib/http/tests/server_client_unittests.cc index 059845b06d..c963404281 100644 --- a/src/lib/http/tests/server_client_unittests.cc +++ b/src/lib/http/tests/server_client_unittests.cc @@ -1027,7 +1027,11 @@ class HttpClientTest : public HttpListenerTest { listener_.stop(); listener2_.stop(); listener3_.stop(); - io_service_->poll(); + io_service_->restart(); + try { + io_service_->poll(); + } catch(...) { + } MultiThreadingMgr::instance().setMode(false); } diff --git a/src/lib/process/d_controller.cc b/src/lib/process/d_controller.cc index b1661db286..1b9276df82 100644 --- a/src/lib/process/d_controller.cc +++ b/src/lib/process/d_controller.cc @@ -50,7 +50,7 @@ DControllerBase::setController(const DControllerBasePtr& controller) { if (controller_) { // This shouldn't happen, but let's make sure it can't be done. // It represents a programmatic error. - isc_throw (DControllerBaseError, "Multiple controller instances attempted."); + isc_throw(DControllerBaseError, "Multiple controller instances attempted."); } controller_ = controller; @@ -103,7 +103,7 @@ DControllerBase::launch(int argc, char* argv[], const bool test_mode) { } catch (const std::exception& ex) { LOG_FATAL(dctl_logger, DCTL_CONFIG_FILE_LOAD_FAIL) .arg(app_name_).arg(ex.what()); - isc_throw (LaunchError, "Launch Failed: " << ex.what()); + isc_throw(LaunchError, "Launch Failed: " << ex.what()); } try { @@ -111,11 +111,11 @@ DControllerBase::launch(int argc, char* argv[], const bool test_mode) { } catch (const DaemonPIDExists& ex) { LOG_FATAL(dctl_logger, DCTL_ALREADY_RUNNING) .arg(bin_name_).arg(ex.what()); - isc_throw (LaunchError, "Launch Failed: " << ex.what()); + isc_throw(LaunchError, "Launch Failed: " << ex.what()); } catch (const std::exception& ex) { LOG_FATAL(dctl_logger, DCTL_PID_FILE_ERROR) .arg(app_name_).arg(ex.what()); - isc_throw (LaunchError, "Launch failed: " << ex.what()); + isc_throw(LaunchError, "Launch failed: " << ex.what()); } // Log the starting of the service. @@ -134,8 +134,8 @@ DControllerBase::launch(int argc, char* argv[], const bool test_mode) { } catch (const std::exception& ex) { LOG_FATAL(dctl_logger, DCTL_INIT_PROCESS_FAIL) .arg(app_name_).arg(ex.what()); - isc_throw (ProcessInitError, - "Application Process initialization failed: " << ex.what()); + isc_throw(ProcessInitError, + "Application Process initialization failed: " << ex.what()); } LOG_DEBUG(dctl_logger, isc::log::DBGLVL_START_SHUT, DCTL_STANDALONE) @@ -147,8 +147,8 @@ DControllerBase::launch(int argc, char* argv[], const bool test_mode) { if (rcode != 0) { LOG_FATAL(dctl_logger, DCTL_CONFIG_FILE_LOAD_FAIL) .arg(app_name_).arg(comment->stringValue()); - isc_throw (ProcessInitError, "Could Not load configuration file: " - << comment->stringValue()); + isc_throw(ProcessInitError, "Could Not load configuration file: " + << comment->stringValue()); } // Note that the controller was started. @@ -163,8 +163,8 @@ DControllerBase::launch(int argc, char* argv[], const bool test_mode) { } catch (const std::exception& ex) { LOG_FATAL(dctl_logger, DCTL_PROCESS_FAILED) .arg(app_name_).arg(ex.what()); - isc_throw (ProcessRunError, - "Application process event loop failed: " << ex.what()); + isc_throw(ProcessRunError, + "Application process event loop failed: " << ex.what()); } // All done, so bail out. @@ -315,7 +315,7 @@ DControllerBase::parseArgs(int argc, char* argv[]) { // We hit an invalid option. isc_throw(InvalidUsage, "unsupported option: -" << saved_optopt << - (saved_optarg.empty() ? std::string() : " " + saved_optarg)); + (saved_optarg.empty() ? std::string() : " " + saved_optarg)); } break; } @@ -342,8 +342,8 @@ DControllerBase::initProcess() { try { process_.reset(createProcess()); } catch (const std::exception& ex) { - isc_throw(DControllerBaseError, std::string("createProcess failed: ") - + ex.what()); + isc_throw(DControllerBaseError, std::string("createProcess failed: ") + + ex.what()); } // This is pretty unlikely, but will test for it just to be safe.. @@ -733,7 +733,7 @@ DControllerBase::shutdownHandler(const std::string&, ConstElementPtr args) { } ConstElementPtr param = args->get("exit-value"); - if (param) { + if (param) { if (param->getType() != Element::integer) { return (createAnswer(CONTROL_RESULT_ERROR, "parameter 'exit-value' is not an integer")); @@ -813,7 +813,7 @@ DControllerBase::usage(const std::string & text) { std::cerr << "Usage error: " << text << std::endl; } - std::cerr << "Usage: " << bin_name_ << std::endl + std::cerr << "Usage: " << bin_name_ << std::endl << " -v: print version number and exit" << std::endl << " -V: print extended version information and exit" << std::endl diff --git a/src/lib/process/d_controller.h b/src/lib/process/d_controller.h index 0c382d2934..0bbefda958 100644 --- a/src/lib/process/d_controller.h +++ b/src/lib/process/d_controller.h @@ -135,8 +135,8 @@ class DControllerBase : public Daemon { /// in their main function. Such a logger uses environmental variables to /// control severity, verbosity etc. /// - /// @param argc is the number of command line arguments supplied - /// @param argv is the array of string (char *) command line arguments + /// @param argc is the number of command line arguments supplied + /// @param argv is the array of string (char *) command line arguments /// @param test_mode is a bool value which indicates if /// @c DControllerBase::launch should be run in the test mode (if true). /// This parameter doesn't have default value to force test implementers to @@ -144,7 +144,7 @@ class DControllerBase : public Daemon { /// /// @throw throws one of the following exceptions: /// InvalidUsage - Indicates invalid command line. - /// ProcessInitError - Failed to create and initialize application + /// ProcessInitError - Failed to create and initialize application /// process object. /// ProcessRunError - A fatal error occurred while in the application /// process event loop. @@ -157,7 +157,7 @@ class DControllerBase : public Daemon { /// implementation will merge the configuration update into the existing /// configuration and then invoke the application process' configure method. /// - /// @param new_config is the new configuration + /// @param new_config is the new configuration /// /// @return returns an Element that contains the results of configuration /// update composed of an integer status value (0 means successful, @@ -172,7 +172,7 @@ class DControllerBase : public Daemon { /// configuration and then invoke the application process' configure method /// with a final rollback. /// - /// @param new_config is the new configuration + /// @param new_config is the new configuration /// /// @return returns an Element that contains the results of configuration /// update composed of an integer status value (0 means successful, @@ -495,8 +495,8 @@ class DControllerBase : public Daemon { /// -c/t for specifying the configuration file, -d for verbose logging, /// and -v/V/W for version reports. /// - /// @param argc is the number of command line arguments supplied - /// @param argv is the array of string (char *) command line arguments + /// @param argc is the number of command line arguments supplied + /// @param argv is the array of string (char *) command line arguments /// /// @throw InvalidUsage when there are usage errors. /// @throw VersionMessage if the -v, -V or -W arguments is given. diff --git a/src/lib/process/d_process.h b/src/lib/process/d_process.h index 24eaff0469..f60e299b70 100644 --- a/src/lib/process/d_process.h +++ b/src/lib/process/d_process.h @@ -145,7 +145,13 @@ class DProcessBase { bool check_only = false) = 0; /// @brief Destructor - virtual ~DProcessBase(){}; + virtual ~DProcessBase() { + io_service_->restart(); + try { + io_service_->poll(); + } catch (...) { + } + } /// @brief Checks if the process has been instructed to shut down. /// diff --git a/src/lib/tcp/mt_tcp_listener_mgr.cc b/src/lib/tcp/mt_tcp_listener_mgr.cc index 6bdc83d202..54b38b0d64 100644 --- a/src/lib/tcp/mt_tcp_listener_mgr.cc +++ b/src/lib/tcp/mt_tcp_listener_mgr.cc @@ -28,10 +28,9 @@ MtTcpListenerMgr::MtTcpListenerMgr(TcpListenerFactory listener_factory, const uint16_t thread_pool_size /* = 1 */, TlsContextPtr context /* = () */, TcpConnectionFilterCallback connection_filter /* = 0 */) - : listener_factory_(listener_factory), - address_(address), port_(port), thread_io_service_(), tcp_listener_(), - thread_pool_size_(thread_pool_size), thread_pool_(), - tls_context_(context), connection_filter_(connection_filter), + : listener_factory_(listener_factory), address_(address), port_(port), + thread_io_service_(), tcp_listener_(), thread_pool_size_(thread_pool_size), + thread_pool_(), tls_context_(context), connection_filter_(connection_filter), idle_timeout_(TCP_IDLE_CONNECTION_TIMEOUT) { } @@ -78,14 +77,33 @@ MtTcpListenerMgr::start() { .arg(port_) .arg(tls_context_ ? "true" : "false"); } catch (const std::exception& ex) { - tcp_listener_.reset(); - thread_pool_.reset(); - thread_io_service_->restart(); - try { - thread_io_service_->poll(); - } catch (...) { + if (thread_pool_) { + // Stop the thread pool. + thread_pool_->stop(); } + + if (tcp_listener_) { + // Stop the listener. + tcp_listener_->stop(); + } + + if (thread_io_service_) { + thread_io_service_->restart(); + try { + thread_io_service_->poll(); + } catch (...) { + } + } + + // Get rid of the thread pool. + thread_pool_.reset(); + + // Get rid of the listener. + tcp_listener_.reset(); + + // Ditch the IOService. thread_io_service_.reset(); + isc_throw(Unexpected, "MtTcpListenerMgr::start failed:" << ex.what()); } } @@ -125,8 +143,8 @@ MtTcpListenerMgr::stop() { // Stop the thread pool. thread_pool_->stop(); - // Get rid of the listener. - tcp_listener_.reset(); + // Stop the listener. + tcp_listener_->stop(); thread_io_service_->restart(); try { @@ -134,6 +152,12 @@ MtTcpListenerMgr::stop() { } catch (...) { } + // Get rid of the thread pool. + thread_pool_.reset(); + + // Get rid of the listener. + tcp_listener_.reset(); + // Ditch the IOService. thread_io_service_.reset(); diff --git a/src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc b/src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc index cd4dc12345..0e7a1788c8 100644 --- a/src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc +++ b/src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc @@ -811,8 +811,6 @@ TEST_F(MtTcpListenerMgrTest, basics) { ASSERT_THROW_MSG(mt_listener_mgr_->start(), InvalidOperation, "MtTcpListenerMgr already started!"); - return; - // Stop it and verify we're no longer listening. ASSERT_NO_THROW_LOG(mt_listener_mgr_->stop()); ASSERT_TRUE(mt_listener_mgr_->isStopped()); diff --git a/src/lib/util/stopwatch.cc b/src/lib/util/stopwatch.cc index f75c6cdf4c..9406de89d8 100644 --- a/src/lib/util/stopwatch.cc +++ b/src/lib/util/stopwatch.cc @@ -23,7 +23,6 @@ Stopwatch::Stopwatch(const bool autostart) } Stopwatch::~Stopwatch() { - delete impl_; } void diff --git a/src/lib/util/stopwatch.h b/src/lib/util/stopwatch.h index c3d0b23079..f5c737abbb 100644 --- a/src/lib/util/stopwatch.h +++ b/src/lib/util/stopwatch.h @@ -118,7 +118,7 @@ class Stopwatch : boost::noncopyable { private: /// @brief Pointer to the @c StopwatchImpl. - StopwatchImpl* impl_; + boost::shared_ptr impl_; };