]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#2799] fixed crash on Listener stop if start throws
authorRazvan Becheriu <razvan@isc.org>
Thu, 23 Mar 2023 18:48:48 +0000 (20:48 +0200)
committerRazvan Becheriu <razvan@isc.org>
Fri, 24 Mar 2023 10:12:40 +0000 (12:12 +0200)
13 files changed:
src/bin/dhcp4/ctrl_dhcp4_srv.cc
src/bin/dhcp4/ctrl_dhcp4_srv.h
src/bin/dhcp6/ctrl_dhcp6_srv.cc
src/bin/dhcp6/ctrl_dhcp6_srv.h
src/bin/netconf/http_control_socket.cc
src/hooks/dhcp/high_availability/ha_service.cc
src/lib/config/cmd_http_listener.cc
src/lib/http/client.cc
src/lib/http/client.h
src/lib/http/tests/client_mt_unittests.cc
src/lib/http/tests/server_client_unittests.cc
src/lib/http/tests/tls_client_unittests.cc
src/lib/tcp/mt_tcp_listener_mgr.cc

index 66a369b118c483561383d5b4245e1a68441de5c7..436f2d982a7250e9f1c41779b965695e4fd34179 100644 (file)
@@ -239,7 +239,12 @@ ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
         HookLibsCollection loaded = HooksManager::getLibraryInfo();
         HooksManager::prepareUnloadLibraries();
         static_cast<void>(HooksManager::unloadLibraries());
-        bool status = HooksManager::loadLibraries(loaded);
+        bool multi_threading_enabled = true;
+        uint32_t thread_count = 0;
+        uint32_t queue_size = 0;
+        CfgMultiThreading::extract(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading(),
+                                   multi_threading_enabled, thread_count, queue_size);
+        bool status = HooksManager::loadLibraries(loaded, multi_threading_enabled);
         if (!status) {
             isc_throw(Unexpected, "Failed to reload hooks libraries "
                                   "(WARNING: libreload is deprecated).");
@@ -259,7 +264,7 @@ ConstElementPtr
 ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
                                                 ConstElementPtr /*args*/) {
     // Get configuration file name.
-    std::string file = ControlledDhcpv4Srv::getInstance()->getConfigFile();
+    string file = ControlledDhcpv4Srv::getInstance()->getConfigFile();
     try {
         LOG_INFO(dhcp4_logger, DHCP4_DYNAMIC_RECONFIGURATION).arg(file);
         auto result = loadConfigFile(file);
@@ -320,7 +325,7 @@ ControlledDhcpv4Srv::commandConfigWriteHandler(const string&,
         ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
         size = writeConfigFile(filename, cfg);
     } catch (const isc::Exception& ex) {
-        return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config:")
+        return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config: ")
                              + ex.what()));
     }
     if (size == 0) {
index 83b339f73e96de46996dac5965efd54ff9a5761f..99f668c4c6fcf80a007309c3b5961beae5e9c6ba 100644 (file)
@@ -45,18 +45,18 @@ public:
 
     /// @brief Configure DHCPv4 server using the configuration file specified.
     ///
-    /// This utility method is called whenever we know a filename of the config
-    /// and need to load it. It calls config-set command once the content of
-    /// the file has been loaded and verified to be a sane JSON configuration.
-    /// config-set handler will process the config file (load it as current
-    /// configuration).
-    ///
     /// This function is used to both configure the DHCP server on its startup
     /// and dynamically reconfigure the server when SIGHUP signal is received.
     ///
     /// It fetches DHCPv4 server's configuration from the 'Dhcp4' section of
     /// the JSON configuration file.
     ///
+    /// This utility method is called whenever we know a filename of the config
+    /// and need to load it. It calls config-set command once the content of
+    /// the file has been loaded and verified to be a sane JSON configuration.
+    /// config-set handler will process the config file (apply it as current
+    /// configuration).
+    ///
     /// @param file_name name of the file to be loaded
     /// @return status of the file loading and outcome of config-set
     isc::data::ConstElementPtr
@@ -70,7 +70,7 @@ public:
 
     /// @brief Initiates shutdown procedure for the whole DHCPv4 server.
     /// @param exit_value integer value to the process should exit with.
-    void shutdownServer(int exit_value);
+    virtual void shutdownServer(int exit_value);
 
     /// @brief Command processor
     ///
@@ -80,11 +80,18 @@ public:
     /// in them.
     ///
     /// Currently supported commands are:
-    /// - config-reload
-    /// - config-test
     /// - shutdown
     /// - libreload
+    /// - config-reload
+    /// - config-set
+    /// - config-get
+    /// - config-test
+    /// - dhcp-disable
+    /// - dhcp-enable
+    /// - version-get
+    /// - build-report
     /// - leases-reclaim
+    /// - config-write
     /// ...
     ///
     /// @note It never throws.
@@ -140,7 +147,6 @@ public:
     }
 
 private:
