Browse Source

[2980] Added missing LibraryManagerCollection files to the repository

Stephen Morris 12 years ago
parent
commit
2bde65105b
2 changed files with 247 additions and 0 deletions
  1. 114 0
      src/lib/hooks/library_manager_collection.cc
  2. 133 0
      src/lib/hooks/library_manager_collection.h

+ 114 - 0
src/lib/hooks/library_manager_collection.cc

@@ -0,0 +1,114 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <hooks/callout_manager.h>
+#include <hooks/library_manager.h>
+#include <hooks/library_manager_collection.h>
+
+namespace isc {
+namespace hooks {
+
+// Return callout manager for the loaded libraries.  This call is only valid
+// after one has been created for the loaded libraries (which includes the
+// case of no loaded libraries).
+//
+// Note that there is no real connection between the callout manager and the
+// libraries, other than it knows the number of libraries so can do sanity
+// checks on values passed to it.  However, this may change in the future,
+// so the hooks framework is written such that a callout manager is used only
+// with the LibraryManagerCollection that created it.  It is also the reason
+// why each LibraryManager contains a pointer to this CalloutManager.
+
+boost::shared_ptr<CalloutManager>
+LibraryManagerCollection::getCalloutManager() const {
+
+    // Only return a pointer if we have a CalloutManager created.
+    if (! callout_manager_) {
+        isc_throw(LoadLibrariesNotCalled, "must load hooks libraries before "
+                  "attempting to retrieve a CalloutManager for them");
+    }
+
+    return (callout_manager_);
+}
+
+// Load a set of libraries
+
+bool
+LibraryManagerCollection::loadLibraries() {
+
+    // Unload libraries if any are loaded.
+    static_cast<void>(unloadLibraries());
+
+    // Create the callout manager.  A pointer to this is maintained by
+    // each library.  Note that the callout manager does not hold any memory
+    // allocated by a library: although a library registers a callout (and so
+    // causes the creation of an entry in the CalloutManager's callout list),
+    // that creation is done by the CalloutManager itself.  The CalloutManager
+    // is created within the server.
+    //
+    // The upshot of this is that it is therefore safe for the CalloutManager
+    // to be deleted after all associated libraries are deleted, hence this
+    // link (LibraryManager -> CalloutManager) is safe.
+    callout_manager_.reset(new CalloutManager(library_names_.size()));
+
+    // Now iterate through the libraries are load them one by one.  We'll
+    for (int i = 0; i < library_names_.size(); ++i) {
+        // Create a pointer to the new library manager.  The index of this
+        // library is determined by the number of library managers currently
+        // loaded: note that the library indexes run from 1 to (number of loaded
+        // libraries).
+        boost::shared_ptr<LibraryManager> manager(
+                new LibraryManager(library_names_[i], lib_managers_.size() + 1,
+                                   callout_manager_));
+
+        // Load the library.  On success, add it to the list of loaded
+        // libraries.  On failure, an error will have been logged and the
+        // library closed.
+        if (manager->loadLibrary()) {
+            lib_managers_.push_back(manager);
+        }
+    }
+
+    // Update the CalloutManager's idea of the number of libraries it is
+    // handling.
+    callout_manager_->setNumLibraries(lib_managers_.size());
+
+    // Get an indication of whether all libraries loaded successfully.
+    bool status = (library_names_.size() == lib_managers_.size());
+
+    // Don't need the library names any more, so free up the space.
+    library_names_.clear();
+
+    return (status);
+}
+
+// Unload the libraries.
+
+void
+LibraryManagerCollection::unloadLibraries() {
+
+    // Delete the library managers in the reverse order to which they were
+    // created, then clear the library manager vector.
+    for (int i = lib_managers_.size() - 1; i >= 0; --i) {
+        lib_managers_[i].reset();
+    }
+    lib_managers_.clear();
+
+    // Get rid of the callout manager. (The other member, the list of library
+    // names, was cleared when the libraries were loaded.)
+    callout_manager_.reset();
+}
+
+} // namespace hooks
+} // namespace isc

+ 133 - 0
src/lib/hooks/library_manager_collection.h

