]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1127] never update lm_collection_ outside init functions
authorRazvan Becheriu <razvan@isc.org>
Wed, 13 May 2020 08:05:01 +0000 (11:05 +0300)
committerRazvan Becheriu <razvan@isc.org>
Fri, 15 May 2020 18:21:41 +0000 (21:21 +0300)
src/bin/dhcp4/tests/hooks_unittest.cc
src/bin/dhcp6/tests/hooks_unittest.cc
src/lib/hooks/hooks_manager.cc
src/lib/hooks/hooks_manager.h
src/lib/hooks/library_manager_collection.cc
src/lib/hooks/library_manager_collection.h
src/lib/hooks/tests/hooks_manager_unittest.cc
src/lib/hooks/tests/library_manager_collection_unittest.cc

index 4e3d0ae858e6477665f4cdacaab58f6f34a9a10e..9c4203e3316a5129352bd8d0f28a71391c066cc7 100644 (file)
@@ -129,7 +129,7 @@ public:
         HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_decline");
         HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("host4_identifier");
 
-        HooksManager::getSharedCalloutManager().reset();
+        HooksManager::getHooksManager().setSharedCalloutManager();
         delete srv_;
     }
 
@@ -2378,7 +2378,8 @@ TEST_F(HooksDhcpv4SrvTest, HooksDecline) {
     IfaceMgr::instance().openSockets4();
 
     // Libraries will be reloaded later
-    HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
+    HooksManager::getHooksManager().setSharedCalloutManager(
+        boost::shared_ptr<CalloutManager>(new CalloutManager(0)));
 
     // Install a callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -2430,7 +2431,8 @@ TEST_F(HooksDhcpv4SrvTest, HooksDeclineSkip) {
     IfaceMgr::instance().openSockets4();
 
     // Libraries will be reloaded later
-    HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
+    HooksManager::getHooksManager().setSharedCalloutManager(
+        boost::shared_ptr<CalloutManager>(new CalloutManager(0)));
 
     // Install a callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -2481,7 +2483,8 @@ TEST_F(HooksDhcpv4SrvTest, HooksDeclineDrop) {
     IfaceMgr::instance().openSockets4();
 
     // Libraries will be reloaded later
-    HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
+    HooksManager::getHooksManager().setSharedCalloutManager(
+        boost::shared_ptr<CalloutManager>(new CalloutManager(0)));
 
     // Install a callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
index e6ff78b28ae29dd554068c85b8ea085328b37502..11a2d0face2790d53fba402985833473e495dbd2 100644 (file)
@@ -138,7 +138,7 @@ public:
     ~HooksDhcpv6SrvTest() {
 
         // Clear shared manager
-        HooksManager::getSharedCalloutManager().reset();
+        HooksManager::getHooksManager().setSharedCalloutManager();
 
     }
 
@@ -4418,7 +4418,8 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Decline) {
     IfaceMgrTestConfig test_config(true);
 
     // Libraries will be reloaded later
-    HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
+    HooksManager::getHooksManager().setSharedCalloutManager(
+        boost::shared_ptr<CalloutManager>(new CalloutManager(0)));
 
     // Install lease6_decline callout
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -4471,7 +4472,8 @@ TEST_F(HooksDhcpv6SrvTest, lease6DeclineSkip) {
     IfaceMgrTestConfig test_config(true);
 
     // Libraries will be reloaded later
-    HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
+    HooksManager::getHooksManager().setSharedCalloutManager(
+        boost::shared_ptr<CalloutManager>(new CalloutManager(0)));
 
     // Install lease6_decline_skip callout. It will set the status to skip
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
@@ -4521,7 +4523,8 @@ TEST_F(HooksDhcpv6SrvTest, lease6DeclineDrop) {
     IfaceMgrTestConfig test_config(true);
 
     // Libraries will be reloaded later
-    HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
+    HooksManager::getHooksManager().setSharedCalloutManager(
+        boost::shared_ptr<CalloutManager>(new CalloutManager(0)));
 
     // Install lease6_decline_drop callout. It will set the status to drop
     EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
index 3056ef784722c9f169508a4b9f68e70d18e8e00f..5e7d36bff68af0c0a8d4c6a435230261a4dd34f4 100644 (file)
@@ -26,7 +26,8 @@ namespace hooks {
 
 // Constructor
 
-HooksManager::HooksManager() {
+HooksManager::HooksManager() : loaded_(false) {
+    init();
 }
 
 // Return reference to singleton hooks manager.
@@ -41,7 +42,6 @@ HooksManager::getHooksManager() {
 
 bool
 HooksManager::calloutsPresentInternal(int index) {
-    conditionallyInitialize();
     return (callout_manager_->calloutsPresent(index));
 }
 
@@ -52,7 +52,6 @@ HooksManager::calloutsPresent(int index) {
 
 bool
 HooksManager::commandHandlersPresentInternal(const std::string& command_name) {
-    conditionallyInitialize();
     return (callout_manager_->commandHandlersPresent(command_name));
 }
 
@@ -65,7 +64,6 @@ HooksManager::commandHandlersPresent(const std::string& command_name) {
 
 void
 HooksManager::callCalloutsInternal(int index, CalloutHandle& handle) {
-    conditionallyInitialize();
     callout_manager_->callCallouts(index, handle);
 }
 
@@ -77,7 +75,6 @@ HooksManager::callCallouts(int index, CalloutHandle& handle) {
 void
 HooksManager::callCommandHandlersInternal(const std::string& command_name,
                                           CalloutHandle& handle) {
-    conditionallyInitialize();
     callout_manager_->callCommandHandlers(command_name, handle);
 }
 
@@ -87,17 +84,17 @@ HooksManager::callCommandHandlers(const std::string& command_name,
     getHooksManager().callCommandHandlersInternal(command_name, handle);
 }
 
-
 // Load the libraries.  This will delete the previously-loaded libraries
-// (if present) and load new ones.
+// (if present) and load new ones. If loading libraries fails, initialize with
+// empty list.
 
 bool
 HooksManager::loadLibrariesInternal(const HookLibsCollection& libraries) {
     // Unload current set of libraries (if any are loaded).
-    unloadLibrariesInternal();
+    unloadLibrariesInternal(false);
 
     // Create the library manager and load the libraries.
-    lm_collection_.reset(new LibraryManagerCollection(libraries));
+    lm_collection_.reset(new LibraryManagerCollection(libraries, shared_callout_manager_));
     bool status = lm_collection_->loadLibraries();
 
     if (status) {
@@ -106,10 +103,11 @@ HooksManager::loadLibrariesInternal(const HookLibsCollection& libraries) {
     } else {
         // Unable to load libraries, reset to state before this function was
         // called.
-        lm_collection_.reset();
-        callout_manager_.reset();
+        init();
     }
 
+    loaded_ = true;
+
     return (status);
 }
 
@@ -118,19 +116,21 @@ HooksManager::loadLibraries(const HookLibsCollection& libraries) {
     return (getHooksManager().loadLibrariesInternal(libraries));
 }
 
-// Unload the libraries.  This just deletes all internal objects which will
-// cause the libraries to be unloaded.
+// Unload the libraries.  This just deletes all internal objects (which will
+// cause the libraries to be unloaded) and initializes them with empty list if
+// requested.
 
 void
-HooksManager::unloadLibrariesInternal() {
-    // The order of deletion does not matter here, as each library manager
-    // holds its own pointer to the callout manager.  However, we may as
-    // well delete the library managers first: if there are no other references
-    // to the callout manager, the second statement will delete it, which may
-    // ease debugging.
-    lm_collection_.reset();
-    callout_manager_.reset();
+HooksManager::unloadLibrariesInternal(bool initialize) {
     ServerHooks::getServerHooks().getParkingLotsPtr()->clear();
+    if (initialize) {
+        init();
+    } else {
+        lm_collection_.reset();
+        callout_manager_.reset();
+    }
+
+    loaded_ = false;
 }
 
 void HooksManager::unloadLibraries() {
@@ -141,9 +141,7 @@ void HooksManager::unloadLibraries() {
 
 boost::shared_ptr<CalloutHandle>
 HooksManager::createCalloutHandleInternal() {
-    conditionallyInitialize();
-    return (boost::shared_ptr<CalloutHandle>(
-            new CalloutHandle(callout_manager_, lm_collection_)));
+    return (boost::make_shared<CalloutHandle>(callout_manager_, lm_collection_));
 }
 
 boost::shared_ptr<CalloutHandle>
@@ -155,14 +153,12 @@ HooksManager::createCalloutHandle() {
 
 std::vector<std::string>
 HooksManager::getLibraryNamesInternal() const {
-    return (lm_collection_ ? lm_collection_->getLibraryNames()
-                           : std::vector<std::string>());
+    return (lm_collection_->getLibraryNames());
 }
 
 HookLibsCollection
 HooksManager::getLibraryInfoInternal() const {
-    return (lm_collection_ ? lm_collection_->getLibraryInfo()
-            : HookLibsCollection());
+    return (lm_collection_->getLibraryInfo());
 }
 
 std::vector<std::string>
@@ -175,17 +171,15 @@ HooksManager::getLibraryInfo() {
     return (getHooksManager().getLibraryInfoInternal());
 }
 
-// Perform conditional initialization if nothing is loaded.
+// Perform initialization
 
 void
-HooksManager::performConditionalInitialization() {
-
+HooksManager::init() {
     // Nothing present, so create the collection with any empty set of
     // libraries, and get the CalloutManager.
     HookLibsCollection libraries;
-    lm_collection_.reset(new LibraryManagerCollection(libraries));
+    lm_collection_.reset(new LibraryManagerCollection(libraries, shared_callout_manager_));
     lm_collection_->loadLibraries();
-
     callout_manager_ = lm_collection_->getCalloutManager();
 }
 
@@ -200,7 +194,6 @@ HooksManager::registerHook(const std::string& name) {
 
 isc::hooks::LibraryHandle&
 HooksManager::preCalloutsLibraryHandleInternal() {
-    conditionallyInitialize();
     return (callout_manager_->getPreLibraryHandle());
 }
 
@@ -211,7 +204,6 @@ HooksManager::preCalloutsLibraryHandle() {
 
 isc::hooks::LibraryHandle&
 HooksManager::postCalloutsLibraryHandleInternal() {
-    conditionallyInitialize();
     return (callout_manager_->getPostLibraryHandle());
 }
 
@@ -227,10 +219,17 @@ HooksManager::validateLibraries(const std::vector<std::string>& libraries) {
     return (LibraryManagerCollection::validateLibraries(libraries));
 }
 
-// Shared callout manager
-boost::shared_ptr<CalloutManager>&
+boost::shared_ptr<CalloutManager>
 HooksManager::getSharedCalloutManager() {
-    return (getHooksManager().shared_callout_manager_);
+    return (shared_callout_manager_);
+}
+
+void
+HooksManager::setSharedCalloutManager(boost::shared_ptr<CalloutManager> manager) {
+    shared_callout_manager_ = manager;
+    if (!loaded_) {
+        init();
+    }
 }
 
 } // namespace util
index 903ad6aa6e091ac239a0dfb16c13d7a0a12e04ab..ecb050ca3c1114b0849b3f8180b511a09cb500cb 100644 (file)
@@ -226,13 +226,20 @@ public:
     static const int CONTEXT_CREATE = ServerHooks::CONTEXT_CREATE;
     static const int CONTEXT_DESTROY = ServerHooks::CONTEXT_DESTROY;
 
-    /// @brief Return the shared callout manager
-    ///
-    /// Declared as static as other methods but only one for the
-    /// singleton will be created.
+    /// @brief Get the shared callout manager
     ///
     /// @return A reference to the shared callout manager
-    static boost::shared_ptr<CalloutManager>& getSharedCalloutManager();
+    boost::shared_ptr<CalloutManager> getSharedCalloutManager();
+
+    /// @brief Set the shared callout manager
+    ///
+    /// This function sets the shared callout manager and explicitly updates
+    /// @ref callout_manager_ (by calling @ref init) if @ref loadLibraries has
+    /// not yet been called.
+    ///
+    /// @param manager The shared callout manager
+    void setSharedCalloutManager(boost::shared_ptr<CalloutManager> manager =
+                                 boost::shared_ptr<CalloutManager>());
 
     /// @brief Park an object (packet).
     ///
@@ -411,7 +418,10 @@ private:
     bool loadLibrariesInternal(const HookLibsCollection& libraries);
 
     /// @brief Unload libraries
-    void unloadLibrariesInternal();
+    ///
+    /// @param initialize flag to indicate if intializing or just resetting the
+    /// @ref lm_collection_ and @ref callout_manager_
+    void unloadLibrariesInternal(bool initialize = true);
 
     /// @brief Are callouts present?
     ///
@@ -479,29 +489,8 @@ private:
 
     /// @brief Initialization to No Libraries
     ///
-    /// Initializes the hooks manager with an "empty set" of libraries.  This
-    /// method is called if conditionallyInitialize() determines that such
-    /// initialization is needed.
-    void performConditionalInitialization();
-
-    /// @brief Conditional initialization of the  hooks manager
-    ///
-    /// loadLibraries() performs the initialization of the HooksManager,
-    /// setting up the internal structures and loading libraries.  However,
-    /// in some cases, server authors may not do that.  This method is called
-    /// whenever any hooks execution function is invoked (checking callouts,
-    /// calling callouts or returning a callout handle).  If the HooksManager
-    /// is uninitialized, it will initialize it with an "empty set"
-    /// of libraries.
-    ///
-    /// For speed, the test of whether initialization is required is done
-    /// in-line here.  The actual initialization is performed in
-    /// performConditionalInitialization().
-    void conditionallyInitialize() {
-        if (!lm_collection_) {
-            performConditionalInitialization();
-        }
-    }
+    /// Initializes the hooks manager with an "empty set" of libraries.
+    void init();
 
     // Members
 
@@ -514,6 +503,8 @@ private:
     /// Shared callout manager to survive library reloads.
     boost::shared_ptr<CalloutManager> shared_callout_manager_;
 
+    /// Loaded flag to indicate if @ref loadLibraries has been called
+    bool loaded_;
 };
 
 } // namespace util
index e814ac7f3a1350123183c8361d092b9d6c8da3c1..17ee10ad03a8a2f4130a31bc75d61f21e8147226 100644 (file)
@@ -7,7 +7,6 @@
 #include <config.h>
 
 #include <hooks/callout_manager.h>
-#include <hooks/hooks_manager.h>
 #include <hooks/library_manager.h>
 #include <hooks/library_manager_collection.h>
 
@@ -29,7 +28,7 @@ boost::shared_ptr<CalloutManager>
 LibraryManagerCollection::getCalloutManager() const {
 
     // Only return a pointer if we have a CalloutManager created.
-    if (! callout_manager_) {
+    if (!callout_manager_) {
         isc_throw(LoadLibrariesNotCalled, "must load hooks libraries before "
                   "attempting to retrieve a CalloutManager for them");
     }
@@ -37,8 +36,9 @@ LibraryManagerCollection::getCalloutManager() const {
     return (callout_manager_);
 }
 
-LibraryManagerCollection::LibraryManagerCollection(const HookLibsCollection& libraries)
-    :library_info_(libraries) {
+LibraryManagerCollection::LibraryManagerCollection(const HookLibsCollection& libraries,
+        const boost::shared_ptr<CalloutManager>& manager)
+    : shared_callout_manager_(manager), library_info_(libraries) {
 
     // We need to split hook libs into library names and library parameters.
     for (HookLibsCollection::const_iterator it = libraries.begin();
@@ -78,7 +78,7 @@ LibraryManagerCollection::loadLibraries() {
     // to re-use the existing callout manager (so retaining registered pre-
     // and post-library callouts).
     if (library_names_.empty()) {
-        callout_manager_ = HooksManager::getSharedCalloutManager();
+        callout_manager_ = shared_callout_manager_;
     }
     if (!library_names_.empty() || !callout_manager_) {
         callout_manager_.reset(new CalloutManager(library_names_.size()));
index df52649ecbeae8310392858adad0ee74819b9872..f1b481b81359ab28c578cdf2575e07762c4fc6ae 100644 (file)
@@ -8,6 +8,7 @@
 #define LIBRARY_MANAGER_COLLECTION_H
 
 #include <exceptions/exceptions.h>
+#include <hooks/hooks_manager.h>
 
 #include <boost/shared_ptr.hpp>
 #include <hooks/libinfo.h>
@@ -74,7 +75,9 @@ public:
     /// @param libraries List of libraries that this collection will manage.
     ///        The order of the libraries is important. It holds the library
     ///        names and its configuration parameters.
-    LibraryManagerCollection(const HookLibsCollection& libraries);
+    LibraryManagerCollection(const HookLibsCollection& libraries,
+                             const boost::shared_ptr<CalloutManager>& manager =
+                             HooksManager::getHooksManager().getSharedCalloutManager());
 
     /// @brief Destructor
     ///
@@ -152,6 +155,8 @@ protected:
     void unloadLibraries();
 
 private:
+    /// Shared Callout manager to be associated with the libraries
+    boost::shared_ptr<CalloutManager>               shared_callout_manager_;
 
     /// Vector of library names
     std::vector<std::string>                        library_names_;
index 8d5eff104ead82008d8f7794f4cb0155e87f7fb7..44b39cb6c7105a59e6ac6b397fe49d3842ddbe6c 100644 (file)
@@ -46,7 +46,7 @@ public:
     /// Unload all libraries and reset the shared manager.
     ~HooksManagerTest() {
         HooksManager::unloadLibraries();
-        HooksManager::getSharedCalloutManager().reset();
+        HooksManager::getHooksManager().setSharedCalloutManager();
     }
 
 
@@ -445,7 +445,8 @@ TEST_F(HooksManagerTest, PrePostCalloutShared) {
     HookLibsCollection library_names;
 
     // Initialize the shared manager.
-    HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
+    HooksManager::getHooksManager().setSharedCalloutManager(
+        boost::shared_ptr<CalloutManager>(new CalloutManager(0)));
 
     // Load the pre- and post- callouts.
     HooksManager::preCalloutsLibraryHandle().registerCallout("hookpt_two",
@@ -492,7 +493,8 @@ TEST_F(HooksManagerTest, PrePostCalloutSharedNotEmpty) {
                                       data::ConstElementPtr()));
 
     // Initialize the shared manager.
-    HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
+    HooksManager::getHooksManager().setSharedCalloutManager(
+        boost::shared_ptr<CalloutManager>(new CalloutManager(0)));
 
     // Load the pre- and post- callouts.
     HooksManager::preCalloutsLibraryHandle().registerCallout("hookpt_two",
@@ -538,7 +540,8 @@ TEST_F(HooksManagerTest, PrePostCalloutSharedTooLate) {
     EXPECT_TRUE(HooksManager::loadLibraries(library_names));
 
     // Initialize the shared manager (after loadLibraries so too late)
-    HooksManager::getSharedCalloutManager().reset(new CalloutManager(0));
+    HooksManager::getHooksManager().setSharedCalloutManager(
+        boost::shared_ptr<CalloutManager>(new CalloutManager(0)));
 
     // Load the pre- and post- callouts.
     HooksManager::preCalloutsLibraryHandle().registerCallout("hookpt_two",
index 6ace663abd404f59b297f394b7a79eafffc91498..6066c6e58a3f266c672f6cc39a097ee37ddc9969 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <hooks/callout_handle.h>
 #include <hooks/callout_manager.h>
+#include <hooks/hooks_manager.h>
 #include <hooks/library_manager.h>
 #include <hooks/library_manager_collection.h>
 #include <hooks/libinfo.h>
@@ -46,27 +47,33 @@ private:
     }
 };
 
+} // namespace
+
+namespace isc {
+namespace hooks {
 /// @brief Public library manager collection class
 ///
 /// This is an instance of the LibraryManagerCollection class but with the
 /// protected methods made public for test purposes.
 
-class PublicLibraryManagerCollection
-                : public isc::hooks::LibraryManagerCollection {
+class PublicLibraryManagerCollection : public LibraryManagerCollection {
 public:
     /// @brief Constructor
     ///
     /// @param List of libraries that this collection will manage.  The order
     ///        of the libraries is important.
     PublicLibraryManagerCollection(const HookLibsCollection& libraries)
-        : LibraryManagerCollection(libraries)
-    {}
+        : LibraryManagerCollection(libraries) {
+    }
 
     /// Public methods that call protected methods on the superclass.
     using LibraryManagerCollection::unloadLibraries;
 };
 
+} // namespace hooks
+} // namespace isc
 
+namespace {
 // This is effectively the same test as for LibraryManager, but using the
 // LibraryManagerCollection object.