diff options
Diffstat (limited to 'src/lib/hooks/library_manager.h')
-rw-r--r-- | src/lib/hooks/library_manager.h | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/src/lib/hooks/library_manager.h b/src/lib/hooks/library_manager.h new file mode 100644 index 0000000..84c5d82 --- /dev/null +++ b/src/lib/hooks/library_manager.h @@ -0,0 +1,253 @@ +// Copyright (C) 2013-2023 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_H +#define LIBRARY_MANAGER_H + +#include <exceptions/exceptions.h> +#include <hooks/server_hooks.h> +#include <boost/shared_ptr.hpp> + +#include <string> + +namespace isc { +namespace hooks { + +/// @brief No Callout Manager +/// +/// Thrown if a library manager is instantiated by an external agency without +/// specifying a CalloutManager object. +class NoCalloutManager : public Exception { +public: + NoCalloutManager(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +class CalloutManager; +class LibraryHandle; +class LibraryManager; + +/// @brief Library manager +/// +/// This class handles the loading and unloading of a specific library. It also +/// provides a static method for checking that a library is valid (this is used +/// in configuration parsing). +/// +/// On loading, it opens the library using dlopen and checks the version (set +/// with the "version" method. If all is OK, it iterates through the list of +/// known hooks and locates their symbols, registering each callout as it does +/// so. Finally it locates the "load" function (if present) and calls it. +/// +/// On unload, it clears the callouts on all hooks, calls the "unload" +/// method if present, clears the callouts on all hooks, and +/// closes the library. +/// +/// @note Caution needs to be exercised when using the close method. During +/// normal use, data will pass between the server and the library. In +/// this process, the library may allocate memory and pass it back to the +/// server. This could happen by the server setting arguments or context +/// in the CalloutHandle object, or by the library modifying the content +/// of pointed-to data. If the library is closed, this memory may lie +/// in the virtual address space deleted in that process. (The word "may" +/// is used, as this could be operating-system specific.) Should this +/// happen, any reference to the memory will cause a segmentation fault. +/// This can occur in a quite obscure place, for example in the middle of +/// a destructor of an STL class when it is deleting memory allocated +/// when the data structure was extended by a function in the library. +/// +/// @note The only safe way to run the "close" function is to ensure that all +/// possible references to it are removed first. This means that all +/// CalloutHandles must be destroyed, as must any data items that were +/// passed to the callouts. In practice, it could mean that a server +/// suspends processing of new requests until all existing ones have +/// been serviced and all packet/context structures destroyed before +/// reloading the libraries. +/// +/// When validating a library, only the fact that the library can be opened and +/// version() exists and returns the correct number is checked. The library +/// is closed after the validation. + +class LibraryManager { +public: + /// @brief Constructor + /// + /// This constructor is used by external agencies (i.e. the + /// LibraryManagerCollection) when instantiating a LibraryManager. It + /// stores the library name - the actual actual loading is done in + /// loadLibrary(). + /// + /// @param name Name of the library to load. This should be an absolute + /// path name. + /// @param index Index of this library + /// @param manager CalloutManager object + /// + /// @throw NoCalloutManager Thrown if the manager argument is NULL. + LibraryManager(const std::string& name, int index, + const boost::shared_ptr<CalloutManager>& manager); + + /// @brief Destructor + /// + /// If the library is open, closes it. This is principally a safety + /// feature to ensure closure in the case of an exception destroying this + /// object. However, see the caveat in the class header about when it is + /// safe to close libraries. + ~LibraryManager(); + + /// @brief Validate library + /// + /// A static method that is used to validate a library. Validation checks + /// that the library can be opened, that "version" exists, and that it + /// returns the right number, and the multi-threading compatibility. + /// + /// @param name Name of the library to validate + /// @param multi_threading_enabled The flag which indicates if MT is enabled + /// (used to check hook libraries compatibility with MT). + /// + /// @return true if the library validated, false if not. If the library + /// fails to validate, the reason for the failure is logged. + static bool validateLibrary(const std::string& name, + bool multi_threading_enabled = false); + + /// @brief Loads a library + /// + /// Open the library, check the version and the multi-threading + /// compatibility. If all is OK, load all standard symbols then + /// call "load" if present. + /// + /// It also calls the @c isc::log::MessageInitializer::loadDictionary, + /// prior to invoking the @c version function of the library, to + /// update the global logging dictionary with the log messages + /// registered by the loaded library. + /// + /// @param multi_threading_enabled The flag which indicates if MT is enabled + /// (used to check hook libraries compatibility with MT). + /// + /// @return true if the library loaded successfully, false otherwise. + /// In the latter case, the library will be unloaded if possible. + bool loadLibrary(bool multi_threading_enabled = false); + + /// @brief Prepares library unloading + /// + /// Searches for the "unload" framework function and, if present, runs it. + /// Regardless of status, remove all callouts associated with this + /// library on all hooks. + /// + /// @return bool true if not found or found and run successfully, + /// false on an error. In this case, an error message will + /// have been output. + bool prepareUnloadLibrary(); + + /// @brief Return library name + /// + /// @return Name of this library + std::string getName() const { + return (library_name_); + } + +protected: + // The following methods are protected as they are accessed in testing. + + /// @brief Unloads a library + /// + /// Calls the libraries "unload" function if present, the closes the + /// library. + /// + /// However, see the caveat in the class header about when it is safe to + /// unload libraries. + /// + /// @return true if the library unloaded successfully, false if an error + /// occurred in the process (most likely the unload() function + /// (if present) returned an error). Even if an error did occur, + /// the library is closed if possible. + bool unloadLibrary(); + + /// @brief Open library + /// + /// Opens the library associated with this LibraryManager. A message is + /// logged on an error. + /// + /// @return true if the library opened successfully, false otherwise. + bool openLibrary(); + + /// @brief Close library + /// + /// Closes the library associated with this LibraryManager. A message is + /// logged on an error. + /// + /// @return true if the library closed successfully, false otherwise. "true" + /// is also returned if the library were already closed when this + /// method was called. + bool closeLibrary(); + + /// @brief Check library version + /// + /// With the library open, accesses the "version()" function and, if + /// present, checks the returned value against the hooks version symbol + /// for the currently running Kea. The "version()" function is + /// mandatory and must be present (and return the correct value) for the + /// library to load. + /// + /// If there is no version() function, or if there is a mismatch in + /// version number, a message logged. + /// + /// @return bool true if the check succeeded + bool checkVersion() const; + + /// @brief Check multi-threading compatibility + /// + /// If the multi-threading mode is disabled returns true, else with + /// the library open, accesses the "multi_threading_compatible()" + /// function and returns false if not exists or has value 0, returns + /// true otherwise. + /// + /// @param multi_threading_enabled The flag which indicates if MT is enabled + /// (used to check hook libraries compatibility with MT). + /// + /// @return bool true if the check succeeded + bool checkMultiThreadingCompatible(bool multi_threading_enabled) const; + + /// @brief Register standard callouts + /// + /// Loops through the list of hook names and searches the library for + /// functions with those names. Any that are found are registered as + /// callouts for that hook. + void registerStandardCallouts(); + + /// @brief Run the load function if present + /// + /// Searches for the "load" framework function and, if present, runs it. + /// + /// @return bool true if not found or found and run successfully, + /// false on an error. In this case, an error message will + /// have been output. + bool runLoad(); + +private: + /// @brief Validating constructor + /// + /// Constructor used when the LibraryManager is instantiated to validate + /// a library (i.e. by the "validateLibrary" static method). + /// + /// @param name Name of the library to load. This should be an absolute + /// path name. + LibraryManager(const std::string& name); + + // Member variables + + void* dl_handle_; ///< Handle returned by dlopen + int index_; ///< Index associated with this library + boost::shared_ptr<CalloutManager> manager_; + ///< Callout manager for registration + std::string library_name_; ///< Name of the library + + ServerHooksPtr server_hooks_; ///< Stores a pointer to ServerHooks. + +}; + +} // namespace hooks +} // namespace isc + +#endif // LIBRARY_MANAGER_H |