-
     /// @brief Callback that will be called from iface_mgr when data
     /// is received over control socket.
     ///
index 55c3046dbf37566e3e24d9f88ffac3a8ece22d73..b4d9e0d2ed2c7bf15ac860ea510469673398b428 100644 (file)
@@ -19,8 +19,8 @@
 #include <dhcpsrv/cfg_multi_threading.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/db_type.h>
-#include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/host_mgr.h>
+#include <dhcpsrv/lease_mgr_factory.h>
 #include <hooks/hooks.h>
 #include <hooks/hooks_manager.h>
 #include <process/cfgrpt/config_report.h>
@@ -91,6 +91,41 @@ namespace dhcp {
 
 ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
 
+void
+ControlledDhcpv6Srv::init(const std::string& file_name) {
+    // Keep the call timestamp.
+    start_ = boost::posix_time::second_clock::universal_time();
+
+    // Configure the server using JSON file.
+    ConstElementPtr result = loadConfigFile(file_name);
+
+    int rcode;
+    ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
+    if (rcode != CONTROL_RESULT_SUCCESS) {
+        string reason = comment ? comment->stringValue() :
+            "no details available";
+        isc_throw(isc::BadValue, reason);
+    }
+
+    // We don't need to call openActiveSockets() or startD2() as these
+    // methods are called in processConfig() which is called by
+    // processCommand("config-set", ...)
+
+    // Set signal handlers. When the SIGHUP is received by the process
+    // the server reconfiguration will be triggered. When SIGTERM or
+    // SIGINT will be received, the server will start shutting down.
+    signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
+
+    signal_set_->add(SIGINT);
+    signal_set_->add(SIGHUP);
+    signal_set_->add(SIGTERM);
+}
+
+void ControlledDhcpv6Srv::cleanup() {
+    signal_set_.reset();
+    getIOService()->poll();
+}
+
 ConstElementPtr
 ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
     // This is a configuration backend implementation that reads the
@@ -103,8 +138,8 @@ ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
     try {
         if (file_name.empty()) {
             // Basic sanity check: file name must not be empty.
-            isc_throw(isc::BadValue, "JSON configuration file not specified. Please "
-                      "use -c command line option.");
+            isc_throw(isc::BadValue, "JSON configuration file not specified."
+                      " Please use -c command line option.");
         }
 
         // Read contents of the file and parse it as JSON
@@ -163,41 +198,6 @@ ControlledDhcpv6Srv::loadConfigFile(const std::string& file_name) {
     return (result);
 }
 
-void
-ControlledDhcpv6Srv::init(const std::string& file_name) {
-    // Keep the call timestamp.
-    start_ = boost::posix_time::second_clock::universal_time();
-
-    // Configure the server using JSON file.
-    ConstElementPtr result = loadConfigFile(file_name);
-
-    int rcode;
-    ConstElementPtr comment = isc::config::parseAnswer(rcode, result);
-    if (rcode != CONTROL_RESULT_SUCCESS) {
-        string reason = comment ? comment->stringValue() :
-            "no details available";
-        isc_throw(isc::BadValue, reason);
-    }
-
-    // We don't need to call openActiveSockets() or startD2() as these
-    // methods are called in processConfig() which is called by
-    // processCommand("config-set", ...)
-
-    // Set signal handlers. When the SIGHUP is received by the process
-    // the server reconfiguration will be triggered. When SIGTERM or
-    // SIGINT will be received, the server will start shutting down.
-    signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
-
-    signal_set_->add(SIGINT);
-    signal_set_->add(SIGHUP);
-    signal_set_->add(SIGTERM);
-}
-
-void ControlledDhcpv6Srv::cleanup() {
-    signal_set_.reset();
-    getIOService()->poll();
-}
-
 ConstElementPtr
 ControlledDhcpv6Srv::commandShutdownHandler(const string&, ConstElementPtr args) {
     if (!ControlledDhcpv6Srv::getInstance()) {
@@ -242,10 +242,15 @@ ControlledDhcpv6Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
         HookLibsCollection loaded = HooksManager::getLibraryInfo();
         HooksManager::prepareUnloadLibraries();
         static_cast<void>(HooksManager::unloadLibraries());
-        bool status = HooksManager::loadLibraries(loaded);
+        bool multi_threading_enabled = true;
+        uint32_t thread_count = 0;
+        uint32_t queue_size = 0;
+        CfgMultiThreading::extract(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading(),
+                                   multi_threading_enabled, thread_count, queue_size);
+        bool status = HooksManager::loadLibraries(loaded, multi_threading_enabled);
         if (!status) {
-            isc_throw(Unexpected, "Failed to reload hooks libraries"
-                                  " (WARNING: libreload is deprecated).");
+            isc_throw(Unexpected, "Failed to reload hooks libraries "
+                                  "(WARNING: libreload is deprecated).");
         }
     } catch (const std::exception& ex) {
         LOG_ERROR(dhcp6_logger, DHCP6_HOOKS_LIBS_RELOAD_FAIL);
@@ -262,7 +267,7 @@ ConstElementPtr
 ControlledDhcpv6Srv::commandConfigReloadHandler(const string&,
                                                 ConstElementPtr /*args*/) {
     // Get configuration file name.
-    std::string file = ControlledDhcpv6Srv::getInstance()->getConfigFile();
+    string file = ControlledDhcpv6Srv::getInstance()->getConfigFile();
     try {
         LOG_INFO(dhcp6_logger, DHCP6_DYNAMIC_RECONFIGURATION).arg(file);
         auto result = loadConfigFile(file);
@@ -323,7 +328,7 @@ ControlledDhcpv6Srv::commandConfigWriteHandler(const string&,
         ConstElementPtr cfg = CfgMgr::instance().getCurrentCfg()->toElement();
         size = writeConfigFile(filename, cfg);
     } catch (const isc::Exception& ex) {
-        return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config:")
+        return (createAnswer(CONTROL_RESULT_ERROR, string("Error during write-config: ")
                              + ex.what()));
     }
     if (size == 0) {
@@ -1115,8 +1120,8 @@ ControlledDhcpv6Srv::checkConfig(isc::data::ConstElementPtr config) {
     return (configureDhcp6Server(*srv, config, true));
 }
 
-ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port,
-                                         uint16_t client_port)
+ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port /*= DHCP6_SERVER_PORT*/,
+                                         uint16_t client_port /*= 0*/)
     : Dhcpv6Srv(server_port, client_port), timer_mgr_(TimerMgr::instance()) {
     if (getInstance()) {
         isc_throw(InvalidOperation,
@@ -1150,17 +1155,23 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port,
     CommandMgr::instance().registerCommand("config-reload",
         std::bind(&ControlledDhcpv6Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
 
+    CommandMgr::instance().registerCommand("config-set",
+        std::bind(&ControlledDhcpv6Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
+
     CommandMgr::instance().registerCommand("config-test",
         std::bind(&ControlledDhcpv6Srv::commandConfigTestHandler, this, ph::_1, ph::_2));
 
     CommandMgr::instance().registerCommand("config-write",
         std::bind(&ControlledDhcpv6Srv::commandConfigWriteHandler, this, ph::_1, ph::_2));
 
+    CommandMgr::instance().registerCommand("dhcp-enable",
+        std::bind(&ControlledDhcpv6Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
+
     CommandMgr::instance().registerCommand("dhcp-disable",
         std::bind(&ControlledDhcpv6Srv::commandDhcpDisableHandler, this, ph::_1, ph::_2));
 
-    CommandMgr::instance().registerCommand("dhcp-enable",
-        std::bind(&ControlledDhcpv6Srv::commandDhcpEnableHandler, this, ph::_1, ph::_2));
+    CommandMgr::instance().registerCommand("libreload",
+        std::bind(&ControlledDhcpv6Srv::commandLibReloadHandler, this, ph::_1, ph::_2));
 
     CommandMgr::instance().registerCommand("leases-reclaim",
         std::bind(&ControlledDhcpv6Srv::commandLeasesReclaimHandler, this, ph::_1, ph::_2));
@@ -1168,12 +1179,6 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port,
     CommandMgr::instance().registerCommand("server-tag-get",
         std::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, ph::_1, ph::_2));
 
-    CommandMgr::instance().registerCommand("libreload",
-        std::bind(&ControlledDhcpv6Srv::commandLibReloadHandler, this, ph::_1, ph::_2));
-
-    CommandMgr::instance().registerCommand("config-set",
-        std::bind(&ControlledDhcpv6Srv::commandConfigSetHandler, this, ph::_1, ph::_2));
-
     CommandMgr::instance().registerCommand("shutdown",
         std::bind(&ControlledDhcpv6Srv::commandShutdownHandler, this, ph::_1, ph::_2));
 
@@ -1187,18 +1192,18 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port,
     CommandMgr::instance().registerCommand("statistic-get",
         std::bind(&StatsMgr::statisticGetHandler, ph::_1, ph::_2));
 
-    CommandMgr::instance().registerCommand("statistic-get-all",
-        std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
-
     CommandMgr::instance().registerCommand("statistic-reset",
         std::bind(&StatsMgr::statisticResetHandler, ph::_1, ph::_2));
 
-    CommandMgr::instance().registerCommand("statistic-reset-all",
-        std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
-
     CommandMgr::instance().registerCommand("statistic-remove",
         std::bind(&StatsMgr::statisticRemoveHandler, ph::_1, ph::_2));
 
+    CommandMgr::instance().registerCommand("statistic-get-all",
+        std::bind(&StatsMgr::statisticGetAllHandler, ph::_1, ph::_2));
+
+    CommandMgr::instance().registerCommand("statistic-reset-all",
+        std::bind(&StatsMgr::statisticResetAllHandler, ph::_1, ph::_2));
+
     CommandMgr::instance().registerCommand("statistic-remove-all",
         std::bind(&StatsMgr::statisticRemoveAllHandler, ph::_1, ph::_2));
 
index 41c2a223e386d10800044b7bddf517af8216f268..41833de59d3b73f127eb4aaa08538947fa54734e 100644 (file)
@@ -80,11 +80,18 @@ public:
     /// in them.
     ///
     /// Currently supported commands are:
-    /// - config-reload
-    /// - config-test
     /// - shutdown
     /// - libreload
+    /// - config-reload
+    /// - config-set
+    /// - config-get
+    /// - config-test
+    /// - dhcp-disable
+    /// - dhcp-enable
+    /// - version-get
+    /// - build-report
     /// - leases-reclaim
+    /// - config-write
     /// ...
     ///
     /// @note It never throws.
@@ -140,7 +147,6 @@ public:
     }
 
 private:
-
     /// @brief Callback that will be called from iface_mgr when data
     /// is received over control socket.
     ///
index 7396488994848bda3a9da893ce0a0e0a118337a2..2546eb9f45b10b3f367f06d3876f35783db9a47e 100644 (file)
@@ -79,7 +79,7 @@ HttpControlSocket::sendCommand(ConstElementPtr command) {
     }
 
     IOServicePtr io_service(new IOService());
-    HttpClient client(*io_service);
+    HttpClient client(*io_service, false);
     boost::system::error_code received_ec;
     string receive_errmsg;
     HttpResponseJsonPtr response(new HttpResponseJson());
index a3951dc7cb40d6c0d515b6a158e915aecd3fdd33..8ddfc3dd742b7deaf28d10c3e4fea6a2bfc69368 100644 (file)
@@ -93,10 +93,10 @@ HAService::HAService(const IOServicePtr& io_service, const NetworkStatePtr& netw
     // Create the client and(or) listener as appropriate.
     if (!config_->getEnableMultiThreading()) {
         // Not configured for multi-threading, start a client in ST mode.
-        client_.reset(new HttpClient(*io_service_, 0));
+        client_.reset(new HttpClient(*io_service_, false));
     } else {
         // Create an MT-mode client.
-        client_.reset(new HttpClient(*io_service_,
+        client_.reset(new HttpClient(*io_service_, true,
                       config_->getHttpClientThreads(), true));
 
         // If we're configured to use our own listener create and start it.
@@ -2263,7 +2263,7 @@ int
 HAService::synchronize(std::string& status_message, const std::string& server_name,
                        const unsigned int max_period) {
     IOService io_service;
-    HttpClient client(io_service);
+    HttpClient client(io_service, false);
 
     asyncSyncLeases(client, server_name, max_period, Lease4Ptr(),
                     [&](const bool success, const std::string& error_message,
@@ -2468,7 +2468,7 @@ HAService::sendLeaseUpdatesFromBacklog() {
     }
 
     IOService io_service;
-    HttpClient client(io_service);
+    HttpClient client(io_service, false);
     auto remote_config = config_->getFailoverPeerConfig();
     bool updates_successful = true;
 
@@ -2553,7 +2553,7 @@ HAService::asyncSendHAReset(HttpClient& http_client,
 bool
 HAService::sendHAReset() {
     IOService io_service;
-    HttpClient client(io_service);
+    HttpClient client(io_service, false);
     auto remote_config = config_->getFailoverPeerConfig();
     bool reset_successful = true;
 
@@ -2656,7 +2656,7 @@ HAService::processMaintenanceStart() {
     HttpResponseJsonPtr response = boost::make_shared<HttpResponseJson>();
 
     IOService io_service;
-    HttpClient client(io_service);
+    HttpClient client(io_service, false);
 
     boost::system::error_code captured_ec;
     std::string captured_error_message;
@@ -2780,7 +2780,7 @@ HAService::processMaintenanceCancel() {
     HttpResponseJsonPtr response = boost::make_shared<HttpResponseJson>();
 
     IOService io_service;
-    HttpClient client(io_service);
+    HttpClient client(io_service, false);
 
     std::string error_message;
 
index be8d7993e24ba75247990431b2a3de08fcf54a29..5fb88046c3f25a2609e20885468837a4f146814e 100644 (file)
@@ -81,6 +81,9 @@ CmdHttpListener::start() {
             .arg(port_)
             .arg(tls_context_ ? "true" : "false");
     } catch (const std::exception& ex) {
+        thread_io_service_.reset();
+        http_listener_.reset();
+        thread_pool_.reset();
         isc_throw(Unexpected, "CmdHttpListener::run failed:" << ex.what());
     }
 }
index 42385ed27edb634ad6427e7e7142306a3dc27011..911843b4b0ceacc20428e7148509013009339c60 100644 (file)
@@ -1947,8 +1947,14 @@ private:
     IoServiceThreadPoolPtr thread_pool_;
 };
 
-HttpClient::HttpClient(IOService& io_service, size_t thread_pool_size,
-                       bool defer_thread_start /* = false */) {
+HttpClient::HttpClient(IOService& io_service, bool multi_threading_enabled,
+                       size_t thread_pool_size, bool defer_thread_start) {
+    if (!multi_threading_enabled && thread_pool_size) {
+        isc_throw(InvalidOperation,
+                  "HttpClient thread_pool_size must be zero "
+                  "when Kea core multi-threading is disabled");
+    }
+
     impl_.reset(new HttpClientImpl(io_service, thread_pool_size,
                                    defer_thread_start));
 }
index f6612c88e286bb68bb10b59fdc79de3946144a09..32c2bf221d7b2da395133e0a601941ab5d909afe 100644 (file)
@@ -134,6 +134,7 @@ public:
     /// @brief Constructor.
     ///
     /// @param io_service IO service to be used by the HTTP client.
+    /// @param multi_threading_enabled The flag which indicates if MT is enabled.
     /// @param thread_pool_size maximum number of threads in the thread pool.
     /// A value greater than zero enables multi-threaded mode and sets the
     /// maximum number of concurrent connections per URL.  A value of zero
@@ -144,7 +145,9 @@ public:
     /// the thread pool threads will be created and started, with the
     /// operational state being RUNNING.  Applicable only when thread-pool size
     /// is greater than zero.
-    explicit HttpClient(asiolink::IOService& io_service, size_t thread_pool_size = 0,
+    explicit HttpClient(asiolink::IOService& io_service,
+                        bool multi_threading_enabled,
+                        size_t thread_pool_size = 0,
                         bool defer_thread_start = false);
 
     /// @brief Destructor.
index e6b98556e6cbe5e3c25333d98d2328c3d52f8747..ef04c28c6000a0d3cbd699fa86feba0d550a2dea 100644 (file)
@@ -481,7 +481,9 @@ public:
         }
 
         // Create an MT client with num_threads
-        ASSERT_NO_THROW_LOG(client_.reset(new HttpClient(io_service_, num_threads, true)));
+        ASSERT_NO_THROW_LOG(client_.reset(new HttpClient(io_service_,
+                                                         num_threads ? true : false,
+                                                         num_threads, true)));
         ASSERT_TRUE(client_);
 
         if (num_threads_ == 0) {
@@ -647,7 +649,7 @@ public:
         }
 
         // Create an instant start, MT client with num_threads
-        ASSERT_NO_THROW_LOG(client_.reset(new HttpClient(io_service_, num_threads, true)));
+        ASSERT_NO_THROW_LOG(client_.reset(new HttpClient(io_service_, true, num_threads, true)));
         ASSERT_TRUE(client_);
 
         // Start the requisite number of requests:
@@ -830,11 +832,10 @@ public:
 // Verifies we can construct and destruct, in both single
 // and multi-threaded modes.
 TEST_F(MultiThreadingHttpClientTest, basics) {
-    MultiThreadingMgr::instance().setMode(false);
     HttpClientPtr client;
 
     // Value of 0 for thread_pool_size means single-threaded.
-    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, 0)));
+    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, false)));
     ASSERT_TRUE(client);
 
     ASSERT_FALSE(client->getThreadIOService());
@@ -844,11 +845,14 @@ TEST_F(MultiThreadingHttpClientTest, basics) {
     // Make sure destruction doesn't throw.
     ASSERT_NO_THROW_LOG(client.reset());
 
-    // Enable Kea core multi-threading.
-    MultiThreadingMgr::instance().setMode(true);
+    // Non-zero thread-pool-size means multi-threaded mode, should throw.
+    ASSERT_THROW_MSG(client.reset(new HttpClient(io_service_, false, 1)), InvalidOperation,
+                                  "HttpClient thread_pool_size must be zero "
+                                  "when Kea core multi-threading is disabled");
+    ASSERT_FALSE(client);
 
     // Multi-threaded construction should work now.
-    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, 3)));
+    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, true, 3)));
     ASSERT_TRUE(client);
 
     // Verify that it has an internal IOService and that thread pool size
@@ -884,7 +888,7 @@ TEST_F(MultiThreadingHttpClientTest, basics) {
     ASSERT_NO_THROW_LOG(client.reset());
 
     // Create another multi-threaded instance.
-    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, 3)));
+    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, true, 3)));
 
     // Make sure destruction doesn't throw.
     ASSERT_NO_THROW_LOG(client.reset());
@@ -892,12 +896,11 @@ TEST_F(MultiThreadingHttpClientTest, basics) {
 
 // Verifies we can construct with deferred start.
 TEST_F(MultiThreadingHttpClientTest, deferredStart) {
-    MultiThreadingMgr::instance().setMode(true);
     HttpClientPtr client;
     size_t thread_pool_size = 3;
 
     // Create MT client with deferred start.
-    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, thread_pool_size, true)));
+    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, true, thread_pool_size, true)));
     ASSERT_TRUE(client);
 
     // Client should be STOPPED, with no threads.
@@ -936,12 +939,11 @@ TEST_F(MultiThreadingHttpClientTest, deferredStart) {
 
 // Verifies we can restart after stop.
 TEST_F(MultiThreadingHttpClientTest, restartAfterStop) {
-    MultiThreadingMgr::instance().setMode(true);
     HttpClientPtr client;
     size_t thread_pool_size = 3;
 
     // Create MT client with instant start.
-    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, thread_pool_size)));
+    ASSERT_NO_THROW_LOG(client.reset(new HttpClient(io_service_, true, thread_pool_size)));
     ASSERT_TRUE(client);
 
     // Verify we're started.
index 4ca280d350ccfffdcb6f5b4bf228eb0573bf4164..7cb66671dddf16f8615a565b2574ad218ec3359e 100644 (file)
@@ -1064,7 +1064,7 @@ public:
         ASSERT_NO_THROW(listener_.start());
 
         // Create a client and specify the URL on which the server can be reached.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
         Url url("http://127.0.0.1:18123");
 
         // Initiate request to the server.
@@ -1122,7 +1122,7 @@ public:
         ASSERT_NO_THROW(listener2_.start());
 
         // Create the client. It will be communicating with the two servers.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URLs on which the servers are available.
         Url url1("http://127.0.0.1:18123");
@@ -1179,7 +1179,7 @@ public:
         ASSERT_NO_THROW(listener_.start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL on which the server is available.
         Url url("http://127.0.0.1:18123");
@@ -1239,7 +1239,7 @@ public:
         ASSERT_NO_THROW(listener3_.start());
 
         // Create the client that will communicate with this server.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of this server.
         Url url("http://127.0.0.1:18125");
@@ -1294,7 +1294,7 @@ public:
     /// server is unreachable.
     void testUnreachable () {
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server. This server is down.
         Url url("http://127.0.0.1:18123");
@@ -1323,7 +1323,7 @@ public:
         ASSERT_NO_THROW(listener_.start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server.
         Url url("http://127.0.0.1:18123");
@@ -1360,7 +1360,7 @@ public:
         ASSERT_NO_THROW(listener_.start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server.
         Url url("http://127.0.0.1:18123");
@@ -1425,7 +1425,7 @@ public:
         ASSERT_NO_THROW(listener_.start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server.
         Url url("http://127.0.0.1:18123");
@@ -1499,7 +1499,7 @@ public:
         ASSERT_NO_THROW(listener_.start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server.
         Url url("http://127.0.0.1:18123");
@@ -1582,7 +1582,7 @@ public:
         ASSERT_NO_THROW(listener_.start());
 
         // Create a client and specify the URL on which the server can be reached.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
         Url url("http://127.0.0.1:18123");
 
         // Initiate request to the server.
@@ -1677,7 +1677,7 @@ public:
         ASSERT_NO_THROW(listener_.start());
 
         // Create a client and specify the URL on which the server can be reached.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
         Url url("http://127.0.0.1:18123");
 
         // Initiate request to the server.
index 4d82e956408e5967e99a4f537c7d7984aec8e606..5828fb0bd844349d7c4543cc072499c7c8636e7f 100644 (file)
@@ -359,7 +359,7 @@ public:
         ASSERT_NO_THROW(listener_->start());
 
         // Create a client and specify the URL on which the server can be reached.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
         Url url("http://127.0.0.1:18123");
 
         // Initiate request to the server.
@@ -421,7 +421,7 @@ public:
         ASSERT_NO_THROW(listener2_->start());
 
         // Create the client. It will be communicating with the two servers.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URLs on which the servers are available.
         Url url1("http://127.0.0.1:18123");
@@ -482,7 +482,7 @@ public:
         ASSERT_NO_THROW(listener_->start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Create a second client context.
         TlsContextPtr client_context2;
@@ -550,7 +550,7 @@ public:
         ASSERT_NO_THROW(listener3_->start());
 
         // Create the client that will communicate with this server.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of this server.
         Url url("http://127.0.0.1:18125");
@@ -609,7 +609,7 @@ public:
     /// server is unreachable.
     void testUnreachable () {
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server. This server is down.
         Url url("http://127.0.0.1:18123");
@@ -640,7 +640,7 @@ public:
         ASSERT_NO_THROW(listener_->start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server.
         Url url("http://127.0.0.1:18123");
@@ -679,7 +679,7 @@ public:
         ASSERT_NO_THROW(listener_->start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server.
         Url url("http://127.0.0.1:18123");
@@ -744,7 +744,7 @@ public:
         ASSERT_NO_THROW(listener_->start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server.
         Url url("http://127.0.0.1:18123");
@@ -818,7 +818,7 @@ public:
         ASSERT_NO_THROW(listener_->start());
 
         // Create the client.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
 
         // Specify the URL of the server.
         Url url("http://127.0.0.1:18123");
@@ -903,7 +903,7 @@ public:
         ASSERT_NO_THROW(listener_->start());
 
         // Create a client and specify the URL on which the server can be reached.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
         Url url("http://127.0.0.1:18123");
 
         // Initiate request to the server.
@@ -1002,7 +1002,7 @@ public:
         ASSERT_NO_THROW(listener_->start());
 
         // Create a client and specify the URL on which the server can be reached.
-        HttpClient client(io_service_);
+        HttpClient client(io_service_, false);
         Url url("http://127.0.0.1:18123");
 
         // Initiate request to the server.
index d2347785e294b17d0f372178cbc125058aab50ab..a8afa6d96512c2eb4c611000a07d794b3064645c 100644 (file)
@@ -78,6 +78,9 @@ MtTcpListenerMgr::start() {
             .arg(port_)
             .arg(tls_context_ ? "true" : "false");
     } catch (const std::exception& ex) {
+        thread_io_service_.reset();
+        tcp_listener_.reset();
+        thread_pool_.reset();
         isc_throw(Unexpected, "MtTcpListenerMgr::start failed:" << ex.what());
     }
 }