// stop thread pool (if running)
MultiThreadingCriticalSection cs;
- /// @todo delete any stored CalloutHandles referring to the old libraries
- /// Get list of currently loaded libraries and reload them.
- HookLibsCollection loaded = HooksManager::getLibraryInfo();
- bool status = HooksManager::loadLibraries(loaded);
- if (!status) {
+ // Clear the packet queue.
+ MultiThreadingMgr::instance().getThreadPool().reset();
+
+ try {
+ /// Get list of currently loaded libraries and reload them.
+ HookLibsCollection loaded = HooksManager::getLibraryInfo();
+ HooksManager::prepareUnloadLibraries();
+ static_cast<void>(HooksManager::unloadLibraries());
+ bool status = HooksManager::loadLibraries(loaded);
+ if (!status) {
+ isc_throw(Unexpected, "Failed to reload hooks libraries.");
+ }
+ } catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_HOOKS_LIBS_RELOAD_FAIL);
- ConstElementPtr answer = isc::config::createAnswer(1,
- "Failed to reload hooks libraries.");
+ ConstElementPtr answer = isc::config::createAnswer(1, ex.what());
return (answer);
}
ConstElementPtr answer = isc::config::createAnswer(0,
-// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Mon Jun 22 2020 17:28
+// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Thu Jun 25 2020 13:36
#include <cstddef>
#include <log/message_types.h>
extern const isc::log::MessageID DHCP4_SRV_CONSTRUCT_ERROR = "DHCP4_SRV_CONSTRUCT_ERROR";
extern const isc::log::MessageID DHCP4_SRV_D2STOP_ERROR = "DHCP4_SRV_D2STOP_ERROR";
extern const isc::log::MessageID DHCP4_SRV_DHCP4O6_ERROR = "DHCP4_SRV_DHCP4O6_ERROR";
+extern const isc::log::MessageID DHCP4_SRV_UNLOAD_LIBRARIES_ERROR = "DHCP4_SRV_UNLOAD_LIBRARIES_ERROR";
extern const isc::log::MessageID DHCP4_STARTED = "DHCP4_STARTED";
extern const isc::log::MessageID DHCP4_STARTING = "DHCP4_STARTING";
extern const isc::log::MessageID DHCP4_START_INFO = "DHCP4_START_INFO";
"DHCP4_SRV_CONSTRUCT_ERROR", "error creating Dhcpv4Srv object, reason: %1",
"DHCP4_SRV_D2STOP_ERROR", "error stopping IO with DHCP_DDNS during shutdown: %1",
"DHCP4_SRV_DHCP4O6_ERROR", "error stopping IO with DHCPv4o6 during shutdown: %1",
+ "DHCP4_SRV_UNLOAD_LIBRARIES_ERROR", "error unloading hooks libraries during shutdown: %1",
"DHCP4_STARTED", "Kea DHCPv4 server version %1 started",
"DHCP4_STARTING", "Kea DHCPv4 server version %1 (%2) starting",
"DHCP4_START_INFO", "pid: %1, server port: %2, client port: %3, verbose: %4",
-// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Mon Jun 22 2020 17:28
+// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Thu Jun 25 2020 13:36
#ifndef DHCP4_MESSAGES_H
#define DHCP4_MESSAGES_H
extern const isc::log::MessageID DHCP4_SRV_CONSTRUCT_ERROR;
extern const isc::log::MessageID DHCP4_SRV_D2STOP_ERROR;
extern const isc::log::MessageID DHCP4_SRV_DHCP4O6_ERROR;
+extern const isc::log::MessageID DHCP4_SRV_UNLOAD_LIBRARIES_ERROR;
extern const isc::log::MessageID DHCP4_STARTED;
extern const isc::log::MessageID DHCP4_STARTING;
extern const isc::log::MessageID DHCP4_START_INFO;
probably due to a programmatic error is not likely to impact either server
upon restart. The reason for the failure is given within the message.
+% DHCP4_SRV_UNLOAD_LIBRARIES_ERROR error unloading hooks libraries during shutdown: %1
+This error message indicates that during shutdown, unloading hooks
+libraries failed to close them. If the list of libraries is empty it is
+a programmatic error in the server code. If it is not empty it could be
+a programmatic error in one of the hooks libraries which could lead to
+a crash during finalization.
+
% DHCP4_STARTED Kea DHCPv4 server version %1 started
This informational message indicates that the DHCPv4 server has
processed all configuration information and is ready to process
LeaseMgrFactory::destroy();
// Explicitly unload hooks
- HooksManager::unloadLibraries();
+ HooksManager::prepareUnloadLibraries();
+ if (!HooksManager::unloadLibraries()) {
+ auto names = HooksManager::getLibraryNames();
+ std::string msg;
+ if (!names.empty()) {
+ msg = names[0];
+ for (size_t i = 1; i < names.size(); ++i) {
+ msg += std::string(", ") + names[i];
+ }
+ }
+ LOG_ERROR(dhcp4_logger, DHCP4_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg);
+ }
}
void
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/timer_mgr.h>
#include <process/config_ctl_parser.h>
+#include <hooks/hooks_manager.h>
#include <hooks/hooks_parser.h>
#include <config/command_mgr.h>
#include <util/encode/hex.h>
// This occurs last as if it succeeds, there is no easy way to
// revert it. As a result, the failure to commit a subsequent
// change causes problems when trying to roll back.
+ HooksManager::prepareUnloadLibraries();
+ static_cast<void>(HooksManager::unloadLibraries());
const HooksConfig& libraries =
CfgMgr::instance().getStagingCfg()->getHooksConfig();
libraries.loadLibraries();
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
callback_sent_pkt_options_copy_ = std::make_pair(false, false);
}
+ /// @brief Destructor
+ ///
+ /// Various cleanups.
+ virtual ~Dhcp4to6IpcTest() {
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_send");
+ callback_recv_pkt_.reset();
+ callback_sent_pkt_.reset();
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ cerr << "(fixture dtor) unloadLibraries failed" << endl;
+ }
+ }
+
/// @brief Configure DHCP4o6 port.
///
/// @param port New port.
/// @brief creates Dhcpv4Srv and prepares buffers for callouts
HooksDhcpv4SrvTest() {
HooksManager::setTestMode(false);
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ cerr << "(fixture ctor) unloadLibraries failed" << endl;
+ }
// Allocate new DHCPv6 Server
srv_ = new NakedDhcpv4Srv(0);
/// @brief destructor (deletes Dhcpv4Srv)
virtual ~HooksDhcpv4SrvTest() {
+ // clear static buffers
+ resetCalloutBuffers();
+
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("dhcp4_srv_configured");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_receive");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer4_send");
delete srv_;
HooksManager::setTestMode(false);
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ cerr << "(fixture dtor) unloadLibraries failed" << endl;
+ }
}
/// @brief creates an option with specified option code
ASSERT_TRUE(status);
int rcode;
ConstElementPtr comment = config::parseAnswer(rcode, status);
- ASSERT_EQ(0, rcode);
+ ASSERT_EQ(0, rcode) << " comment: " << comment->stringValue();
ASSERT_NO_THROW( {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
cfg_db->setAppendedParameters("universe=4");
// stop thread pool (if running)
MultiThreadingCriticalSection cs;
- /// @todo delete any stored CalloutHandles referring to the old libraries
- /// Get list of currently loaded libraries and reload them.
- HookLibsCollection loaded = HooksManager::getLibraryInfo();
- bool status = HooksManager::loadLibraries(loaded);
- if (!status) {
+ // Clear the packet queue.
+ MultiThreadingMgr::instance().getThreadPool().reset();
+
+ try {
+ /// Get list of currently loaded libraries and reload them.
+ HookLibsCollection loaded = HooksManager::getLibraryInfo();
+ HooksManager::prepareUnloadLibraries();
+ static_cast<void>(HooksManager::unloadLibraries());
+ bool status = HooksManager::loadLibraries(loaded);
+ if (!status) {
+ isc_throw(Unexpected, "Failed to reload hooks libraries.");
+ }
+ } catch (const std::exception& ex) {
LOG_ERROR(dhcp6_logger, DHCP6_HOOKS_LIBS_RELOAD_FAIL);
- ConstElementPtr answer = isc::config::createAnswer(1,
- "Failed to reload hooks libraries.");
+ ConstElementPtr answer = isc::config::createAnswer(1, ex.what());
return (answer);
}
ConstElementPtr answer = isc::config::createAnswer(0,
-// File created from ../../../src/bin/dhcp6/dhcp6_messages.mes on Mon Jun 22 2020 17:30
+// File created from ../../../src/bin/dhcp6/dhcp6_messages.mes on Thu Jun 25 2020 14:35
#include <cstddef>
#include <log/message_types.h>
extern const isc::log::MessageID DHCP6_SOCKET_UNICAST = "DHCP6_SOCKET_UNICAST";
extern const isc::log::MessageID DHCP6_SRV_CONSTRUCT_ERROR = "DHCP6_SRV_CONSTRUCT_ERROR";
extern const isc::log::MessageID DHCP6_SRV_D2STOP_ERROR = "DHCP6_SRV_D2STOP_ERROR";
+extern const isc::log::MessageID DHCP6_SRV_UNLOAD_LIBRARIES_ERROR = "DHCP6_SRV_UNLOAD_LIBRARIES_ERROR";
extern const isc::log::MessageID DHCP6_STANDALONE = "DHCP6_STANDALONE";
extern const isc::log::MessageID DHCP6_STARTED = "DHCP6_STARTED";
extern const isc::log::MessageID DHCP6_STARTING = "DHCP6_STARTING";
"DHCP6_SOCKET_UNICAST", "server is about to open socket on address %1 on interface %2",
"DHCP6_SRV_CONSTRUCT_ERROR", "error creating Dhcpv6Srv object, reason: %1",
"DHCP6_SRV_D2STOP_ERROR", "error stopping IO with DHCP_DDNS during shutdown: %1",
+ "DHCP6_SRV_UNLOAD_LIBRARIES_ERROR", "error unloading hooks libraries during shutdown: %1",
"DHCP6_STANDALONE", "skipping message queue, running standalone",
"DHCP6_STARTED", "Kea DHCPv6 server version %1 started",
"DHCP6_STARTING", "Kea DHCPv6 server version %1 (%2) starting",
-// File created from ../../../src/bin/dhcp6/dhcp6_messages.mes on Mon Jun 22 2020 17:30
+// File created from ../../../src/bin/dhcp6/dhcp6_messages.mes on Thu Jun 25 2020 14:35
#ifndef DHCP6_MESSAGES_H
#define DHCP6_MESSAGES_H
extern const isc::log::MessageID DHCP6_SOCKET_UNICAST;
extern const isc::log::MessageID DHCP6_SRV_CONSTRUCT_ERROR;
extern const isc::log::MessageID DHCP6_SRV_D2STOP_ERROR;
+extern const isc::log::MessageID DHCP6_SRV_UNLOAD_LIBRARIES_ERROR;
extern const isc::log::MessageID DHCP6_STANDALONE;
extern const isc::log::MessageID DHCP6_STARTED;
extern const isc::log::MessageID DHCP6_STARTING;
probably due to a programmatic error is not likely to impact either server
upon restart. The reason for the failure is given within the message.
+% DHCP6_SRV_UNLOAD_LIBRARIES_ERROR error unloading hooks libraries during shutdown: %1
+This error message indicates that during shutdown, unloading hooks
+libraries failed to close them. If the list of libraries is empty it is
+a programmatic error in the server code. If it is not empty it could be
+a programmatic error in one of the hooks libraries which could lead to
+a crash during finalization.
+
% DHCP6_STANDALONE skipping message queue, running standalone
This is a debug message indicating that the IPv6 server is running in
standalone mode, not connected to the message queue. Standalone mode
LeaseMgrFactory::destroy();
// Explicitly unload hooks
- HooksManager::unloadLibraries();
+ HooksManager::prepareUnloadLibraries();
+ if (!HooksManager::unloadLibraries()) {
+ auto names = HooksManager::getLibraryNames();
+ std::string msg;
+ if (!names.empty()) {
+ msg = names[0];
+ for (size_t i = 1; i < names.size(); ++i) {
+ msg += std::string(", ") + names[i];
+ }
+ }
+ LOG_ERROR(dhcp6_logger, DHCP6_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg);
+ }
}
void Dhcpv6Srv::shutdown() {
-// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// Delete previously set arguments
callout_handle->deleteAllArguments();
+ // Use the RAII wrapper to make sure that the callout handle state is
+ // reset when this object goes out of scope. All hook points must do
+ // it to prevent possible circular dependency between the callout
+ // handle and its arguments.
+ ScopedCalloutHandleState callout_handle_state(callout_handle);
+
// Enable copying options from the packet within hook library.
ScopedEnableOptionsCopy<Pkt6> response6_options_copy(pkt);
}
}
-}; // namespace dhcp
+} // namespace dhcp
+
+} // namespace isc
-}; // namespace isc
#include <dhcpsrv/parsers/sanity_checks_parser.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <hooks/hooks_parser.h>
+#include <hooks/hooks_manager.h>
#include <log/logger_support.h>
#include <process/config_ctl_parser.h>
// change causes problems when trying to roll back.
const HooksConfig& libraries =
CfgMgr::instance().getStagingCfg()->getHooksConfig();
+ HooksManager::prepareUnloadLibraries();
+ static_cast<void>(HooksManager::unloadLibraries());
libraries.loadLibraries();
}
catch (const isc::Exception& ex) {
-// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
callback_pkt_options_copy_ = false;
}
+ /// @brief Destructor
+ ///
+ /// Various cleanups.
+ virtual ~Dhcp6to4IpcTest() {
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer6_send");
+ callback_pkt_.reset();
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ std::cerr << "(fixture dtor) unloadLibraries failed" << std::endl;
+ }
+ }
+
/// @brief Configure DHCP4o6 port.
///
/// @param port New port.
: Dhcpv6SrvTest() {
HooksManager::setTestMode(false);
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ cerr << "(fixture ctor) unloadLibraries failed" << endl;
+ }
// Allocate new DHCPv6 Server
srv_.reset(new NakedDhcpv6Srv(0));
/// @brief destructor (deletes Dhcpv6Srv)
~HooksDhcpv6SrvTest() {
+ // Clear static buffers
+ resetCalloutBuffers();
+
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer6_receive");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt6_receive");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("pkt6_send");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("buffer6_send");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("subnet6_select");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("leases6_committed");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease6_renew");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease6_release");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease6_rebind");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease6_decline");
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("host6_identifier");
+
HooksManager::setTestMode(false);
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ cerr << "(fixture dtor) unloadLibraries failed" << endl;
+ }
}
/// @brief creates an option with specified option code
/// that no libraries are loaded and that any marker files are deleted.
void reset() {
// Unload any previously-loaded libraries.
- HooksManager::unloadLibraries();
+ EXPECT_TRUE(HooksManager::unloadLibraries());
// Get rid of any marker files.
static_cast<void>(remove(LOAD_MARKER_FILE));
-// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
#include <hooks/callout_manager.h>
#include <hooks/hooks_manager.h>
+#include <iostream>
+
using namespace std;
using namespace isc::hooks;
using namespace isc::asiolink;
}
virtual ~HookAllocEngine6Test() {
+ resetCalloutBuffers();
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
"lease6_select");
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ cerr << "(fixture dtor) unloadLibraries failed" << endl;
+ }
}
/// @brief clears out buffers, so callouts can store received arguments
// Initialize Hooks Manager
HookLibsCollection libraries; // no libraries at this time
- HooksManager::loadLibraries(libraries);
+ ASSERT_NO_THROW(HooksManager::loadLibraries(libraries));
// Install lease6_select
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
// Initialize Hooks Manager
HookLibsCollection libraries; // no libraries at this time
- HooksManager::loadLibraries(libraries);
+ ASSERT_NO_THROW(HooksManager::loadLibraries(libraries));
// Install a callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
// Initialize Hooks Manager
HookLibsCollection libraries; // no libraries at this time
- HooksManager::loadLibraries(libraries);
+ ASSERT_NO_THROW(HooksManager::loadLibraries(libraries));
// Install a callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
class HookAllocEngine4Test : public AllocEngine4Test {
public:
HookAllocEngine4Test() {
+ // The default context is not used in these tests.
+ ctx_.callout_handle_.reset();
resetCalloutBuffers();
}
virtual ~HookAllocEngine4Test() {
+ resetCalloutBuffers();
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
"lease4_select");
+ bool status = HooksManager::unloadLibraries();
+ if (!status) {
+ cerr << "(fixture dtor) unloadLibraries failed" << endl;
+ }
}
/// @brief clears out buffers, so callouts can store received arguments
// Initialize Hooks Manager
HookLibsCollection libraries; // no libraries at this time
- HooksManager::loadLibraries(libraries);
+ ASSERT_NO_THROW(HooksManager::loadLibraries(libraries));
// Install lease4_select
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
// Initialize Hooks Manager
HookLibsCollection libraries; // no libraries at this time
- HooksManager::loadLibraries(libraries);
+ ASSERT_NO_THROW(HooksManager::loadLibraries(libraries));
// Install a callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
// Initialize Hooks Manager
HookLibsCollection libraries; // no libraries at this time
- HooksManager::loadLibraries(libraries);
+ ASSERT_NO_THROW(HooksManager::loadLibraries(libraries));
// Install a callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
checkCalloutHandleReset(ctx.query_);
}
-}; // namespace test
-}; // namespace dhcp
-}; // namespace isc
+} // namespace test
+} // namespace dhcp
+} // namespace isc
bool
HooksManager::unloadLibrariesInternal() {
+ if (test_mode_) {
+ return (true);
+ }
+
ServerHooks::getServerHooks().getParkingLotsPtr()->clear();
// Keep a weak pointer on the existing library manager collection.
void
HooksManager::prepareUnloadLibrariesInternal() {
+ if (test_mode_) {
+ return;
+ }
+
static_cast<void>(lm_collection_->prepareUnloadLibraries());
}
// ... and check that the pre- and post- callout functions don't survive a
// reload.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
EXPECT_TRUE(HooksManager::loadLibraries(library_names));
handle = HooksManager::createCalloutHandle();
// ... and check that the pre- and post- callout functions survive a
// reload.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
EXPECT_TRUE(HooksManager::loadLibraries(library_names));
handle = HooksManager::createCalloutHandle();
// ... and check that the pre- and post- callout functions don't survive a
// reload.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
EXPECT_TRUE(HooksManager::loadLibraries(library_names));
handle = HooksManager::createCalloutHandle();
// ... and check that the pre- and post- callout functions don't survive a
// reload.
+ EXPECT_NO_THROW(HooksManager::prepareUnloadLibraries());
+ bool status = false;
+ EXPECT_NO_THROW(status = HooksManager::unloadLibraries());
+ EXPECT_TRUE(status);
EXPECT_TRUE(HooksManager::loadLibraries(library_names));
handle = HooksManager::createCalloutHandle();