diff options
Diffstat (limited to 'src/lib/hooks/library_manager_collection.h')
-rw-r--r-- | src/lib/hooks/library_manager_collection.h | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/lib/hooks/library_manager_collection.h b/src/lib/hooks/library_manager_collection.h new file mode 100644 index 0000000..53a9669 --- /dev/null +++ b/src/lib/hooks/library_manager_collection.h @@ -0,0 +1,187 @@ +// Copyright (C) 2013-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 +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef LIBRARY_MANAGER_COLLECTION_H +#define LIBRARY_MANAGER_COLLECTION_H + +#include <exceptions/exceptions.h> + +#include <boost/shared_ptr.hpp> +#include <hooks/libinfo.h> + +#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 closed 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 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. +/// +/// The collection object also provides a utility function to validate a set +/// of libraries. The function checks that each library exists, can be opened, +/// that the "version" function exists and return the right number. + +class LibraryManagerCollection { +public: + /// @brief Constructor + /// + /// @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); + + /// @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 loading is abandoned and all libraries loaded so far + /// are unloaded. + /// + /// @return true if all libraries loaded, false if one or more failed t + //// load. + 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 called 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; + + /// @brief Get library names + /// + /// Returns the list of library names. If called before loadLibraries(), + /// the list is the list of names to be loaded; if called afterwards, it + /// is the list of libraries that have been loaded. + std::vector<std::string> getLibraryNames() const { + return (library_names_); + } + + /// @brief Returns library info + /// + /// Returns a collection of libraries, each entry consisting of a library + /// name + all its parameters. + HookLibsCollection getLibraryInfo() const { + return (library_info_); + } + + /// @brief Get number of loaded libraries + /// + /// Mainly for testing, this returns the number of libraries that are + /// loaded. + /// + /// @return Number of libraries that are loaded. + int getLoadedLibraryCount() const; + + /// @brief Validate libraries + /// + /// Utility function to validate libraries. It checks that the libraries + /// exist, can be opened, that a "version" function is present in them, and + /// that it returns the right number. All errors are logged. + /// + /// @param libraries List of libraries to validate + /// + /// @return Vector of libraries that failed to validate, or an empty vector + /// if all validated. + static std::vector<std::string> + validateLibraries(const std::vector<std::string>& libraries); + + /// @brief Prepare libaries unloading + /// + /// Utility function to call before closing libraries. It runs the + /// unload() function when it exists and removes associated callout. + /// When this function returns either there is only one owner + /// (the hook manager) or some visible dangling pointers so + /// libraries are not closed to lower the probability of a crash. + /// See @ref LibraryManager::prepareUnloadLibrary. + /// + /// @return true if all libraries unload were not found or run + /// successfully, false on an error. + bool prepareUnloadLibraries(); + +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_; + + /// Vector of library information. Each piece of information + /// consists of a pair of (library name, library parameters) + HookLibsCollection library_info_; + + /// Callout manager to be associated with the libraries + boost::shared_ptr<CalloutManager> callout_manager_; +}; + +} // namespace hooks +} // namespace isc + + +#endif // LIBRARY_MANAGER_COLLECTION_H |