@@ -0,0 +1,133 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef LIBRARY_MANAGER_COLLECTION_H
+#define LIBRARY_MANAGER_COLLECTION_H
+
+#include <exceptions/exceptions.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+
+namespace isc {
+namespace hooks {
+
+/// @brief LoadLibraries not called
+///
+/// Thrown if an attempt is made get a CalloutManager before the libraries
+/// have been loaded.
+class LoadLibrariesNotCalled : public Exception {
+public:
+    LoadLibrariesNotCalled(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+
+// Forward declarations
+class CalloutManager;
+class LibraryManager;
+
+/// @brief Library manager collection
+///
+/// The LibraryManagerCollection class, as the name implies, is responsible for
+/// managing the collection of LibraryManager objects that describe the loaded
+/// libraries.  As such, it converts a single operation (e.g load libraries)
+/// into multiple operations, one per library.  However, the class does more
+/// than that - it provides a single object with which to manage lifetimes.
+///
+/// As described in the LibraryManager documentation, a CalloutHandle may end
+/// up with pointers to memory within the address space of a loaded library.
+/// If the library is unloaded before this address space is deleted, the
+/// deletion of the CalloutHandle may attempt to free memory into the newly-
+/// unmapped address space and cause a segmentation fault.
+///
+/// To prevent this, each CalloutHandle maintains a shared pointer to the
+/// LibraryManagerCollection current when it was created.  In addition, the
+/// containing HooksManager object also maintains a shared pointer to it.  A
+/// a LibraryManagerCollection is never explicitly deleted: when a new set
+/// of libraries is loaded, the HooksManager clears its pointer to the
+/// collection.  The LibraryManagerCollection is only destroyed when all
+/// CallHandle objects referencing it are destroyed.
+///
+/// Note that this does not completely solve the problem - a hook function may
+/// have modified a packet being processed by the server and that packet may
+/// hold a pointer to memory in the library's virtual address space. To avoid
+/// a segmentation fault, that packet needs to free the memory before the
+/// LibraryManagerCollection is destroyed and this places demands on the server
+/// code.  However, the link with the CalloutHandle does at least mean that
+/// authors of server code do not need to be so careful about when they destroy
+/// CalloutHandles.
+
+class LibraryManagerCollection {
+public:
+    /// @brief Constructor
+    ///
+    /// @param List of libraries that this collection will manage.  The order
+    ///        of the libraries is important.
+    LibraryManagerCollection(const std::vector<std::string>& libraries)
+        : library_names_(libraries)
+    {}
+
+    /// @brief Destructor
+    ///
+    /// Unloads all loaded libraries.
+    ~LibraryManagerCollection() {
+        static_cast<void>(unloadLibraries());
+    }
+
+    /// @brief Load libraries
+    ///
+    /// Loads the libraries.  This creates the LibraryManager associated with
+    /// each library and calls its loadLibrary() method.  If a library fails
+    /// to load, the fact is noted but attempts are made to load the remaining
+    /// libraries.
+    bool loadLibraries();
+
+    /// @brief Get callout manager
+    ///
+    /// Returns a callout manager that can be used with this set of loaded
+    /// libraries (even if the number of loaded libraries is zero).  This
+    /// method may only be caslled after loadLibraries() has been called.
+    ///
+    /// @return Pointer to a callout manager for this set of libraries.
+    ///
+    /// @throw LoadLibrariesNotCalled Thrown if this method is called between
+    ///        construction and the time loadLibraries() is called.
+    boost::shared_ptr<CalloutManager> getCalloutManager() const;
+
+protected:
+    /// @brief Unload libraries
+    ///
+    /// Unloads and closes all loaded libraries.  They are unloaded in the
+    /// reverse order to the order in which they were loaded.
+    void unloadLibraries();
+
+private:
+
+    /// Vector of library names
+    std::vector<std::string>                        library_names_;
+
+    /// Vector of library managers
+    std::vector<boost::shared_ptr<LibraryManager> > lib_managers_;
+
+    /// Callout manager to be associated with the libraries
+    boost::shared_ptr<CalloutManager>               callout_manager_;
+};
+
+} // namespace hooks
+} // namespace isc
+
+
+#endif // LIBRARY_MANAGER_COLLECTION_H