From: Razvan Becheriu Date: Wed, 27 Mar 2024 21:38:26 +0000 (+0200) Subject: [#3315] use internal IOService for hooks X-Git-Tag: Kea-2.5.8~52 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4398fb6c4ade33e8da7af7c7ab55ccbe5abace01;p=thirdparty%2Fkea.git [#3315] use internal IOService for hooks --- diff --git a/src/bin/agent/ca_process.cc b/src/bin/agent/ca_process.cc index 9559d84444..536c1fe29f 100644 --- a/src/bin/agent/ca_process.cc +++ b/src/bin/agent/ca_process.cc @@ -89,6 +89,7 @@ CtrlAgentProcess::run() { size_t CtrlAgentProcess::runIO() { + getIOService()->pollExternalIOServices(); size_t cnt = getIOService()->poll(); if (!cnt) { cnt = getIOService()->runOne(); @@ -192,6 +193,17 @@ CtrlAgentProcess::configure(isc::data::ConstElementPtr config_set, int rcode = 0; config::parseAnswer(rcode, answer); + + /// Let postponed hook initializations to run. + try { + getIOService()->pollExternalIOServices(); + } catch (const std::exception& ex) { + std::ostringstream err; + err << "Error initializing hooks: " + << ex.what(); + return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str())); + } + return (answer); } diff --git a/src/bin/d2/check_exists_add.cc b/src/bin/d2/check_exists_add.cc index 5cd4601664..528f9863f7 100644 --- a/src/bin/d2/check_exists_add.cc +++ b/src/bin/d2/check_exists_add.cc @@ -29,10 +29,10 @@ const int CheckExistsAddTransaction::FQDN_NOT_IN_USE_EVT; CheckExistsAddTransaction:: CheckExistsAddTransaction(asiolink::IOServicePtr& io_service, - dhcp_ddns::NameChangeRequestPtr& ncr, - DdnsDomainPtr& forward_domain, - DdnsDomainPtr& reverse_domain, - D2CfgMgrPtr& cfg_mgr) + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain, + D2CfgMgrPtr& cfg_mgr) : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain, cfg_mgr) { if (ncr->getChangeType() != isc::dhcp_ddns::CHG_ADD) { diff --git a/src/bin/d2/check_exists_remove.cc b/src/bin/d2/check_exists_remove.cc index f55680a573..7f2f2e2e26 100644 --- a/src/bin/d2/check_exists_remove.cc +++ b/src/bin/d2/check_exists_remove.cc @@ -26,10 +26,10 @@ const int CheckExistsRemoveTransaction::REMOVING_REV_PTRS_ST; CheckExistsRemoveTransaction:: CheckExistsRemoveTransaction(asiolink::IOServicePtr& io_service, - dhcp_ddns::NameChangeRequestPtr& ncr, - DdnsDomainPtr& forward_domain, - DdnsDomainPtr& reverse_domain, - D2CfgMgrPtr& cfg_mgr) + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain, + D2CfgMgrPtr& cfg_mgr) : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain, cfg_mgr) { if (ncr->getChangeType() != isc::dhcp_ddns::CHG_REMOVE) { diff --git a/src/bin/d2/d2_hooks.dox b/src/bin/d2/d2_hooks.dox index 0c33820b8f..55410809b7 100644 --- a/src/bin/d2/d2_hooks.dox +++ b/src/bin/d2/d2_hooks.dox @@ -55,12 +55,15 @@ to the end of this list. - @b Description: this callout is executed when the server has completed its (re)configuration. The server provides received and parsed configuration - structures to the hook library. It also provides a pointer to the IOService - object which is used by the server to run asynchronous operations. The hooks - libraries can use this IOService object to schedule asynchronous tasks which - are triggered by the Kea DHCP DDNS's main loop. The hook library should hold - the provided pointer until the library is unloaded. The D2CfgContext - object provides access to the D2 running configuration. + structures to the hook library. + If the library uses any IO operations, it should create a local IOService + object and register it to the main IOService which is also provided. This way + the local IOService is used by the server to run asynchronous operations. The + hooks library can use the local IOService object to schedule asynchronous + tasks which are triggered by the D2 server's main loop. The hook library + should hold the provided pointer until the library is unloaded at which stage + it must unregister the local IOService. + The D2CfgContext object provides access to the D2 running configuration. - Next step status: If any callout sets the status to DROP, the server considers the configuration is incorrect and rejects it using the error diff --git a/src/bin/d2/d2_process.cc b/src/bin/d2/d2_process.cc index 134498a457..c77430cd82 100644 --- a/src/bin/d2/d2_process.cc +++ b/src/bin/d2/d2_process.cc @@ -129,6 +129,7 @@ D2Process::run() { size_t D2Process::runIO() { + getIOService()->pollExternalIOServices(); // We want to block until at least one handler is called. We'll use // boost::asio::io_service directly for two reasons. First off // asiolink::IOService::runOne is a void and boost::asio::io_service::stopped @@ -148,7 +149,6 @@ D2Process::runIO() { // service is stopped it will return immediately with a cnt of zero. cnt = getIOService()->runOne(); } - return (cnt); } @@ -301,6 +301,16 @@ D2Process::configure(isc::data::ConstElementPtr config_set, bool check_only) { } } + /// Let postponed hook initializations to run. + try { + getIOService()->pollExternalIOServices(); + } catch (const std::exception& ex) { + std::ostringstream err; + err << "Error initializing hooks: " + << ex.what(); + return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str())); + } + // If we are here, configuration was valid, at least it parsed correctly // and therefore contained no invalid values. // Return the success answer from above. diff --git a/src/bin/d2/nc_remove.cc b/src/bin/d2/nc_remove.cc index f2e86efd57..bb0daee074 100644 --- a/src/bin/d2/nc_remove.cc +++ b/src/bin/d2/nc_remove.cc @@ -26,10 +26,10 @@ const int NameRemoveTransaction::REMOVING_REV_PTRS_ST; NameRemoveTransaction:: NameRemoveTransaction(asiolink::IOServicePtr& io_service, - dhcp_ddns::NameChangeRequestPtr& ncr, - DdnsDomainPtr& forward_domain, - DdnsDomainPtr& reverse_domain, - D2CfgMgrPtr& cfg_mgr) + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain, + D2CfgMgrPtr& cfg_mgr) : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain, cfg_mgr) { if (ncr->getChangeType() != isc::dhcp_ddns::CHG_REMOVE) { diff --git a/src/bin/d2/simple_add.cc b/src/bin/d2/simple_add.cc index 3a577f3141..ddfc2ad838 100644 --- a/src/bin/d2/simple_add.cc +++ b/src/bin/d2/simple_add.cc @@ -28,10 +28,10 @@ const int SimpleAddTransaction::FQDN_NOT_IN_USE_EVT; SimpleAddTransaction:: SimpleAddTransaction(asiolink::IOServicePtr& io_service, - dhcp_ddns::NameChangeRequestPtr& ncr, - DdnsDomainPtr& forward_domain, - DdnsDomainPtr& reverse_domain, - D2CfgMgrPtr& cfg_mgr) + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain, + D2CfgMgrPtr& cfg_mgr) : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain, cfg_mgr) { if (ncr->getChangeType() != isc::dhcp_ddns::CHG_ADD) { diff --git a/src/bin/d2/simple_add_without_dhcid.cc b/src/bin/d2/simple_add_without_dhcid.cc index 8979f8b4f3..02cc8cf233 100644 --- a/src/bin/d2/simple_add_without_dhcid.cc +++ b/src/bin/d2/simple_add_without_dhcid.cc @@ -28,10 +28,10 @@ const int SimpleAddWithoutDHCIDTransaction::FQDN_NOT_IN_USE_EVT; SimpleAddWithoutDHCIDTransaction:: SimpleAddWithoutDHCIDTransaction(asiolink::IOServicePtr& io_service, - dhcp_ddns::NameChangeRequestPtr& ncr, - DdnsDomainPtr& forward_domain, - DdnsDomainPtr& reverse_domain, - D2CfgMgrPtr& cfg_mgr) + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain, + D2CfgMgrPtr& cfg_mgr) : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain, cfg_mgr) { if (ncr->getChangeType() != isc::dhcp_ddns::CHG_ADD) { diff --git a/src/bin/d2/simple_remove.cc b/src/bin/d2/simple_remove.cc index 92765e3a74..1c165dd462 100644 --- a/src/bin/d2/simple_remove.cc +++ b/src/bin/d2/simple_remove.cc @@ -25,10 +25,10 @@ const int SimpleRemoveTransaction::REMOVING_REV_PTRS_ST; SimpleRemoveTransaction:: SimpleRemoveTransaction(asiolink::IOServicePtr& io_service, - dhcp_ddns::NameChangeRequestPtr& ncr, - DdnsDomainPtr& forward_domain, - DdnsDomainPtr& reverse_domain, - D2CfgMgrPtr& cfg_mgr) + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain, + D2CfgMgrPtr& cfg_mgr) : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain, cfg_mgr) { if (ncr->getChangeType() != isc::dhcp_ddns::CHG_REMOVE) { diff --git a/src/bin/d2/simple_remove_without_dhcid.cc b/src/bin/d2/simple_remove_without_dhcid.cc index d96939b558..ba7d8722ac 100644 --- a/src/bin/d2/simple_remove_without_dhcid.cc +++ b/src/bin/d2/simple_remove_without_dhcid.cc @@ -25,10 +25,10 @@ const int SimpleRemoveWithoutDHCIDTransaction::REMOVING_REV_PTRS_ST; SimpleRemoveWithoutDHCIDTransaction:: SimpleRemoveWithoutDHCIDTransaction(asiolink::IOServicePtr& io_service, - dhcp_ddns::NameChangeRequestPtr& ncr, - DdnsDomainPtr& forward_domain, - DdnsDomainPtr& reverse_domain, - D2CfgMgrPtr& cfg_mgr) + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain, + D2CfgMgrPtr& cfg_mgr) : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain, cfg_mgr) { if (ncr->getChangeType() != isc::dhcp_ddns::CHG_REMOVE) { diff --git a/src/bin/d2/tests/check_exists_remove_unittests.cc b/src/bin/d2/tests/check_exists_remove_unittests.cc index d852860297..af42ed6fef 100644 --- a/src/bin/d2/tests/check_exists_remove_unittests.cc +++ b/src/bin/d2/tests/check_exists_remove_unittests.cc @@ -1159,7 +1159,7 @@ TEST_F(CheckExistsRemoveTransactionTest, selectingRevServerHandler) { // Post a server IO error event. This simulates an IO error occurring // and a need to select the new server. ASSERT_NO_THROW(name_remove->postNextEvent(NameChangeTransaction:: - SERVER_IO_ERROR_EVT)) + SERVER_IO_ERROR_EVT)) << " num_servers: " << num_servers << " selections: " << i; } diff --git a/src/bin/d2/tests/d2_simple_parser_unittest.cc b/src/bin/d2/tests/d2_simple_parser_unittest.cc index fcdbb26560..51728cbfdc 100644 --- a/src/bin/d2/tests/d2_simple_parser_unittest.cc +++ b/src/bin/d2/tests/d2_simple_parser_unittest.cc @@ -378,7 +378,7 @@ public: /// @return the number of default items added to the tree size_t setDefaults(data::ElementPtr config) { return (SimpleParser::setListDefaults(config, D2SimpleParser:: - TSIG_KEY_DEFAULTS)); + TSIG_KEY_DEFAULTS)); } /// @brief Attempts to parse the given element into a list of TSIGKeyInfos @@ -422,7 +422,7 @@ public: /// @return the number of default items added to the tree virtual size_t setDefaults(data::ElementPtr config) { return (SimpleParser::setDefaults(config, D2SimpleParser:: - DNS_SERVER_DEFAULTS)); + DNS_SERVER_DEFAULTS)); } /// @brief Attempts to parse the given element into a DnsServerInfo @@ -468,7 +468,7 @@ public: /// @return the number of default items added to the tree virtual size_t setDefaults(data::ElementPtr config) { return (SimpleParser::setListDefaults(config, D2SimpleParser:: - DNS_SERVER_DEFAULTS)); + DNS_SERVER_DEFAULTS)); } /// @brief Attempts to parse the given element into a list of DnsServerInfos @@ -579,9 +579,8 @@ public: // We don't use SimpleParser::setListDefaults() as this does // not handle sub-lists or sub-maps for (auto const& domain : config->listValue()) { - cnt += D2SimpleParser:: - setDdnsDomainDefaults(domain, D2SimpleParser:: - DDNS_DOMAIN_DEFAULTS); + cnt += D2SimpleParser::setDdnsDomainDefaults(domain, D2SimpleParser:: + DDNS_DOMAIN_DEFAULTS); } return (cnt); diff --git a/src/bin/d2/tests/nc_remove_unittests.cc b/src/bin/d2/tests/nc_remove_unittests.cc index df00876cf3..0371ab3978 100644 --- a/src/bin/d2/tests/nc_remove_unittests.cc +++ b/src/bin/d2/tests/nc_remove_unittests.cc @@ -1159,7 +1159,7 @@ TEST_F(NameRemoveTransactionTest, selectingRevServerHandler) { // Post a server IO error event. This simulates an IO error occurring // and a need to select the new server. ASSERT_NO_THROW(name_remove->postNextEvent(NameChangeTransaction:: - SERVER_IO_ERROR_EVT)) + SERVER_IO_ERROR_EVT)) << " num_servers: " << num_servers << " selections: " << i; } diff --git a/src/bin/d2/tests/simple_remove_unittests.cc b/src/bin/d2/tests/simple_remove_unittests.cc index 180fb2b3e0..b7e33d2dcd 100644 --- a/src/bin/d2/tests/simple_remove_unittests.cc +++ b/src/bin/d2/tests/simple_remove_unittests.cc @@ -717,7 +717,7 @@ TEST_F(SimpleRemoveTransactionTest, selectingRevServerHandler) { // Post a server IO error event. This simulates an IO error occurring // and a need to select the new server. ASSERT_NO_THROW(name_remove->postNextEvent(NameChangeTransaction:: - SERVER_IO_ERROR_EVT)); + SERVER_IO_ERROR_EVT)); } // We should have exhausted the list of servers. Processing another diff --git a/src/bin/d2/tests/simple_remove_without_dhcid_unittests.cc b/src/bin/d2/tests/simple_remove_without_dhcid_unittests.cc index 4dbd584b6f..9479d8178e 100644 --- a/src/bin/d2/tests/simple_remove_without_dhcid_unittests.cc +++ b/src/bin/d2/tests/simple_remove_without_dhcid_unittests.cc @@ -717,7 +717,7 @@ TEST_F(SimpleRemoveWithoutDHCIDTransactionTest, selectingRevServerHandler) { // Post a server IO error event. This simulates an IO error occurring // and a need to select the new server. ASSERT_NO_THROW(name_remove->postNextEvent(NameChangeTransaction:: - SERVER_IO_ERROR_EVT)); + SERVER_IO_ERROR_EVT)); } // We should have exhausted the list of servers. Processing another diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc index 54a8d12da2..a3cc72087d 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc @@ -241,6 +241,7 @@ ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) { HookLibsCollection loaded = HooksManager::getLibraryInfo(); HooksManager::prepareUnloadLibraries(); static_cast(HooksManager::unloadLibraries()); + getIOService()->clearExternalIOServices(); bool multi_threading_enabled = true; uint32_t thread_count = 0; uint32_t queue_size = 0; @@ -452,7 +453,7 @@ ControlledDhcpv4Srv::commandConfigSetHandler(const string&, /// Let postponed hook initializations to run. try { - getIOService()->poll(); + getIOService()->pollExternalIOServices(); } catch (const std::exception& ex) { std::ostringstream err; err << "Error initializing hooks: " diff --git a/src/bin/dhcp4/dhcp4_hooks.dox b/src/bin/dhcp4/dhcp4_hooks.dox index ae6c903ff9..177e5600ba 100644 --- a/src/bin/dhcp4/dhcp4_hooks.dox +++ b/src/bin/dhcp4/dhcp4_hooks.dox @@ -55,13 +55,17 @@ to the end of this list. - @b Description: this callout is executed when the server has completed its (re)configuration. The server provides received and parsed configuration - structures to the hook library. It also provides a pointer to the IOService - object which is used by the server to run asynchronous operations. The hooks - libraries can use this IOService object to schedule asynchronous tasks which - are triggered by the DHCP server's main loop. The hook library should hold the - provided pointer until the library is unloaded. The NetworkState object - provides access to the DHCP service state of the server and allows for - enabling and disabling the DHCP service from the hooks libraries. + structures to the hook library. + If the library uses any IO operations, it should create a local IOService + object and register it to the main IOService which is also provided. This way + the local IOService is used by the server to run asynchronous operations. The + hooks library can use the local IOService object to schedule asynchronous + tasks which are triggered by the DHCP server's main loop. The hook library + should hold the provided pointer until the library is unloaded at which stage + it must unregister the local IOService. + The NetworkState object provides access to the DHCP service state of the + server and allows for enabling and disabling the DHCP service from the hooks + libraries. - Next step status: If any callout sets the status to DROP, the server will interrupt the reconfiguration process. The hook callout is expected to diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index db0c632be8..dd242cd0a5 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -706,6 +706,7 @@ Dhcpv4Srv::~Dhcpv4Srv() { } LOG_ERROR(dhcp4_logger, DHCP4_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg); } + getIOService()->clearExternalIOServices(); io_service_->stop(); io_service_->restart(); try { @@ -1132,6 +1133,7 @@ Dhcpv4Srv::run() { #endif // ENABLE_AFL try { runOne(); + getIOService()->pollExternalIOServices(); getIOService()->poll(); } catch (const std::exception& e) { // General catch-all exception that are not caught by more specific diff --git a/src/bin/dhcp4/tests/callout_library_4.cc b/src/bin/dhcp4/tests/callout_library_4.cc index f7b5869bfa..e9b55d85ad 100644 --- a/src/bin/dhcp4/tests/callout_library_4.cc +++ b/src/bin/dhcp4/tests/callout_library_4.cc @@ -31,6 +31,9 @@ void start_service(void) { isc_throw(isc::Unexpected, "start service failed"); }; +IOServicePtr io_service; +IOServicePtr main_io_service; + } // end anonymous // Functions accessed by the hooks framework use C linkage to avoid the name @@ -40,6 +43,7 @@ extern "C" { int do_load_impl(LibraryHandle& handle) { + io_service.reset(new IOService()); // Determine if this callout is configured to fail. isc::dhcp::SrvConfigPtr config; isc::data::ConstElementPtr const& parameters(handle.getParameters()); @@ -51,9 +55,17 @@ do_load_impl(LibraryHandle& handle) { return (0); } +int +do_unload_impl() { + if (main_io_service) { + main_io_service->unregisterExternalIOService(io_service); + } + return (0); +} + int (*do_load)(LibraryHandle& handle) = do_load_impl; -int (*do_unload)(); +int (*do_unload)() = do_unload_impl; /// @brief Callout which appends library number and provided arguments to /// the marker file for dhcp4_srv_configured callout. @@ -79,13 +91,13 @@ dhcp4_srv_configured(CalloutHandle& handle) { // Get the IO context to post start_service on it. std::string error(""); - IOServicePtr io_context; try { - handle.getArgument("io_context", io_context); - if (!io_context) { + handle.getArgument("io_context", main_io_service); + if (!main_io_service) { error = "null io_context"; } - io_context->post(start_service); + main_io_service->registerExternalIOService(io_service); + io_service->post(start_service); } catch (const std::exception& ex) { error = "no io_context in arguments"; } diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc index 66717ed513..bfea49d256 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc @@ -244,6 +244,7 @@ ControlledDhcpv6Srv::commandLibReloadHandler(const string&, ConstElementPtr) { HookLibsCollection loaded = HooksManager::getLibraryInfo(); HooksManager::prepareUnloadLibraries(); static_cast(HooksManager::unloadLibraries()); + getIOService()->clearExternalIOServices(); bool multi_threading_enabled = true; uint32_t thread_count = 0; uint32_t queue_size = 0; @@ -454,7 +455,7 @@ ControlledDhcpv6Srv::commandConfigSetHandler(const string&, /// Let postponed hook initializations to run. try { - getIOService()->poll(); + getIOService()->pollExternalIOServices(); } catch (const std::exception& ex) { std::ostringstream err; err << "Error initializing hooks: " diff --git a/src/bin/dhcp6/dhcp6_hooks.dox b/src/bin/dhcp6/dhcp6_hooks.dox index a8bc84acb7..7c7e5dfa53 100644 --- a/src/bin/dhcp6/dhcp6_hooks.dox +++ b/src/bin/dhcp6/dhcp6_hooks.dox @@ -55,14 +55,17 @@ to the end of this list. - @b Description: this callout is executed when the server has completed its (re)configuration. The server provides received and parsed configuration - structures to the hook library. It also provides a pointer to the IOService - object which is used by the server to run asynchronous operations. The hooks - libraries can use this IOService object to schedule asynchronous tasks which - are triggered by the DHCP server's main loop. The hook library should hold the - provided pointer until the library is unloaded. The NetworkState object - provides access to the DHCP service state of the server and allows for - enabling and disabling the DHCP service from the hooks libraries. - + structures to the hook library. + If the library uses any IO operations, it should create a local IOService + object and register it to the main IOService which is also provided. This way + the local IOService is used by the server to run asynchronous operations. The + hooks library can use the local IOService object to schedule asynchronous + tasks which are triggered by the DHCP server's main loop. The hook library + should hold the provided pointer until the library is unloaded at which stage + it must unregister the local IOService. + The NetworkState object provides access to the DHCP service state of the + server and allows for enabling and disabling the DHCP service from the hooks + libraries. - Next step status: If any callout sets the status to DROP, the server will interrupt the reconfiguration process. The hook callout is expected to diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index a0facd7923..0f59bc4481 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -302,6 +302,7 @@ Dhcpv6Srv::~Dhcpv6Srv() { } LOG_ERROR(dhcp6_logger, DHCP6_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg); } + getIOService()->clearExternalIOServices(); io_service_->stop(); io_service_->restart(); try { @@ -613,6 +614,7 @@ Dhcpv6Srv::run() { #endif // ENABLE_AFL try { runOne(); + getIOService()->pollExternalIOServices(); getIOService()->poll(); } catch (const std::exception& e) { // General catch-all standard exceptions that are not caught by more diff --git a/src/bin/dhcp6/tests/callout_library_4.cc b/src/bin/dhcp6/tests/callout_library_4.cc index 3036124c87..0739268fc1 100644 --- a/src/bin/dhcp6/tests/callout_library_4.cc +++ b/src/bin/dhcp6/tests/callout_library_4.cc @@ -31,6 +31,9 @@ void start_service(void) { isc_throw(isc::Unexpected, "start service failed"); }; +IOServicePtr io_service; +IOServicePtr main_io_service; + } // end anonymous // Functions accessed by the hooks framework use C linkage to avoid the name @@ -40,6 +43,7 @@ extern "C" { int do_load_impl(LibraryHandle& handle) { + io_service.reset(new IOService()); // Determine if this callout is configured to fail. isc::dhcp::SrvConfigPtr config; isc::data::ConstElementPtr const& parameters(handle.getParameters()); @@ -51,9 +55,17 @@ do_load_impl(LibraryHandle& handle) { return (0); } +int +do_unload_impl() { + if (main_io_service) { + main_io_service->unregisterExternalIOService(io_service); + } + return (0); +} + int (*do_load)(LibraryHandle& handle) = do_load_impl; -int (*do_unload)(); +int (*do_unload)() = do_unload_impl; /// @brief Callout which appends library number and provided arguments to /// the marker file for dhcp6_srv_configured callout. @@ -79,13 +91,13 @@ dhcp6_srv_configured(CalloutHandle& handle) { // Get the IO context to post start_service on it. std::string error(""); - IOServicePtr io_context; try { - handle.getArgument("io_context", io_context); - if (!io_context) { + handle.getArgument("io_context", main_io_service); + if (!main_io_service) { error = "null io_context"; } - io_context->post(start_service); + main_io_service->registerExternalIOService(io_service); + io_service->post(start_service); } catch (const std::exception& ex) { error = "no io_context in arguments"; } diff --git a/src/bin/netconf/netconf_process.cc b/src/bin/netconf/netconf_process.cc index c0f9b23a16..0b3dcb0a36 100644 --- a/src/bin/netconf/netconf_process.cc +++ b/src/bin/netconf/netconf_process.cc @@ -65,6 +65,7 @@ NetconfProcess::run() { size_t NetconfProcess::runIO() { + getIOService()->pollExternalIOServices(); size_t cnt = getIOService()->poll(); if (!cnt) { cnt = getIOService()->runOne(); @@ -85,6 +86,17 @@ NetconfProcess::configure(isc::data::ConstElementPtr config_set, getCfgMgr()->simpleParseConfig(config_set, check_only); int rcode = 0; config::parseAnswer(rcode, answer); + + /// Let postponed hook initializations to run. + try { + getIOService()->pollExternalIOServices(); + } catch (const std::exception& ex) { + std::ostringstream err; + err << "Error initializing hooks: " + << ex.what(); + return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str())); + } + return (answer); } diff --git a/src/hooks/dhcp/bootp/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/bootp/libloadtests/load_unload_unittests.cc index 53c7f95827..79ad89ea08 100644 --- a/src/hooks/dhcp/bootp/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/bootp/libloadtests/load_unload_unittests.cc @@ -12,12 +12,8 @@ #include -#include -#include -#include -#include +#include #include -#include #include #include diff --git a/src/hooks/dhcp/flex_option/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/flex_option/libloadtests/load_unload_unittests.cc index c786b86854..bffcbf83ae 100644 --- a/src/hooks/dhcp/flex_option/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/flex_option/libloadtests/load_unload_unittests.cc @@ -12,11 +12,8 @@ #include -#include -#include -#include -#include -#include +#include +#include #include #include diff --git a/src/hooks/dhcp/high_availability/ha.dox b/src/hooks/dhcp/high_availability/ha.dox index e63eefd6bd..cb16c0b4a7 100644 --- a/src/hooks/dhcp/high_availability/ha.dox +++ b/src/hooks/dhcp/high_availability/ha.dox @@ -142,6 +142,9 @@ have been introduced. These hook points are used by the DHCPv4 and the DHCPv6 servers respectively, to pass the instance of the IOService (via "io_context" argument) to the hooks libraries which require to schedule asynchronous tasks. +The hook's IOService object must be registered on the server's main IOService by +calling registerExternalIOService and must unregister it on "unload" hook point +by calling unregisterExternalIOService. It is also worth to note that the blocking reception of the DHCP packets may cause up to 1 second delays in the asynchronous operations. This is diff --git a/src/hooks/dhcp/high_availability/ha_callouts.cc b/src/hooks/dhcp/high_availability/ha_callouts.cc index b0a1426301..200efd0f6b 100644 --- a/src/hooks/dhcp/high_availability/ha_callouts.cc +++ b/src/hooks/dhcp/high_availability/ha_callouts.cc @@ -46,9 +46,8 @@ extern "C" { /// @param handle callout handle. int dhcp4_srv_configured(CalloutHandle& handle) { try { - isc::asiolink::IOServicePtr io_service; - handle.getArgument("io_context", io_service); - if (!io_service) { + handle.getArgument("io_context", impl->getMainIOService()); + if (!impl->getMainIOService()) { // Should not happen! handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); const string error("Error: io_context is null"); @@ -57,7 +56,8 @@ int dhcp4_srv_configured(CalloutHandle& handle) { } isc::dhcp::NetworkStatePtr network_state; handle.getArgument("network_state", network_state); - impl->startServices(io_service, network_state, HAServerType::DHCPv4); + impl->startServices(network_state, HAServerType::DHCPv4); + impl->getMainIOService()->registerExternalIOService(impl->getIOService()); } catch (const std::exception& ex) { LOG_ERROR(ha_logger, HA_DHCP4_START_SERVICE_FAILED) @@ -164,9 +164,8 @@ int lease4_server_decline(CalloutHandle& handle) { /// @param handle callout handle. int dhcp6_srv_configured(CalloutHandle& handle) { try { - isc::asiolink::IOServicePtr io_service; - handle.getArgument("io_context", io_service); - if (!io_service) { + handle.getArgument("io_context", impl->getMainIOService()); + if (!impl->getMainIOService()) { // Should not happen! handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); const string error("Error: io_context is null"); @@ -175,7 +174,8 @@ int dhcp6_srv_configured(CalloutHandle& handle) { } isc::dhcp::NetworkStatePtr network_state; handle.getArgument("network_state", network_state); - impl->startServices(io_service, network_state, HAServerType::DHCPv6); + impl->startServices(network_state, HAServerType::DHCPv6); + impl->getMainIOService()->registerExternalIOService(impl->getIOService()); } catch (const std::exception& ex) { LOG_ERROR(ha_logger, HA_DHCP6_START_SERVICE_FAILED) @@ -442,6 +442,17 @@ int load(LibraryHandle& handle) { /// /// @return 0 if deregistration was successful, 1 otherwise int unload() { + if (impl) { + if (impl->getMainIOService()) { + impl->getMainIOService()->unregisterExternalIOService(impl->getIOService()); + } + impl->getIOService()->stop(); + impl->getIOService()->restart(); + try { + impl->getIOService()->poll(); + } catch (...) { + } + } impl.reset(); LOG_INFO(ha_logger, HA_DEINIT_OK); return (0); diff --git a/src/hooks/dhcp/high_availability/ha_impl.cc b/src/hooks/dhcp/high_availability/ha_impl.cc index f0e2179328..127ceb9545 100644 --- a/src/hooks/dhcp/high_availability/ha_impl.cc +++ b/src/hooks/dhcp/high_availability/ha_impl.cc @@ -31,7 +31,7 @@ namespace isc { namespace ha { HAImpl::HAImpl() - : config_(), services_(new HAServiceMapper()) { + : io_service_(new IOService()), config_(), services_(new HAServiceMapper()) { } void @@ -40,13 +40,12 @@ HAImpl::configure(const ConstElementPtr& input_config) { } void -HAImpl::startServices(const IOServicePtr& io_service, - const NetworkStatePtr& network_state, +HAImpl::startServices(const NetworkStatePtr& network_state, const HAServerType& server_type) { auto configs = config_->getAll(); for (auto id = 0; id < configs.size(); ++id) { // Create the HA service and crank up the state machine. - auto service = boost::make_shared(id, io_service, network_state, + auto service = boost::make_shared(id, io_service_, network_state, configs[id], server_type); for (auto const& peer_config : configs[id]->getAllServersConfig()) { services_->map(peer_config.first, service); @@ -54,7 +53,7 @@ HAImpl::startServices(const IOServicePtr& io_service, } // Schedule a start of the services. This ensures we begin after // the dust has settled and Kea MT mode has been firmly established. - io_service->post([&]() { + io_service_->post([&]() { for (auto const& service : services_->getAll()) { service->startClientAndListener(); } diff --git a/src/hooks/dhcp/high_availability/ha_impl.h b/src/hooks/dhcp/high_availability/ha_impl.h index 00f8a901fd..041ade8c82 100644 --- a/src/hooks/dhcp/high_availability/ha_impl.h +++ b/src/hooks/dhcp/high_availability/ha_impl.h @@ -45,13 +45,11 @@ public: /// The caller must ensure that the HA configuration is valid before /// calling this function. /// - /// @param io_service IO service object provided by the DHCP server. /// @param network_state pointer to the object holding a state of the /// DHCP service (enabled/disabled). /// @param server_type DHCP server type for which the HA service should /// be created. - void startServices(const asiolink::IOServicePtr& io_service, - const dhcp::NetworkStatePtr& network_state, + void startServices(const dhcp::NetworkStatePtr& network_state, const HAServerType& server_type); /// @brief Destructor. @@ -223,8 +221,42 @@ public: HAServicePtr getHAServiceByServerName(const std::string& command_name, data::ConstElementPtr args) const; + /// @brief Get the hook I/O service. + /// + /// @return the hook I/O service. + isc::asiolink::IOServicePtr& getIOService() { + return (io_service_); + } + + /// @brief Set the hook I/O service. + /// + /// @param io_service the hook I/O service. + void setIOService(isc::asiolink::IOServicePtr io_service) { + io_service_ = io_service; + } + + /// @brief Get the main I/O service. + /// + /// @return the main I/O service. + isc::asiolink::IOServicePtr& getMainIOService() { + return (main_io_service_); + } + + /// @brief Set the main I/O service. + /// + /// @param io_service the main I/O service. + void setMainIOService(isc::asiolink::IOServicePtr io_service) { + main_io_service_ = io_service; + } + protected: + /// @brief The hook I/O service. + isc::asiolink::IOServicePtr io_service_; + + /// @brief The main I/O service. + isc::asiolink::IOServicePtr main_io_service_; + /// @brief Holds parsed configuration. HAConfigMapperPtr config_; diff --git a/src/hooks/dhcp/high_availability/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/high_availability/libloadtests/load_unload_unittests.cc index 00197a28b3..b217c5cd3f 100644 --- a/src/hooks/dhcp/high_availability/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/high_availability/libloadtests/load_unload_unittests.cc @@ -12,11 +12,8 @@ #include -#include -#include -#include -#include -#include +#include +#include #include #include 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 e207450465..122de668df 100644 --- a/src/hooks/dhcp/high_availability/tests/ha_impl_unittest.cc +++ b/src/hooks/dhcp/high_availability/tests/ha_impl_unittest.cc @@ -127,11 +127,12 @@ public: const std::string& expected_response) { io_service_.reset(new IOService()); ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON(ha_sync_command); @@ -174,13 +175,14 @@ public: TEST_F(HAImplTest, startServices) { // Valid configuration must be provided prior to starting the service. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // Make sure that the HA service has been created for the requested @@ -193,13 +195,14 @@ TEST_F(HAImplTest, startServices) { TEST_F(HAImplTest, startServices6) { // Valid configuration must be provided prior to starting the service. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // Make sure that the HA service has been created for the requested @@ -216,11 +219,12 @@ TEST_F(HAImplTest, buffer4Receive) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // Initially the HA service is in the waiting state and serves no scopes. @@ -329,11 +333,12 @@ TEST_F(HAImplTest, subnet4Select) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // The hub is a standby server and by default serves no scopes. Explicitly @@ -386,11 +391,12 @@ TEST_F(HAImplTest, subnet4SelectSharedNetwork) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // The hub is a standby server and by default serves no scopes. Explicitly @@ -446,11 +452,12 @@ TEST_F(HAImplTest, subnet4SelectSingleRelationship) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // Create callout handle to be used for passing arguments to the @@ -487,11 +494,12 @@ TEST_F(HAImplTest, subnet4SelectDropNoServerName) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // The hub is a standby server and by default serves no scopes. Explicitly @@ -532,11 +540,12 @@ TEST_F(HAImplTest, subnet4SelectDropInvalidServerNameType) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // The hub is a standby server and by default serves no scopes. Explicitly @@ -581,11 +590,12 @@ TEST_F(HAImplTest, subnet4SelectDropNotInScope) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // This server serves server1/server2 scopes but not server3/server4 scopes. @@ -633,11 +643,12 @@ TEST_F(HAImplTest, subnet4SelectNoSubnet) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); test_ha_impl_->services_->get("server2")->serveFailoverScopes(); @@ -679,11 +690,12 @@ TEST_F(HAImplTest, buffer6Receive) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // Initially the HA service is in the waiting state and serves no scopes. @@ -769,11 +781,12 @@ TEST_F(HAImplTest, subnet6Select) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // The hub is a standby server and by default serves no scopes. Explicitly @@ -823,11 +836,12 @@ TEST_F(HAImplTest, subnet6SelectSharedNetwork) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // The hub is a standby server and by default serves no scopes. Explicitly @@ -883,11 +897,12 @@ TEST_F(HAImplTest, subnet6SelectSingleRelationship) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // Create callout handle to be used for passing arguments to the @@ -924,11 +939,12 @@ TEST_F(HAImplTest, subnet6SelectDropNoServerName) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // The hub is a standby server and by default serves no scopes. Explicitly @@ -969,11 +985,12 @@ TEST_F(HAImplTest, subnet6SelectDropInvalidServerNameType) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // The hub is a standby server and by default serves no scopes. Explicitly @@ -1018,11 +1035,12 @@ TEST_F(HAImplTest, subnet6SelectDropNotInScope) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // This server serves server1/server2 scopes but not server3/server4 scopes. @@ -1070,11 +1088,12 @@ TEST_F(HAImplTest, subnet6SelectNoSubnet) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); test_ha_impl_->services_->get("server2")->serveFailoverScopes(); @@ -1112,11 +1131,12 @@ TEST_F(HAImplTest, subnet6SelectNoSubnet) { TEST_F(HAImplTest, leases4Committed) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // Make sure we wait for the acks from the backup server to be able to @@ -1198,11 +1218,12 @@ TEST_F(HAImplTest, leases4Committed) { TEST_F(HAImplTest, leases4CommittedMultipleRelationships) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // By enabling this setting we ensure that the lease updates are always @@ -1254,11 +1275,12 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationships) { TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsNoServerName) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // By enabling this setting we ensure that the lease updates are always @@ -1306,11 +1328,12 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsNoServerName) { TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsInvalidServerName) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // By enabling this setting we ensure that the lease updates are always @@ -1360,11 +1383,12 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsInvalidServerName) { TEST_F(HAImplTest, leases6Committed) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // Make sure we wait for the acks from the backup server to be able to @@ -1445,11 +1469,12 @@ TEST_F(HAImplTest, leases6Committed) { TEST_F(HAImplTest, leases6CommittedMultipleRelationships) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // By enabling this setting we ensure that the lease updates are always @@ -1500,11 +1525,12 @@ TEST_F(HAImplTest, leases6CommittedMultipleRelationships) { TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsNoServerName) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // By enabling this setting we ensure that the lease updates are always @@ -1551,11 +1577,12 @@ TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsNoServerName) { TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsInvalidServerName) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv6)); // By enabling this setting we ensure that the lease updates are always @@ -1682,11 +1709,12 @@ TEST_F(HAImplTest, synchronizeHandler) { // Tests ha-continue command handler with a specified server name. TEST_F(HAImplTest, continueHandler) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON("{" @@ -1711,11 +1739,12 @@ TEST_F(HAImplTest, continueHandler) { // Tests ha-continue command handler without a server name. TEST_F(HAImplTest, continueHandlerWithNoServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON("{ \"command\": \"ha-continue\" }"); @@ -1735,11 +1764,12 @@ TEST_F(HAImplTest, continueHandlerWithNoServerName) { // Tests ha-continue command handler with wrong server name. TEST_F(HAImplTest, continueHandlerWithWrongServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON("{" @@ -1764,11 +1794,12 @@ TEST_F(HAImplTest, continueHandlerWithWrongServerName) { // Tests status-get command processed handler. TEST_F(HAImplTest, statusGet) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); std::string name = "status-get"; @@ -1825,12 +1856,13 @@ TEST_F(HAImplTest, statusGet) { // Tests status-get command processed handler for backup server. TEST_F(HAImplTest, statusGetBackupServer) { test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); std::string name = "status-get"; @@ -1875,11 +1907,12 @@ TEST_F(HAImplTest, statusGetBackupServer) { // passive-backup state. TEST_F(HAImplTest, statusGetPassiveBackup) { test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); std::string name = "status-get"; @@ -1924,11 +1957,12 @@ TEST_F(HAImplTest, statusGetPassiveBackup) { // hub-and-spoke mode. TEST_F(HAImplTest, statusGetHubAndSpoke) { test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); std::string name = "status-get"; @@ -2009,11 +2043,12 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) { // Test ha-maintenance-notify command handler with server name. TEST_F(HAImplTest, maintenanceNotify) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2041,11 +2076,12 @@ TEST_F(HAImplTest, maintenanceNotify) { // Test ha-maintenance-notify command handler without server name. TEST_F(HAImplTest, maintenanceNotifyNoServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2072,11 +2108,12 @@ TEST_F(HAImplTest, maintenanceNotifyNoServerName) { // Test ha-maintenance-notify command handler without server name. TEST_F(HAImplTest, maintenanceNotifyBadServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2104,11 +2141,12 @@ TEST_F(HAImplTest, maintenanceNotifyBadServerName) { // Test ha-reset command handler with a specified server name. TEST_F(HAImplTest, haReset) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2135,11 +2173,12 @@ TEST_F(HAImplTest, haReset) { // Test ha-reset command handler without a specified server name. TEST_F(HAImplTest, haResetNoServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2163,11 +2202,12 @@ TEST_F(HAImplTest, haResetNoServerName) { // Test ha-reset command handler with a wrong server name. TEST_F(HAImplTest, haResetBadServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2194,11 +2234,12 @@ TEST_F(HAImplTest, haResetBadServerName) { // Test ha-heartbeat command handler with a specified server name. TEST_F(HAImplTest, haHeartbeat) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2225,11 +2266,12 @@ TEST_F(HAImplTest, haHeartbeat) { // Test ha-heartbeat command handler without a specified server name. TEST_F(HAImplTest, haHeartbeatNoServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2253,11 +2295,12 @@ TEST_F(HAImplTest, haHeartbeatNoServerName) { // Test ha-heartbeat command handler with a wrong server name. TEST_F(HAImplTest, haHeartbeatBadServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2284,11 +2327,12 @@ TEST_F(HAImplTest, haHeartbeatBadServerName) { // Test ha-sync-complete-notify command handler with a specified server name. TEST_F(HAImplTest, haSyncCompleteNotify) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2316,11 +2360,12 @@ TEST_F(HAImplTest, haSyncCompleteNotify) { // Test ha-sync-complete-notify command handler without a specified server name. TEST_F(HAImplTest, haSyncCompleteNotifyNoServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2345,11 +2390,12 @@ TEST_F(HAImplTest, haSyncCompleteNotifyNoServerName) { // Test ha-sync-complete-notify command handler with a wrong server name. TEST_F(HAImplTest, haSyncCompleteNotifyBadServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2376,11 +2422,12 @@ TEST_F(HAImplTest, haSyncCompleteNotifyBadServerName) { // Test ha-scopes command handler with a specified server name. TEST_F(HAImplTest, haScopes) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2408,11 +2455,12 @@ TEST_F(HAImplTest, haScopes) { // Test ha-scopes command handler without a specified server name. TEST_F(HAImplTest, haScopesNoServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2439,11 +2487,12 @@ TEST_F(HAImplTest, haScopesNoServerName) { // Test ha-scopes command handler with a wrong server name. TEST_F(HAImplTest, haScopesBadServerName) { ha_impl_.reset(new HAImpl()); + ha_impl_->setIOService(io_service_); 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, + ASSERT_NO_THROW(ha_impl_->startServices(network_state, HAServerType::DHCPv4)); ConstElementPtr command = Element::fromJSON( @@ -2472,11 +2521,12 @@ TEST_F(HAImplTest, haScopesBadServerName) { TEST_F(HAImplTest, lease4ServerDecline) { // Create implementation object and configure it. test_ha_impl_.reset(new TestHAImpl()); + test_ha_impl_->setIOService(io_service_); 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(test_ha_impl_->startServices(io_service_, network_state, + ASSERT_NO_THROW(test_ha_impl_->startServices(network_state, HAServerType::DHCPv4)); // Make sure we wait for the acks from the backup server to be able to diff --git a/src/hooks/dhcp/lease_cmds/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/lease_cmds/libloadtests/load_unload_unittests.cc index 926dcf4397..0d0bab6c58 100644 --- a/src/hooks/dhcp/lease_cmds/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/lease_cmds/libloadtests/load_unload_unittests.cc @@ -12,12 +12,8 @@ #include -#include -#include -#include -#include +#include #include -#include #include #include diff --git a/src/hooks/dhcp/mysql_cb/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/mysql_cb/libloadtests/load_unload_unittests.cc index b8b73589db..8b27e5153d 100644 --- a/src/hooks/dhcp/mysql_cb/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/mysql_cb/libloadtests/load_unload_unittests.cc @@ -12,12 +12,8 @@ #include -#include -#include -#include -#include +#include #include -#include #include #include diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_callouts.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_callouts.cc index c047f421f0..2186dbf312 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_callouts.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_callouts.cc @@ -22,6 +22,7 @@ #include #include +using namespace isc::asiolink; using namespace isc::cb; using namespace isc::dhcp; using namespace isc::hooks; @@ -67,15 +68,15 @@ int load(LibraryHandle& /* handle */) { /// @param handle callout handle passed to the callout. /// @return 0 on success, 1 otherwise. int dhcp4_srv_configured(CalloutHandle& handle) { - isc::asiolink::IOServicePtr io_service; - handle.getArgument("io_context", io_service); - if (!io_service) { + handle.getArgument("io_context", isc::dhcp::MySqlConfigBackendImpl::getMainIOService()); + if (!isc::dhcp::MySqlConfigBackendImpl::getMainIOService()) { const string error("Error: io_context is null"); handle.setArgument("error", error); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); return (1); } - isc::dhcp::MySqlConfigBackendImpl::setIOService(io_service); + isc::dhcp::MySqlConfigBackendImpl::getIOService().reset(new IOService()); + isc::dhcp::MySqlConfigBackendImpl::getMainIOService()->registerExternalIOService(isc::dhcp::MySqlConfigBackendImpl::getIOService()); return (0); } @@ -86,15 +87,15 @@ int dhcp4_srv_configured(CalloutHandle& handle) { /// @param handle callout handle passed to the callout. /// @return 0 on success, 1 otherwise. int dhcp6_srv_configured(CalloutHandle& handle) { - isc::asiolink::IOServicePtr io_service; - handle.getArgument("io_context", io_service); - if (!io_service) { + handle.getArgument("io_context", isc::dhcp::MySqlConfigBackendImpl::getMainIOService()); + if (!isc::dhcp::MySqlConfigBackendImpl::getMainIOService()) { const string error("Error: io_context is null"); handle.setArgument("error", error); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); return (1); } - isc::dhcp::MySqlConfigBackendImpl::setIOService(io_service); + isc::dhcp::MySqlConfigBackendImpl::getIOService().reset(new IOService()); + isc::dhcp::MySqlConfigBackendImpl::getMainIOService()->registerExternalIOService(isc::dhcp::MySqlConfigBackendImpl::getIOService()); return (0); } @@ -106,6 +107,17 @@ int unload() { // Unregister the factories and remove MySQL backends isc::dhcp::MySqlConfigBackendDHCPv4::unregisterBackendType(); isc::dhcp::MySqlConfigBackendDHCPv6::unregisterBackendType(); + if (isc::dhcp::MySqlConfigBackendImpl::getMainIOService()) { + isc::dhcp::MySqlConfigBackendImpl::getMainIOService()->unregisterExternalIOService(isc::dhcp::MySqlConfigBackendImpl::getIOService()); + } + if (isc::dhcp::MySqlConfigBackendImpl::getIOService()) { + isc::dhcp::MySqlConfigBackendImpl::getIOService()->stop(); + isc::dhcp::MySqlConfigBackendImpl::getIOService()->restart(); + try { + isc::dhcp::MySqlConfigBackendImpl::getIOService()->poll(); + } catch (...) { + } + } return (0); } diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc index 9e8648a431..390bf9cd2f 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc @@ -29,7 +29,8 @@ using namespace isc::util; namespace isc { namespace dhcp { -isc::asiolink::IOServicePtr MySqlConfigBackendImpl::io_service_ = isc::asiolink::IOServicePtr(); +isc::asiolink::IOServicePtr MySqlConfigBackendImpl::io_service_; +isc::asiolink::IOServicePtr MySqlConfigBackendImpl::main_io_service_; MySqlConfigBackendImpl:: ScopedAuditRevision::ScopedAuditRevision(MySqlConfigBackendImpl* impl, @@ -86,6 +87,11 @@ MySqlConfigBackendImpl(const std::string& space, } } +MySqlConfigBackendImpl::~MySqlConfigBackendImpl() { + /// nothing to do there. The conn_ connection will be deleted and its dtor + /// will take care of releasing the compiled statements and similar. +} + MySqlBindingPtr MySqlConfigBackendImpl::createBinding(const Triplet& triplet) { if (triplet.unspecified()) { diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h index dcf3d29d1f..9931c8a551 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h @@ -115,7 +115,7 @@ public: const db::DbCallback db_reconnect_callback); /// @brief Destructor. - virtual ~MySqlConfigBackendImpl() {}; + virtual ~MySqlConfigBackendImpl(); /// @brief Creates MySQL binding from an @c Optional of integer type. /// @@ -836,16 +836,32 @@ public: return (parameters_); } - /// @brief Sets IO service to be used by the MySQL config backend. + /// @brief Get the hook I/O service. /// - /// @param IOService object, used for all ASIO operations. - static void setIOService(const isc::asiolink::IOServicePtr& io_service) { + /// @return the hook I/O service. + static isc::asiolink::IOServicePtr& getIOService() { + return (io_service_); + } + + /// @brief Set the hook I/O service. + /// + /// @param io_service the hook I/O service. + static void setIOService(isc::asiolink::IOServicePtr io_service) { io_service_ = io_service; } - /// @brief Returns pointer to the IO service. - static isc::asiolink::IOServicePtr& getIOService() { - return (io_service_); + /// @brief Get the main I/O service. + /// + /// @return the main I/O service. + static isc::asiolink::IOServicePtr& getMainIOService() { + return (main_io_service_); + } + + /// @brief Set the main I/O service. + /// + /// @param io_service the main I/O service. + static void setMainIOService(isc::asiolink::IOServicePtr io_service) { + main_io_service_ = io_service; } /// @brief Represents connection to the MySQL database. @@ -864,8 +880,11 @@ private: /// @brief Connection parameters isc::db::DatabaseConnection::ParameterMap parameters_; - /// @brief The IOService object, used for all ASIO operations. + /// @brief The hook I/O service. static isc::asiolink::IOServicePtr io_service_; + + /// @brief The main I/O service. + static isc::asiolink::IOServicePtr main_io_service_; }; } // end of namespace isc::dhcp diff --git a/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc index 3a187cfe4e..56f1793650 100644 --- a/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/perfmon/libloadtests/load_unload_unittests.cc @@ -12,12 +12,8 @@ #include -#include -#include -#include -#include +#include #include -#include #include #include diff --git a/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc index 71d5adb330..11388463ce 100644 --- a/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/pgsql_cb/libloadtests/load_unload_unittests.cc @@ -12,12 +12,8 @@ #include -#include -#include -#include -#include +#include #include -#include #include #include diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc index 06727e1695..f824a0c59f 100644 --- a/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_callouts.cc @@ -22,6 +22,7 @@ #include #include +using namespace isc::asiolink; using namespace isc::cb; using namespace isc::dhcp; using namespace isc::hooks; @@ -67,15 +68,15 @@ int load(LibraryHandle& /* handle */) { /// @param handle callout handle passed to the callout. /// @return 0 on success, 1 otherwise. int dhcp4_srv_configured(CalloutHandle& handle) { - isc::asiolink::IOServicePtr io_service; - handle.getArgument("io_context", io_service); - if (!io_service) { + handle.getArgument("io_context", isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()); + if (!isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()) { const string error("Error: io_context is null"); handle.setArgument("error", error); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); return (1); } - isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service); + isc::dhcp::PgSqlConfigBackendImpl::getIOService().reset(new IOService()); + isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()->registerExternalIOService(isc::dhcp::PgSqlConfigBackendImpl::getIOService()); return (0); } @@ -86,15 +87,15 @@ int dhcp4_srv_configured(CalloutHandle& handle) { /// @param handle callout handle passed to the callout. /// @return 0 on success, 1 otherwise. int dhcp6_srv_configured(CalloutHandle& handle) { - isc::asiolink::IOServicePtr io_service; - handle.getArgument("io_context", io_service); - if (!io_service) { + handle.getArgument("io_context", isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()); + if (!isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()) { const string error("Error: io_context is null"); handle.setArgument("error", error); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); return (1); } - isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service); + isc::dhcp::PgSqlConfigBackendImpl::getIOService().reset(new IOService()); + isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()->registerExternalIOService(isc::dhcp::PgSqlConfigBackendImpl::getIOService()); return (0); } @@ -106,6 +107,17 @@ int unload() { // Unregister the factories and remove PostgreSQL backends isc::dhcp::PgSqlConfigBackendDHCPv4::unregisterBackendType(); isc::dhcp::PgSqlConfigBackendDHCPv6::unregisterBackendType(); + if (isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()) { + isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()->unregisterExternalIOService(isc::dhcp::PgSqlConfigBackendImpl::getIOService()); + } + if (isc::dhcp::PgSqlConfigBackendImpl::getIOService()) { + isc::dhcp::PgSqlConfigBackendImpl::getIOService()->stop(); + isc::dhcp::PgSqlConfigBackendImpl::getIOService()->restart(); + try { + isc::dhcp::PgSqlConfigBackendImpl::getIOService()->poll(); + } catch (...) { + } + } return (0); } diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc index 8b37468017..2104e450a1 100644 --- a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.cc @@ -28,7 +28,8 @@ using namespace isc::util; namespace isc { namespace dhcp { -isc::asiolink::IOServicePtr PgSqlConfigBackendImpl::io_service_ = isc::asiolink::IOServicePtr(); +isc::asiolink::IOServicePtr PgSqlConfigBackendImpl::io_service_; +isc::asiolink::IOServicePtr PgSqlConfigBackendImpl::main_io_service_; PgSqlTaggedStatement& PgSqlConfigBackendImpl::getStatement(size_t /* index */) const { diff --git a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h index 0e1917d4d0..a4d1d93db4 100644 --- a/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h +++ b/src/hooks/dhcp/pgsql_cb/pgsql_cb_impl.h @@ -800,18 +800,6 @@ public: return (parameters_); } - /// @brief Sets IO service to be used by the PostgreSQL config backend. - /// - /// @param IOService object, used for all ASIO operations. - static void setIOService(const isc::asiolink::IOServicePtr& io_service) { - io_service_ = io_service; - } - - /// @brief Returns pointer to the IO service. - static isc::asiolink::IOServicePtr& getIOService() { - return (io_service_); - } - /// @brief Fetches the SQL statement for a given statement index. /// /// Derivations must override the implementation. The reference @@ -872,6 +860,34 @@ public: /// @return Number of affected rows. uint64_t updateDeleteQuery(size_t index, const db::PsqlBindArray& in_bindings); + /// @brief Get the hook I/O service. + /// + /// @return the hook I/O service. + static isc::asiolink::IOServicePtr& getIOService() { + return (io_service_); + } + + /// @brief Set the hook I/O service. + /// + /// @param io_service the hook I/O service. + static void setIOService(isc::asiolink::IOServicePtr io_service) { + io_service_ = io_service; + } + + /// @brief Get the main I/O service. + /// + /// @return the main I/O service. + static isc::asiolink::IOServicePtr& getMainIOService() { + return (main_io_service_); + } + + /// @brief Set the main I/O service. + /// + /// @param io_service the main I/O service. + static void setMainIOService(isc::asiolink::IOServicePtr io_service) { + main_io_service_ = io_service; + } + /// @brief Represents connection to the PostgreSQL database. db::PgSqlConnection conn_; @@ -888,9 +904,12 @@ private: /// @brief Connection parameters isc::db::DatabaseConnection::ParameterMap parameters_; - /// @brief The IOService object, used for all ASIO operations. + /// @brief The hook I/O service. static isc::asiolink::IOServicePtr io_service_; + /// @brief The main I/O service. + static isc::asiolink::IOServicePtr main_io_service_; + /// @brief Statement index of the SQL statement to use for fetching /// last inserted id in a given table. size_t last_insert_id_index_; diff --git a/src/hooks/dhcp/run_script/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/run_script/libloadtests/load_unload_unittests.cc index 32bf1e5e25..eddbbad80f 100644 --- a/src/hooks/dhcp/run_script/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/run_script/libloadtests/load_unload_unittests.cc @@ -12,11 +12,8 @@ #include -#include -#include -#include -#include -#include +#include +#include #include #include diff --git a/src/hooks/dhcp/run_script/run_script.cc b/src/hooks/dhcp/run_script/run_script.cc index e82c56897d..54ddb4139b 100644 --- a/src/hooks/dhcp/run_script/run_script.cc +++ b/src/hooks/dhcp/run_script/run_script.cc @@ -19,8 +19,9 @@ namespace isc { namespace run_script { IOServicePtr RunScriptImpl::io_service_; +IOServicePtr RunScriptImpl::main_io_service_; -RunScriptImpl::RunScriptImpl() : name_(), sync_(false) { +RunScriptImpl::RunScriptImpl() : io_context_(new IOService()), name_(), sync_(false) { } void diff --git a/src/hooks/dhcp/run_script/run_script.h b/src/hooks/dhcp/run_script/run_script.h index 8d9f63c961..dc9f9b8a42 100644 --- a/src/hooks/dhcp/run_script/run_script.h +++ b/src/hooks/dhcp/run_script/run_script.h @@ -30,20 +30,6 @@ public: /// @brief Destructor. ~RunScriptImpl() = default; - /// @brief Sets IO service to be used by the @ref ProcessSpawn instance. - /// - /// @param io_service The IOService object, used for all ASIO operations. - static void setIOService(const isc::asiolink::IOServicePtr& io_service) { - io_service_ = io_service; - } - - /// @brief Gets IO service to be used by the @ref ProcessSpawn instance. - /// - /// @return The IOService object, used for all ASIO operations. - static isc::asiolink::IOServicePtr getIOService() { - return (io_service_); - } - /// @brief Extract boolean data and append to environment. /// /// @param value The value to be exported to target script environment. @@ -256,7 +242,53 @@ public: /// @brief This function parses and applies configuration parameters. void configure(isc::hooks::LibraryHandle& handle); + /// @brief Get the hook I/O service. + /// + /// @return the hook I/O service. + isc::asiolink::IOServicePtr& getIOContext() { + return (io_context_); + } + + /// @brief Set the hook I/O service. + /// + /// @param io_service the hook I/O service. + void setIOContext(isc::asiolink::IOServicePtr io_service) { + io_context_ = io_service; + } + + /// @brief Get the hook I/O service. + /// + /// @return the hook I/O service. + static isc::asiolink::IOServicePtr& getIOService() { + return (io_service_); + } + + /// @brief Set the hook I/O service. + /// + /// @param io_service the hook I/O service. + static void setIOService(isc::asiolink::IOServicePtr io_service) { + io_service_ = io_service; + } + + /// @brief Get the main I/O service. + /// + /// @return the main I/O service. + static isc::asiolink::IOServicePtr& getMainIOService() { + return (main_io_service_); + } + + /// @brief Set the main I/O service. + /// + /// @param io_service the main I/O service. + static void setMainIOService(isc::asiolink::IOServicePtr io_service) { + main_io_service_ = io_service; + } + private: + + /// @brief The IOService object, used for all ASIO operations. + isc::asiolink::IOServicePtr io_context_; + /// @brief Script name. std::string name_; @@ -267,8 +299,11 @@ private: /// started. bool sync_; - /// @brief The IOService object, used for all ASIO operations. + /// @brief The hook I/O service. static isc::asiolink::IOServicePtr io_service_; + + /// @brief The main I/O service. + static isc::asiolink::IOServicePtr main_io_service_; }; /// @brief The type of shared pointers to Run Script implementations. diff --git a/src/hooks/dhcp/run_script/run_script_callouts.cc b/src/hooks/dhcp/run_script/run_script_callouts.cc index 09717b5127..22ee765c9a 100644 --- a/src/hooks/dhcp/run_script/run_script_callouts.cc +++ b/src/hooks/dhcp/run_script/run_script_callouts.cc @@ -80,7 +80,18 @@ int load(LibraryHandle& handle) { /// /// @return always 0. int unload() { + if (RunScriptImpl::getMainIOService()) { + RunScriptImpl::getMainIOService()->unregisterExternalIOService(impl->getIOContext()); + } impl.reset(); + if (RunScriptImpl::getIOService()) { + RunScriptImpl::getIOService()->stop(); + RunScriptImpl::getIOService()->restart(); + try { + RunScriptImpl::getIOService()->poll(); + } catch (...) { + } + } RunScriptImpl::setIOService(IOServicePtr()); LOG_INFO(run_script_logger, RUN_SCRIPT_UNLOAD); return (0); @@ -91,16 +102,16 @@ int unload() { /// @param handle callout handle. int dhcp4_srv_configured(CalloutHandle& handle) { try { - isc::asiolink::IOServicePtr io_service; - handle.getArgument("io_context", io_service); - if (!io_service) { + handle.getArgument("io_context", RunScriptImpl::getMainIOService()); + if (!RunScriptImpl::getMainIOService()) { // Should not happen! handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); const string error("Error: io_context is null"); handle.setArgument("error", error); return (1); } - RunScriptImpl::setIOService(io_service); + RunScriptImpl::setIOService(impl->getIOContext()); + RunScriptImpl::getMainIOService()->registerExternalIOService(impl->getIOContext()); } catch (const exception& ex) { LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR) @@ -116,16 +127,16 @@ int dhcp4_srv_configured(CalloutHandle& handle) { /// @param handle callout handle. int dhcp6_srv_configured(CalloutHandle& handle) { try { - isc::asiolink::IOServicePtr io_service; - handle.getArgument("io_context", io_service); - if (!io_service) { + handle.getArgument("io_context", RunScriptImpl::getMainIOService()); + if (!RunScriptImpl::getMainIOService()) { // Should not happen! handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); const string error("Error: io_context is null"); handle.setArgument("error", error); return (1); } - RunScriptImpl::setIOService(io_service); + RunScriptImpl::setIOService(impl->getIOContext()); + RunScriptImpl::getMainIOService()->registerExternalIOService(impl->getIOContext()); } catch (const exception& ex) { LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR) diff --git a/src/hooks/dhcp/stat_cmds/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/stat_cmds/libloadtests/load_unload_unittests.cc index caccebaada..86444ee6a9 100644 --- a/src/hooks/dhcp/stat_cmds/libloadtests/load_unload_unittests.cc +++ b/src/hooks/dhcp/stat_cmds/libloadtests/load_unload_unittests.cc @@ -12,12 +12,8 @@ #include -#include -#include -#include -#include +#include #include -#include #include #include diff --git a/src/lib/asiolink/io_service.cc b/src/lib/asiolink/io_service.cc index 3cc6012fe2..8c42d6855f 100644 --- a/src/lib/asiolink/io_service.cc +++ b/src/lib/asiolink/io_service.cc @@ -18,98 +18,102 @@ namespace isc { namespace asiolink { class IOServiceImpl { + /// @brief Constructors and Destructor. + /// + /// @note The copy constructor and the assignment operator are + /// intentionally defined as private, making this class non-copyable. + //@{ private: IOServiceImpl(const IOService& source); IOServiceImpl& operator=(const IOService& source); public: - /// \brief The constructor + /// @brief The constructor. IOServiceImpl() : io_service_(), work_(new boost::asio::io_service::work(io_service_)) { }; - /// \brief The destructor. - ~IOServiceImpl() { - }; + /// @brief The destructor. + ~IOServiceImpl() = default; //@} - /// \brief Start the underlying event loop. + /// @brief Start the underlying event loop. /// /// This method does not return control to the caller until - /// the \c stop() method is called via some handler. + /// the @ref stop() method is called via some handler. void run() { io_service_.run(); }; - /// \brief Run the underlying event loop for a single event. + /// @brief Run the underlying event loop for a single event. /// /// This method return control to the caller as soon as the /// first handler has completed. (If no handlers are ready when /// it is run, it will block until one is.) /// - /// \return The number of handlers that were executed. + /// @return The number of handlers that were executed. size_t runOne() { return (static_cast(io_service_.run_one())); }; - /// \brief Run the underlying event loop for a ready events. + /// @brief Run the underlying event loop for a ready events. /// /// This method executes handlers for all ready events and returns. /// It will return immediately if there are no ready events. /// - /// \return The number of handlers that were executed. + /// @return The number of handlers that were executed. size_t poll() { return (static_cast(io_service_.poll())); }; - /// \brief Run the underlying event loop for a ready events. + /// @brief Run the underlying event loop for a ready events. /// /// This method executes handlers for all ready events and returns. /// It will return immediately if there are no ready events. /// - /// \return The number of handlers that were executed. + /// @return The number of handlers that were executed. size_t pollOne() { return (static_cast(io_service_.poll_one())); }; - /// \brief Stop the underlying event loop. + /// @brief Stop the underlying event loop. /// - /// This will return the control to the caller of the \c run() method. + /// This will return the control to the caller of the @ref run() method. void stop() { io_service_.stop(); } - /// \brief Indicates if the IOService has been stopped. + /// @brief Indicates if the IOService has been stopped. /// - /// \return true if the IOService has been stopped, false otherwise. + /// @return true if the IOService has been stopped, false otherwise. bool stopped() const { return (io_service_.stopped()); } - /// \brief Restarts the IOService in preparation for a subsequent \c run() invocation. + /// @brief Restarts the IOService in preparation for a subsequent @ref run() invocation. void restart() { io_service_.reset(); } - /// \brief Removes IO service work object to let it finish running + /// @brief Removes IO service work object to let it finish running /// when all handlers have been invoked. void stopWork() { work_.reset(); } - /// \brief Return the native \c io_service object used in this wrapper. + /// @brief Return the native @ref io_service object used in this wrapper. /// /// This is a short term work around to support other Kea modules - /// that share the same \c io_service with the authoritative server. + /// that share the same @ref io_service with the authoritative server. /// It will eventually be removed once the wrapper interface is /// generalized. boost::asio::io_service& getInternalIOService() { return (io_service_); } - /// \brief Post a callback on the IO service + /// @brief Post a callback on the IO service. /// - /// \param callback The callback to be run on the IO service. + /// @param callback The callback to be run on the IO service. void post(const std::function& callback) { io_service_.post(callback); } @@ -175,5 +179,25 @@ IOService::post(const std::function& callback) { return (io_impl_->post(callback)); } +void +IOService::registerExternalIOService(IOServicePtr io_service) { + external_io_services_.push_back(io_service); +} + +void +IOService::unregisterExternalIOService(IOServicePtr io_service) { + auto it = std::find(external_io_services_.begin(), external_io_services_.end(), io_service); + if (it != external_io_services_.end()) { + external_io_services_.erase(it); + } +} + +void +IOService::pollExternalIOServices() { + for (auto& io_service : external_io_services_) { + io_service->poll(); + } +} + } // namespace asiolink } // namespace isc diff --git a/src/lib/asiolink/io_service.h b/src/lib/asiolink/io_service.h index 7da1f9e108..1800478b78 100644 --- a/src/lib/asiolink/io_service.h +++ b/src/lib/asiolink/io_service.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace boost { namespace asio { @@ -26,84 +27,89 @@ namespace isc { namespace asiolink { class IOServiceImpl; +class IOService; -/// \brief The \c IOService class is a wrapper for the ASIO \c io_service +/// @brief Defines a smart pointer to an IOService instance. +typedef boost::shared_ptr IOServicePtr; + +/// @brief The @ref IOService class is a wrapper for the ASIO @ref io_service /// class. -/// class IOService { + /// @brief Constructors and Destructor. /// - /// \name Constructors and Destructor - /// - /// Note: The copy constructor and the assignment operator are + /// @note The copy constructor and the assignment operator are /// intentionally defined as private, making this class non-copyable. //@{ private: IOService(const IOService& source); IOService& operator=(const IOService& source); public: - /// \brief The constructor + /// @brief The constructor. IOService(); - /// \brief The destructor. + + /// @brief The destructor. ~IOService(); //@} - /// \brief Start the underlying event loop. + /// @brief Start the underlying event loop. /// /// This method does not return control to the caller until - /// the \c stop() method is called via some handler. + /// the @ref stop() method is called via some handler. void run(); - /// \brief Run the underlying event loop for a single event. + /// @brief Run the underlying event loop for a single event. /// /// This method return control to the caller as soon as the /// first handler has completed. (If no handlers are ready when /// it is run, it will block until one is.) /// - /// \return The number of handlers that were executed. + /// @return The number of handlers that were executed. size_t runOne(); - /// \brief Run the underlying event loop for a ready events. + /// @brief Run the underlying event loop for a ready events. /// /// This method executes handlers for all ready events and returns. /// It will return immediately if there are no ready events. /// - /// \return The number of handlers that were executed. + /// @return The number of handlers that were executed. size_t poll(); - /// \brief Run the underlying event loop for a ready events. + /// @brief Run the underlying event loop for a ready events. /// /// This method executes handlers for all ready events and returns. /// It will return immediately if there are no ready events. /// - /// \return The number of handlers that were executed. + /// @return The number of handlers that were executed. size_t pollOne(); - /// \brief Stop the underlying event loop. + /// @brief Stop the underlying event loop. /// - /// This will return the control to the caller of the \c run() method. + /// This will return the control to the caller of the @ref run() method. void stop(); - /// \brief Indicates if the IOService has been stopped. + /// @brief Indicates if the IOService has been stopped. /// - /// \return true if the IOService has been stopped, false otherwise. + /// @return true if the IOService has been stopped, false otherwise. bool stopped() const; - /// \brief Restarts the IOService in preparation for a subsequent \c run() invocation. + /// @brief Restarts the IOService in preparation for a subsequent @ref run() invocation. void restart(); - /// \brief Removes IO service work object to let it finish running + /// @brief Removes IO service work object to let it finish running /// when all handlers have been invoked. void stopWork(); - /// \brief Return the native \c io_service object used in this wrapper. + /// @brief Return the native @ref io_service object used in this wrapper. /// /// This is a short term work around to support other Kea modules - /// that share the same \c io_service with the authoritative server. + /// that share the same @ref io_service with the authoritative server. /// It will eventually be removed once the wrapper interface is /// generalized. + /// + /// @return The internal io_service object. boost::asio::io_service& getInternalIOService(); - /// \brief Post a callback to the end of the queue. + /// @brief Post a callback to the end of the queue. /// /// Requests the callback be called sometime later. It is not guaranteed /// by the underlying asio, but it can reasonably be expected the callback @@ -114,12 +120,39 @@ public: /// by small bits that are called from time to time). void post(const std::function& callback); + /// @brief Register external IOService. + /// + /// @param io_service The external IOService to be registered. + void registerExternalIOService(IOServicePtr io_service); + + /// @brief Unregister external IOService. + /// + /// @param io_service The external IOService to be unregistered. + void unregisterExternalIOService(IOServicePtr io_service); + + /// @brief Clear the list of external IOService objects. + void clearExternalIOServices() { + external_io_services_.clear(); + } + + /// @brief The count of external IOService objects. + /// + // @return The count of external IOService objects. + size_t externalIOServiceCount() { + return (external_io_services_.size()); + } + + /// @brief Poll external IOService objects. + void pollExternalIOServices(); + private: + + /// @brief The implementation. boost::shared_ptr io_impl_; -}; -/// @brief Defines a smart pointer to an IOService instance. -typedef boost::shared_ptr IOServicePtr; + /// @brief The list of external IOService objects. + std::list external_io_services_; +}; } // namespace asiolink } // namespace isc diff --git a/src/lib/asiolink/tests/io_service_unittest.cc b/src/lib/asiolink/tests/io_service_unittest.cc index 7a96702e83..01a550d0f9 100644 --- a/src/lib/asiolink/tests/io_service_unittest.cc +++ b/src/lib/asiolink/tests/io_service_unittest.cc @@ -45,4 +45,105 @@ TEST(IOService, post) { EXPECT_EQ(3, called[2]); } +TEST(IOService, externalIOService) { + IOServicePtr main_io_service(new IOService()); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 0); + int one_io_callback_count = 0; + auto one_f = [&one_io_callback_count] () { + one_io_callback_count++; + }; + int two_io_callback_count = 0; + auto two_f = [&two_io_callback_count] () { + two_io_callback_count++; + }; + { + IOServicePtr one_io_service(new IOService()); + one_io_service->post(one_f); + + IOServicePtr two_io_service(new IOService()); + two_io_service->post(two_f); + + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 0); + EXPECT_EQ(two_io_callback_count, 0); + + main_io_service->registerExternalIOService(one_io_service); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 1); + + main_io_service->registerExternalIOService(two_io_service); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 2); + + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 1); + EXPECT_EQ(two_io_callback_count, 1); + one_io_service->post(one_f); + two_io_service->post(two_f); + } + EXPECT_EQ(main_io_service->externalIOServiceCount(), 2); + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 2); + EXPECT_EQ(two_io_callback_count, 2); + + main_io_service->clearExternalIOServices(); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 0); + + IOServicePtr one_io_service(new IOService()); + one_io_service->post(one_f); + + IOServicePtr two_io_service(new IOService()); + two_io_service->post(two_f); + + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 2); + EXPECT_EQ(two_io_callback_count, 2); + + main_io_service->registerExternalIOService(one_io_service); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 1); + + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 3); + EXPECT_EQ(two_io_callback_count, 2); + one_io_service->post(one_f); + two_io_service->post(two_f); + + main_io_service->registerExternalIOService(two_io_service); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 2); + + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 4); + EXPECT_EQ(two_io_callback_count, 4); + one_io_service->post(one_f); + two_io_service->post(two_f); + + main_io_service->unregisterExternalIOService(one_io_service); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 1); + + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 4); + EXPECT_EQ(two_io_callback_count, 5); + one_io_service->post(one_f); + two_io_service->post(two_f); + + main_io_service->unregisterExternalIOService(two_io_service); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 0); + + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 4); + EXPECT_EQ(two_io_callback_count, 5); + + EXPECT_NO_THROW(main_io_service->registerExternalIOService(main_io_service)); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 1); + main_io_service->post(one_f); + + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 5); + EXPECT_EQ(two_io_callback_count, 5); + EXPECT_NO_THROW(main_io_service->unregisterExternalIOService(main_io_service)); + EXPECT_EQ(main_io_service->externalIOServiceCount(), 0); + + main_io_service->pollExternalIOServices(); + EXPECT_EQ(one_io_callback_count, 5); + EXPECT_EQ(two_io_callback_count, 5); +} + } diff --git a/src/lib/d2srv/tests/nc_trans_unittests.cc b/src/lib/d2srv/tests/nc_trans_unittests.cc index 2f4a1ba9ce..39e024f39a 100644 --- a/src/lib/d2srv/tests/nc_trans_unittests.cc +++ b/src/lib/d2srv/tests/nc_trans_unittests.cc @@ -579,7 +579,7 @@ TEST_F(NameChangeTransactionTest, responseString) { EXPECT_EQ("IO_STOPPED", name_change_->responseString()); ASSERT_NO_THROW(name_change_->setDnsUpdateStatus(DNSClient:: - INVALID_RESPONSE)); + INVALID_RESPONSE)); EXPECT_EQ("INVALID_RESPONSE", name_change_->responseString()); ASSERT_NO_THROW(name_change_->setDnsUpdateStatus(DNSClient::OTHER)); diff --git a/src/lib/d2srv/testutils/nc_test_utils.cc b/src/lib/d2srv/testutils/nc_test_utils.cc index c9aaf0b1d0..563b5ba69e 100644 --- a/src/lib/d2srv/testutils/nc_test_utils.cc +++ b/src/lib/d2srv/testutils/nc_test_utils.cc @@ -540,7 +540,7 @@ checkAddFwdAddressRequest(NameChangeTransaction& tran) { dns::RRsetPtr rrset; checkRRCount(request, D2UpdateMessage::SECTION_PREREQUISITE, 1); ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 0)); + SECTION_PREREQUISITE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), dns::RRType::ANY(), 0, ncr); // Verify the UPDATE SECTION @@ -552,12 +552,12 @@ checkAddFwdAddressRequest(NameChangeTransaction& tran) { // First, Verify the FQDN/IP add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), exp_ip_rr_type, ttl, ncr); // Now, verify the DHCID add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 1)); + SECTION_UPDATE, 1)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), ttl, ncr); @@ -595,12 +595,12 @@ checkReplaceFwdAddressRequest(NameChangeTransaction& tran) { // Verify the FQDN test RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 0)); + SECTION_PREREQUISITE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), dns::RRType::ANY(), 0, ncr); // Verify the DHCID test RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 1)); + SECTION_PREREQUISITE, 1)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), 0, ncr); // Verify the UPDATE SECTION @@ -613,12 +613,12 @@ checkReplaceFwdAddressRequest(NameChangeTransaction& tran) { // Verify the FQDN delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), exp_ip_rr_type, 0, ncr); // Verify the FQDN/IP add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 1)); + SECTION_UPDATE, 1)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), exp_ip_rr_type, ttl, ncr); // Verify there are no RRs in the ADDITIONAL Section. @@ -663,25 +663,25 @@ checkReplaceRevPtrsRequest(NameChangeTransaction& tran) { // Verify the PTR delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_rev_addr, dns::RRClass::ANY(), dns::RRType::PTR(), 0, ncr); // Verify the DHCID delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 1)); + SECTION_UPDATE, 1)); checkRR(rrset, exp_rev_addr, dns::RRClass::ANY(), dns::RRType::DHCID(), 0, ncr); // Verify the PTR add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 2)); + SECTION_UPDATE, 2)); checkRR(rrset, exp_rev_addr, dns::RRClass::IN(), dns::RRType::PTR(), ttl, ncr); // Verify the DHCID add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 3)); + SECTION_UPDATE, 3)); checkRR(rrset, exp_rev_addr, dns::RRClass::IN(), dns::RRType::DHCID(), ttl, ncr); @@ -714,7 +714,7 @@ checkRemoveFwdAddressRequest(NameChangeTransaction& tran) { // Verify the DHCID matching assertion RR. dns::RRsetPtr rrset; ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 0)); + SECTION_PREREQUISITE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), 0, ncr); @@ -724,7 +724,7 @@ checkRemoveFwdAddressRequest(NameChangeTransaction& tran) { // Verify the FQDN/IP delete RR. const dns::RRType& exp_ip_rr_type = tran.getAddressRRType(); ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), exp_ip_rr_type, 0, ncr); @@ -754,19 +754,19 @@ checkRemoveFwdRRsRequest(NameChangeTransaction& tran) { // Verify the DHCID matches assertion. dns::RRsetPtr rrset; ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 0)); + SECTION_PREREQUISITE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), 0, ncr); // Verify the NO A RRs assertion. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 1)); + SECTION_PREREQUISITE, 1)); checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), dns::RRType::A(), 0, ncr, NO_RDATA); // Verify the NO AAAA RRs assertion. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 2)); + SECTION_PREREQUISITE, 2)); checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), dns::RRType::AAAA(), 0, ncr, NO_RDATA); @@ -775,7 +775,7 @@ checkRemoveFwdRRsRequest(NameChangeTransaction& tran) { // Verify the delete all for the FQDN RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), dns::RRType::ANY(), 0, ncr); @@ -805,7 +805,7 @@ checkRemoveRevPtrsRequest(NameChangeTransaction& tran) { // Verify the FQDN-PTRNAME assertion RR. dns::RRsetPtr rrset; ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 0)); + SECTION_PREREQUISITE, 0)); checkRR(rrset, exp_rev_addr, dns::RRClass::IN(), dns::RRType::PTR(), 0, ncr); @@ -814,7 +814,7 @@ checkRemoveRevPtrsRequest(NameChangeTransaction& tran) { // Verify the delete all for the FQDN RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_rev_addr, dns::RRClass::ANY(), dns::RRType::ANY(), 0, ncr); @@ -876,23 +876,23 @@ checkSimpleReplaceFwdAddressRequest(NameChangeTransaction& tran) { // Verify the FQDN delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), exp_ip_rr_type, 0, ncr); // Verify the DHCID delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 1)); + SECTION_UPDATE, 1)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), dns::RRType::DHCID(), 0, ncr); // Verify the FQDN/IP add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 2)); + SECTION_UPDATE, 2)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), exp_ip_rr_type, ttl, ncr); // Now, verify the DHCID add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 3)); + SECTION_UPDATE, 3)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), ttl, ncr); @@ -929,12 +929,12 @@ checkSimpleRemoveFwdRRsRequest(NameChangeTransaction& tran) { // Verify the FQDN delete RR. dns::RRsetPtr rrset; ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), exp_ip_rr_type, 0, ncr); // Verify the DHCID delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 1)); + SECTION_UPDATE, 1)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), dns::RRType::DHCID(), 0, ncr); @@ -970,12 +970,12 @@ checkSimpleRemoveRevPtrsRequest(NameChangeTransaction& tran) { // Verify the FQDN delete RR. dns::RRsetPtr rrset; ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_rev_addr, dns::RRClass::ANY(), dns::RRType::PTR(), 0, ncr); // Verify the DHCID delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 1)); + SECTION_UPDATE, 1)); checkRR(rrset, exp_rev_addr, dns::RRClass::ANY(), dns::RRType::DHCID(), 0, ncr); // Verify that it will render toWire without throwing. @@ -1021,7 +1021,7 @@ checkExistsReplaceFwdAddressRequest(NameChangeTransaction& tran) { // Verify the DHCID test RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 0)); + SECTION_PREREQUISITE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), dns::RRType::DHCID(), 0, ncr); // Verify the UPDATE SECTION @@ -1037,22 +1037,22 @@ checkExistsReplaceFwdAddressRequest(NameChangeTransaction& tran) { // Verify the FQDN delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), exp_ip_rr_type, 0, ncr); // Verify the DHCID delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 1)); + SECTION_UPDATE, 1)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), dns::RRType::DHCID(), 0, ncr); // Verify the FQDN/IP add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 2)); + SECTION_UPDATE, 2)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), exp_ip_rr_type, ttl, ncr); // Verify the DHCID add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 3)); + SECTION_UPDATE, 3)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), ttl, ncr); @@ -1088,7 +1088,7 @@ checkExistsRemoveFwdAddressRequest(NameChangeTransaction& tran) { // Verify the DHCID exists assertion RR. dns::RRsetPtr rrset; ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 0)); + SECTION_PREREQUISITE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), dns::RRType::DHCID(), 0, ncr); @@ -1098,7 +1098,7 @@ checkExistsRemoveFwdAddressRequest(NameChangeTransaction& tran) { // Verify the FQDN/IP delete RR. const dns::RRType& exp_ip_rr_type = tran.getAddressRRType(); ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), exp_ip_rr_type, 0, ncr); @@ -1131,13 +1131,13 @@ checkExistsRemoveFwdRRsRequest(NameChangeTransaction& tran) { // Verify the NO A RRs assertion. dns::RRsetPtr rrset; ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 0)); + SECTION_PREREQUISITE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), dns::RRType::A(), 0, ncr, NO_RDATA); // Verify the NO AAAA RRs assertion. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_PREREQUISITE, 1)); + SECTION_PREREQUISITE, 1)); checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), dns::RRType::AAAA(), 0, ncr, NO_RDATA); @@ -1146,7 +1146,7 @@ checkExistsRemoveFwdRRsRequest(NameChangeTransaction& tran) { // Verify the DHCID delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), dns::RRType::DHCID(), 0, ncr); @@ -1190,12 +1190,12 @@ checkSimpleReplaceFwdAddressWithoutDHCIDRequest(NameChangeTransaction& tran) { // Verify the FQDN delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), exp_ip_rr_type, 0, ncr); // Verify the FQDN/IP add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 1)); + SECTION_UPDATE, 1)); checkRR(rrset, exp_fqdn, dns::RRClass::IN(), exp_ip_rr_type, ttl, ncr); // Verify there are no RRs in the ADDITIONAL Section. @@ -1234,7 +1234,7 @@ checkSimpleRemoveFwdRRsWithoutDHCIDRequest(NameChangeTransaction& tran) { // Verify the FQDN delete RR. dns::RRsetPtr rrset; ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), exp_ip_rr_type, 0, ncr); // Verify that it will render toWire without throwing. @@ -1275,13 +1275,13 @@ checkSimpleReplaceRevPtrsWithoutDHCIDRequest(NameChangeTransaction& tran) { // Verify the PTR delete RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_rev_addr, dns::RRClass::ANY(), dns::RRType::PTR(), 0, ncr); // Verify the PTR add RR. ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 1)); + SECTION_UPDATE, 1)); checkRR(rrset, exp_rev_addr, dns::RRClass::IN(), dns::RRType::PTR(), ttl, ncr); @@ -1320,7 +1320,7 @@ checkSimpleRemoveRevPtrsWithoutDHCIDRequest(NameChangeTransaction& tran) { // Verify the FQDN delete RR. dns::RRsetPtr rrset; ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: - SECTION_UPDATE, 0)); + SECTION_UPDATE, 0)); checkRR(rrset, exp_rev_addr, dns::RRClass::ANY(), dns::RRType::PTR(), 0, ncr); // Verify that it will render toWire without throwing. diff --git a/src/lib/dhcpsrv/testutils/Makefile.am b/src/lib/dhcpsrv/testutils/Makefile.am index aa4f83f839..471d61deeb 100644 --- a/src/lib/dhcpsrv/testutils/Makefile.am +++ b/src/lib/dhcpsrv/testutils/Makefile.am @@ -16,6 +16,7 @@ libdhcpsrvtest_la_SOURCES = concrete_lease_mgr.cc concrete_lease_mgr.h libdhcpsrvtest_la_SOURCES += config_result_check.cc config_result_check.h libdhcpsrvtest_la_SOURCES += dhcp4o6_test_ipc.cc dhcp4o6_test_ipc.h libdhcpsrvtest_la_SOURCES += host_data_source_utils.cc host_data_source_utils.h +libdhcpsrvtest_la_SOURCES += lib_load_test_fixture.h libdhcpsrvtest_la_SOURCES += memory_host_data_source.cc memory_host_data_source.h libdhcpsrvtest_la_SOURCES += test_utils.cc test_utils.h libdhcpsrvtest_la_SOURCES += generic_backend_unittest.cc generic_backend_unittest.h diff --git a/src/lib/testutils/lib_load_test_fixture.h b/src/lib/dhcpsrv/testutils/lib_load_test_fixture.h similarity index 99% rename from src/lib/testutils/lib_load_test_fixture.h rename to src/lib/dhcpsrv/testutils/lib_load_test_fixture.h index 918656d4fd..11f03b3201 100644 --- a/src/lib/testutils/lib_load_test_fixture.h +++ b/src/lib/dhcpsrv/testutils/lib_load_test_fixture.h @@ -9,7 +9,9 @@ #include #include +#include #include + #include namespace isc { diff --git a/src/lib/hooks/hooks_user.dox b/src/lib/hooks/hooks_user.dox index ce9ff442c0..e6e96e392d 100644 --- a/src/lib/hooks/hooks_user.dox +++ b/src/lib/hooks/hooks_user.dox @@ -1620,7 +1620,7 @@ cb4_updated and cb6_updated have no thread safety requirements. Other hook library entry points are called by the main thread: - io service (io context is recent boost versions) is polled by the main - thread + thread - external socket callbacks are executed by the main thread - commands including command_process diff --git a/src/lib/process/d_controller.cc b/src/lib/process/d_controller.cc index 1b9276df82..6f2994accb 100644 --- a/src/lib/process/d_controller.cc +++ b/src/lib/process/d_controller.cc @@ -415,6 +415,8 @@ DControllerBase::configFromFile() { // case of problems. storage->applyLoggingCfg(); + getIOService()->clearExternalIOServices(); + answer = updateConfig(module_config); // In all cases the right logging configuration is in the context. process_->getCfgMgr()->getContext()->applyLoggingCfg(); @@ -655,6 +657,8 @@ DControllerBase::configSetHandler(const std::string&, ConstElementPtr args) { // case of problems. storage->applyLoggingCfg(); + getIOService()->clearExternalIOServices(); + ConstElementPtr answer = updateConfig(module_config); int rcode = 0; parseAnswer(rcode, answer); @@ -844,6 +848,8 @@ DControllerBase::~DControllerBase() { LOG_ERROR(dctl_logger, DCTL_UNLOAD_LIBRARIES_ERROR).arg(msg); } + getIOService()->clearExternalIOServices(); + io_signal_set_.reset(); try { getIOService()->poll(); diff --git a/src/lib/testutils/Makefile.am b/src/lib/testutils/Makefile.am index 03d78fbab1..30332da548 100644 --- a/src/lib/testutils/Makefile.am +++ b/src/lib/testutils/Makefile.am @@ -16,7 +16,6 @@ libkea_testutils_la_SOURCES += unix_control_client.cc unix_control_client.h libkea_testutils_la_SOURCES += user_context_utils.cc user_context_utils.h libkea_testutils_la_SOURCES += gtest_utils.h libkea_testutils_la_SOURCES += multi_threading_utils.h -libkea_testutils_la_SOURCES += lib_load_test_fixture.h libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) libkea_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la libkea_testutils_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la diff --git a/tools/check-lib-dependencies.sh b/tools/check-lib-dependencies.sh new file mode 100755 index 0000000000..b2ae9acdcf --- /dev/null +++ b/tools/check-lib-dependencies.sh @@ -0,0 +1,319 @@ +#!/bin/bash + +# extract folder name containing file +# +# param ${1} file name +# return folder name +extract_folder_name() { + # return name of the file until last '/' + echo "$(echo "${1}" | rev | cut -d '/' -f 2- | rev)" +} + +# extract all includes found in source files found in the same folder as specified Makefile.am +# +# param ${1} path to a Makefile.am +# return all dependencies libs in the order of compilation +extract_includes() { + # extract folder name from current library Makefile.am + CURRENT_FOLDER=$(extract_folder_name "${1}")"/" + # select only files in current folder + SEARCH_FILES=$(echo "${FILE_LIST}" | grep "${CURRENT_FOLDER}") + # select all lines containing '#include ' directive + RAW_INCLUDES_LIST=$(echo "${SEARCH_FILES}" | xargs grep "^#include " 2>/dev/null) + # filter only included dependencies found in other libraries by using the form 'other_lib_name/header_file.h' + # to do this it is required to select the string between '<' and '>', searching for '/' character and returning the name until last '/' + RAW_INCLUDES_LIST=$(echo "${RAW_INCLUDES_LIST}" | cut -d "#" -f 2 | tr "\"" " " | cut -d "<" -f 2 | cut -d ">" -f 1 | grep "\/" | rev | cut -d "/" -f 2 | rev | sort | uniq) + # filter includes that are not compiled by the project's Makefiles + INCLUDES_LIST= + for i in ${LIBRARIES_LIST}; do + for j in ${RAW_INCLUDES_LIST}; do + if test "${j}" = "${i}"; then + INCLUDES_LIST="${i} ${INCLUDES_LIST}" + break + fi + done + done + # remove empty spaces + INCLUDES_LIST=$(echo ${INCLUDES_LIST} | tr -s " ") + # order dependencies in the order of compilation + FILTERED_INCLUDES_LIST= + for i in ${LIBRARIES_LIST}; do + if test $(echo "${INCLUDES_LIST}" | grep "\b${i}\b" | wc -l) -ne 0; then + FILTERED_INCLUDES_LIST="${i} ${FILTERED_INCLUDES_LIST}" + fi + done + echo "${FILTERED_INCLUDES_LIST}" +} + +# extract all header only files and headers and source files found in the external library required by specified library +# param ${1} name of the current library +# param ${2} name of the external dependency library required by current library +# return the list of header only files as 'HEADERS: heaser1.h header2.h' and header and source files as 'HEADERS_AND_SOURCES: source1.h source1.cc source2.h source2.cpp' +extract_non_include_files() { + # extract folder name for current library Makefile.am + CURRENT_FOLDER=$(extract_folder_name "src/lib/${1}/Makefile.am")"/" + # extract folder name for external dependency library Makefile.am + EXTERNAL_FOLDER=$(extract_folder_name "src/lib/${2}/Makefile.am")"/" + # select only files in current folder + SEARCH_FILES=$(echo "${FILE_LIST}" | grep "${CURRENT_FOLDER}") + HEADERS_LIST= + NON_HEADERS_LIST= + # select all lines containing '#include ' directive + RAW_INCLUDES_LIST=$(echo "${SEARCH_FILES}" | xargs grep "^#include " 2>/dev/null) + # filter only included headers found in other libraries by using the form 'other_lib_name/header_file.h' + # to do this it is required to select the string between '<' and '>', searching for '/' character, search for the extension marker '.' and returning the name after last '/' + RAW_INCLUDES_LIST=$(echo "${RAW_INCLUDES_LIST}" | cut -d "#" -f 2 | tr "\"" " " | cut -d "<" -f 2 | cut -d ">" -f 1 | grep "\/" | grep "\b${2}\b" | cut -d "/" -f 2 | grep "\." | sort | uniq) + # select only files in dependency library folder and strip full path + RELATIVE_SEARCH_FILES=$(echo "${FILE_LIST}" | grep "${EXTERNAL_FOLDER}" | sed -e "s#${REPO_FOLDER}${EXTERNAL_FOLDER}##g") + # search for the header file but also for source files + for i in ${RAW_INCLUDES_LIST}; do + # filter by name only (no extension) + FILTER=$(echo "${i}" | cut -d "." -f 1) + # filter non header files with exact name of the header file without the extension + NON_HEADER=$(echo "${RELATIVE_SEARCH_FILES}" | grep "\b${FILTER}\." | grep -v "${i}") + if test $(echo "${NON_HEADER}" | wc -w) -ne 0; then + # append header and source file names + NON_HEADERS_LIST="${i} ${NON_HEADER} ${NON_HEADERS_LIST}" + else + # append header only file name + HEADERS_LIST="${i} ${HEADERS_LIST}" + fi + done + # sort header only files + HEADERS_LIST=$(echo ${HEADERS_LIST} | tr -s " " | sort | uniq) + # sort header and source files + NON_HEADERS_LIST=$(echo ${NON_HEADERS_LIST} | tr -s " " | sort | uniq) + echo "HEADERS_AND_SOURCES:${NON_HEADERS_LIST}" + echo "HEADERS:${HEADERS_LIST}" +} + +# extract all valid dependencies of a specified library +# +# param ${1} list of all libraries in the reverse compilation order +# param ${2} library name for which the dependency list is computed +# return the list of dependencies for specified library in the reverse compilation order +extract_dependencies() { + echo "${1}" | grep -Eo "\b${2}\b.*$" +} + +# extract computed dependency for specified library +# +# param ${1} library name for which the dependency list is retrieved +# param ${2} library path for which the dependency list is retrieved +# return stored value of computed dependencies or 'NONE' if dependencies have not been computed yet +extract_computed_dependencies() { + PATH_TO_NAME=$(echo "${2}" | tr -s "/" "_") + NAME="COMPUTED_DEPENDENCIES_${PATH_TO_NAME}_${1}" + if test -n "${!NAME+x}"; then + echo "${!NAME}" + else + echo "NONE" + fi +} + +# extract library directive +# +# param ${1} artifact path +extract_library_directive() { + ARTIFACT_PATH="${1}" + echo `cat ${ARTIFACT_PATH}/Makefile.am | grep "LIBADD\|LDADD" | sort | tr -s ' ' | cut -d " " -f 1 | sort -u` +} + +# extract library name +# +# param ${1} artifact path +extract_library_name() { + ARTIFACT_PATH="${1}" + echo `cat ${ARTIFACT_PATH}/Makefile.am | grep "LIBRARIES" | tr -s ' ' | cut -d " " -f 3` +} + +# compute artifact dependencies +# +# param ${1} artifact name +# param ${2} artifact path +compute_dependencies() { + ARTIFACT="${1}" + ARTIFACT_PATH="${2}" + echo "" + echo "########################################" + echo "### ${ARTIFACT_PATH}/${ARTIFACT}" + echo "########################################" + echo "" + # all valid dependencies that can be added by each dependency library + echo "${ARTIFACT_PATH}/${ARTIFACT} valid dependencies:" + echo "${VALID_LIST}" + # detect dependencies errors by searching for dependencies that are compiled after the current library and can generate missing symbols + NON_RECURSIVE_BASE_DEPENDENCIES= + for j in ${BASE_DEPENDENCIES}; do + # only add the dependency if it is in the valid dependencies list to prevent infinite recursion and log the error otherwise + if test $(echo "${VALID_LIST}" | grep "\b${j}\b" | wc -l) -eq 0; then + # search for external header and source files + INVALID_EXTERNAL_DEPENDENCIES=$(extract_non_include_files "${ARTIFACT}" "${j}") + # filter header only external files + EXTERNAL_HEADERS=$(echo "${INVALID_EXTERNAL_DEPENDENCIES}" | grep "HEADERS:" | cut -d ":" -f 2) + # filter header and source external files + EXTERNAL_ALL=$(echo "${INVALID_EXTERNAL_DEPENDENCIES}" | grep "HEADERS_AND_SOURCES:" | cut -d ":" -f 2) + echo "### ERROR ### dependencies ERROR for ${ARTIFACT_PATH}/${ARTIFACT} on ${j} with:" + # if there are any header only external files + if test $(echo "${EXTERNAL_ALL}" | wc -w) -ne 0; then + echo "non header only files: ${EXTERNAL_ALL}" + fi + # if there are any header and source external files + if test $(echo "${EXTERNAL_HEADERS}" | wc -w) -ne 0; then + echo "header only files: ${EXTERNAL_HEADERS}" + fi + else + # don't add current library to it's dependencies list + if test ${j} != ${ARTIFACT}; then + NON_RECURSIVE_BASE_DEPENDENCIES="${NON_RECURSIVE_BASE_DEPENDENCIES} ${j}" + fi + fi + done + # all found dependencies in the reverse compilation order + BASE_DEPENDENCIES=$(echo "${BASE_DEPENDENCIES}" | xargs) + # all found and valid dependencies in the reverse compilation order + NON_RECURSIVE_BASE_DEPENDENCIES=$(echo "${NON_RECURSIVE_BASE_DEPENDENCIES}" | xargs) + echo "${ARTIFACT_PATH}/${ARTIFACT} base dependencies:" + echo "${BASE_DEPENDENCIES}" + echo "${ARTIFACT_PATH}/${ARTIFACT} non recursive dependencies:" + echo "${NON_RECURSIVE_BASE_DEPENDENCIES}" + # minimum set of dependencies for current library + DEPENDENCIES= + for j in ${NON_RECURSIVE_BASE_DEPENDENCIES}; do + NEW_DEPENDENCIES=$(extract_computed_dependencies "${j}" "src/lib") + if test "${NEW_DEPENDENCIES}" == "NONE"; then + echo "### ERROR ### computed dependency not found for ${j}" + else + DEPENDENCIES="${NEW_DEPENDENCIES} ${DEPENDENCIES}" + fi + done + DEPENDENCIES=$(echo "${DEPENDENCIES} ${NON_RECURSIVE_BASE_DEPENDENCIES}" | tr -s " " "\n" | sort | uniq | xargs) + # order dependencies in the order of compilation + SORTED_DEPENDENCIES= + for j in ${LIBRARIES_LIST}; do + if test $(echo "${DEPENDENCIES}" | grep "\b${j}\b" | wc -l) -ne 0; then + SORTED_DEPENDENCIES="${j} ${SORTED_DEPENDENCIES}" + fi + done + echo "${ARTIFACT_PATH}/${ARTIFACT} minimum dependencies:" + echo "${SORTED_DEPENDENCIES}" + echo "" + echo "++++++++++++++++++++++++++++++++++++++++" + ARTIFACT_DIRECTIVE=$(extract_library_directive ${ARTIFACT_PATH}/${ARTIFACT}) + for j in ${SORTED_DEPENDENCIES}; do + DEPENDENCY_LIBRARY_NAME=$(extract_library_name "src/lib/${j}") + echo "${ARTIFACT_DIRECTIVE} += \$(top_builddir)/src/lib/${j}/${DEPENDENCY_LIBRARY_NAME}" + done + echo "++++++++++++++++++++++++++++++++++++++++" + echo "########################################" + echo "" +} + +# if wrong number of parameters print usage +if test ${#} -ne 1; then + echo "Usage: ${0} path/to/kea/repo" + exit +fi + +# folder containing full repo +REPO_FOLDER=${1} + +if test $(echo -n ${REPO_FOLDER} | tail -c 1) != "/"; then + REPO_FOLDER="${REPO_FOLDER}/" +fi + +# filter all Makefile.am files +MAKEFILES_LIST=$(find ${REPO_FOLDER} | grep "Makefile\.am" | sed -e "s#${REPO_FOLDER}##g" | grep "src\/" | sort) + +# if no Makefile.am found exit +if test -z "${MAKEFILES_LIST}"; then + echo "invalid repo path: no Makefile.am file found" + exit +fi + +echo "list of Makefile.am:" +echo "${MAKEFILES_LIST}" + +# base Makefile.am for all sources is in src/lib/Makefile.am +BASE_MAKEFILE=$(echo "${MAKEFILES_LIST}" | grep "src\/lib\/Makefile.am") + +# if no src/lib/Makefile.am found exit +if test -z ${BASE_MAKEFILE}; then + echo "invalid repo path: no src/lib/Makefile.am file found" + exit +fi + +echo "base Makefile.am:" +echo "${BASE_MAKEFILE}" + +# generate the list of libraries in the compilation order +LIBRARIES_LIST= +RAW_LIBRARIES_LIST=$(cat "${REPO_FOLDER}${BASE_MAKEFILE}" | grep "SUBDIRS") +for i in ${RAW_LIBRARIES_LIST}; do + LIBRARIES_LIST="${LIBRARIES_LIST} $(echo ${i} | grep -v "SUBDIRS" | grep -v '=')" +done + +# remove empty spaces +LIBRARIES_LIST=$(echo "${LIBRARIES_LIST}" | tr -s ' ' | xargs) + +# generate the list of libraries in the reverse compilation order +REVERSE_LIBRARIES_LIST= +for i in ${LIBRARIES_LIST}; do + REVERSE_LIBRARIES_LIST="${i} ${REVERSE_LIBRARIES_LIST}" +done + +echo "list of libraries:" +echo "${LIBRARIES_LIST}" + +echo "reverse list of libraries:" +echo "${REVERSE_LIBRARIES_LIST}" + +# filter all files of interest ignoring irrelevant ones +# ignore .git, .libs, .deps doc folders and .o .lo .Plo .Po .gcno .gcda .m4 .dox .json .mes files +FILE_LIST=$(find "${REPO_FOLDER}" 2>/dev/null | grep -v "\.git" | grep -v "\/\.libs\/" | grep -v "\.o$" | grep -v "\/\.deps\/" | grep -v "\.lo$" | grep -v "\.Plo$" | grep -v "\.Po$" | grep -v "\.gcno$" | grep -v "gcda" | grep -v "\.m4$" | grep -v "\.dox$" | grep -v "\.json$" | grep -v "\/doc\/" | grep -v "\.mes$" | sort) + +#echo "files:" +#echo "${FILE_LIST}" + +BASE_LIBRARIES_MAKEFILES= + +# generate the list of dependencies for all libraries in src/lib +for i in ${LIBRARIES_LIST}; do + # generate current library Makefile.am path + BASE_LIBRARIES_MAKEFILES="${BASE_LIBRARIES_MAKEFILES} src/lib/${i}/Makefile.am" + # extract dependencies found in the library folder + BASE_DEPENDENCIES=$(extract_includes "src/lib/${i}/Makefile.am") + # generate the list of valid dependencies for the current library (take compilation order into account) + VALID_LIST=$(extract_dependencies "${REVERSE_LIBRARIES_LIST}" "${i}") + compute_dependencies "${i}" "src/lib" + PATH_TO_NAME=$(echo "src/lib" | tr -s "/" "_") + declare COMPUTED_DEPENDENCIES_${PATH_TO_NAME}_${i}="${SORTED_DEPENDENCIES}" +done + +# remove empty spaces +BASE_LIBRARIES_MAKEFILES=$(echo "${BASE_LIBRARIES_MAKEFILES}" | xargs | tr -s " " "\n") + +echo "base Makefiles.am files:" +echo "${BASE_LIBRARIES_MAKEFILES}" + +OTHER_MAKEFILES=$(echo "${MAKEFILES_LIST}" | tr -s " " "\n" | grep -v "src/lib/" | grep -v "src/share/" | grep -v "src/Makefile.am") +# remove empty spaces +OTHER_MAKEFILES=$(echo "${OTHER_MAKEFILES}" | xargs | tr -s " " "\n") + +echo "remaining Makefile.am files:" +echo "${OTHER_MAKEFILES}" + +for i in ${OTHER_MAKEFILES}; do + # extract dependencies found in the artifact folder + BASE_DEPENDENCIES=$(extract_includes "${i}") + # generate the list of valid dependencies for the current artifact (take compilation order into account) + VALID_LIST="${REVERSE_LIBRARIES_LIST}" + ARTIFACT=$(echo "${i}" | rev | cut -d "/" -f 2 | rev) + ARTIFACT_PATH=$(echo "${i}" | rev | cut -d "/" -f 3- | rev) + compute_dependencies "${ARTIFACT}" "${ARTIFACT_PATH}" + PATH_TO_NAME=$(echo "${ARTIFACT_PATH}" | tr -s "/" "_") + declare COMPUTED_DEPENDENCIES_${PATH_TO_NAME}_${ARTIFACT}="${SORTED_DEPENDENCIES}" +done + +exit +