summaryrefslogtreecommitdiffstats
path: root/src/lib/hooks/hooks_manager.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/hooks/hooks_manager.h')
-rw-r--r--src/lib/hooks/hooks_manager.h499
1 files changed, 499 insertions, 0 deletions
diff --git a/src/lib/hooks/hooks_manager.h b/src/lib/hooks/hooks_manager.h
new file mode 100644
index 0000000..647e14a
--- /dev/null
+++ b/src/lib/hooks/hooks_manager.h
@@ -0,0 +1,499 @@
+// Copyright (C) 2013-2021 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 HOOKS_MANAGER_H
+#define HOOKS_MANAGER_H
+
+#include <hooks/server_hooks.h>
+#include <hooks/libinfo.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace hooks {
+
+/// @brief Libraries still opened.
+///
+/// Thrown if an attempt is made to load libraries when some are still
+/// in memory likely because they were not unloaded (logic error in Kea)
+/// or they have some visible dangling pointers (logic error in a hook
+/// library).
+class LibrariesStillOpened : public Exception {
+public:
+ LibrariesStillOpened(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+// Forward declarations
+class CalloutHandle;
+class CalloutManager;
+class LibraryHandle;
+class LibraryManagerCollection;
+
+/// @brief Hooks Manager
+///
+/// This is the overall manager of the hooks framework and is the main class
+/// used by a Kea module when handling hooks. It is responsible for the
+/// loading and unloading of user libraries, and for calling the callouts on
+/// each hook point.
+///
+/// The class is a singleton, the single instance of the object being accessed
+/// through the static getHooksManager() method.
+
+class HooksManager : boost::noncopyable {
+public:
+
+ /// @brief Load and reload libraries
+ ///
+ /// Loads the list of libraries into the server address space. For each
+ /// library, the "standard" functions (ones with the same names as the
+ /// hook points) are configured and the libraries' "load" function
+ /// called.
+ ///
+ /// @note this method now requires the libraries are unloaded before
+ /// being called.
+ ///
+ /// If any library fails to load, an error message will be logged. The
+ /// remaining libraries will be loaded if possible.
+ ///
+ /// @param libraries List of libraries to be loaded. The order is
+ /// important, as it determines the order that callouts on the same
+ /// hook will be called.
+ ///
+ /// @return true if all libraries loaded without a problem, false if one or
+ /// more libraries failed to load. In the latter case, message will
+ /// be logged that give the reason.
+ /// @throw LibrariesStillOpened when some libraries are already loaded.
+ static bool loadLibraries(const HookLibsCollection& libraries);
+
+ /// @brief Unload libraries
+ ///
+ /// Unloads the loaded libraries and leaves the hooks subsystem in the
+ /// state it was after construction but before loadLibraries() is called.
+ ///
+ /// @note: This method should be called after @ref prepareUnloadLibraries
+ /// in order to destroy appropriate objects. See notes for
+ /// the class LibraryManager for pitfalls.
+ /// @note: if even after @ref prepareUnloadLibraries there are still
+ /// visible pointers (i.e. callout handles owning the
+ /// library manager collection) the method will fail to close
+ /// libraries and returns false. It is a fatal error as there
+ /// is no possible recovery. It is a logic error in the hook
+ /// code too so the solution is to fix it and to restart
+ /// the server with a correct hook library binary.
+ ///
+ /// @return true if all libraries unloaded successfully, false if they
+ /// are still in memory.
+ static bool unloadLibraries();
+
+ /// @brief Prepare the unloading of libraries
+ ///
+ /// Calls the unload functions when they exist and removes callouts.
+ ///
+ /// @note: after the call to this method there should be no visible
+ /// dangling pointers (i.e. callout handles owning the library
+ /// manager collection) nor invisible dangling pointers.
+ /// In the first case it will be impossible to close libraries
+ /// so they will remain in memory, in the second case a crash
+ /// is possible in particular at exit time during global
+ /// object finalization. In both cases the hook library code
+ /// causing the problem is incorrect and must be fixed.
+ /// @note: it is a logic error to not call this method before
+ /// @ref unloadLibraries even it hurts only with particular
+ /// hooks libraries.
+ static void prepareUnloadLibraries();
+
+ /// @brief Are callouts present?
+ ///
+ /// Checks loaded libraries and returns true if at lease one callout
+ /// has been registered by them for the given hook.
+ ///
+ /// @param index Hooks index for which callouts are checked.
+ ///
+ /// @return true if callouts are present, false if not.
+ /// @throw NoSuchHook Given index does not correspond to a valid hook.
+ static bool calloutsPresent(int index);
+
+ /// @brief Checks if control command handlers are present for the
+ /// specified command.
+ ///
+ /// @param command_name Command name for which handlers' presence should
+ /// be checked.
+ ///
+ /// @return true if there is a hook point associated with the specified
+ /// command and callouts/command handlers are installed for this hook
+ /// point, false otherwise.
+ static bool commandHandlersPresent(const std::string& command_name);
+
+ /// @brief Calls the callouts for a given hook
+ ///
+ /// Iterates through the library handles and calls the callouts associated
+ /// with the given hook index.
+ ///
+ /// @note This method invalidates the current library index set with
+ /// setLibraryIndex().
+ ///
+ /// @param index Index of the hook to call.
+ /// @param handle Reference to the CalloutHandle object for the current
+ /// object being processed.
+ static void callCallouts(int index, CalloutHandle& handle);
+
+ /// @brief Calls the callouts/command handlers for a given command name.
+ ///
+ /// Iterates through the library handles and calls the command handlers
+ /// associated with the given command. It expects that the hook point
+ /// for this command exists (with a name being a command_name prefixed
+ /// with a dollar sign and with hyphens replaced with underscores).
+ ///
+ /// @param command_name Command name for which handlers should be called.
+ /// @param handle Reference to the CalloutHandle object for the current
+ /// object being processed.
+ ///
+ /// @throw NoSuchHook if the hook point for the specified command does
+ /// not exist.
+ static void callCommandHandlers(const std::string& command_name,
+ CalloutHandle& handle);
+
+ /// @brief Return pre-callouts library handle
+ ///
+ /// Returns a library handle that can be used by the server to register
+ /// callouts on a hook that are called _before_ any callouts belonging
+ /// to a library.
+ ///
+ /// @note Both the reference returned and the callouts registered with
+ /// this handle only remain valid until the next loadLibraries() or
+ /// unloadLibraries() call. If the callouts are to remain registered
+ /// after this time, a new handle will need to be obtained and the
+ /// callouts re-registered.
+ ///
+ /// @return Reference to library handle associated with pre-library callout
+ /// registration.
+ static LibraryHandle& preCalloutsLibraryHandle();
+
+ /// @brief Return post-callouts library handle
+ ///
+ /// Returns a library handle that can be used by the server to register
+ /// callouts on a hook that are called _after any callouts belonging
+ /// to a library.
+ ///
+ /// @note Both the reference returned and the callouts registered with
+ /// this handle only remain valid until the next loadLibraries() or
+ /// unloadLibraries() call. If the callouts are to remain registered
+ /// after this time, a new handle will need to be obtained and the
+ /// callouts re-registered.
+ ///
+ /// @return Reference to library handle associated with post-library callout
+ /// registration.
+ static LibraryHandle& postCalloutsLibraryHandle();
+
+ /// @brief Return callout handle
+ ///
+ /// Returns a callout handle to be associated with a request passed round
+ /// the system.
+ ///
+ /// @note This handle is valid only after a loadLibraries() call and then
+ /// only up to the next loadLibraries() call.
+ ///
+ /// @return Shared pointer to a CalloutHandle object.
+ static boost::shared_ptr<CalloutHandle> createCalloutHandle();
+
+ /// @brief Register Hook
+ ///
+ /// This is just a convenience shell around the ServerHooks::registerHook()
+ /// method. It - along with the definitions of the two hook indexes for
+ /// the context_create and context_destroy methods - means that server
+ /// authors only need to deal with HooksManager and CalloutHandle, and not
+ /// include any other hooks framework classes.
+ ///
+ /// @param name Name of the hook
+ ///
+ /// @return Index of the hook, to be used in subsequent hook-related calls.
+ /// This will be greater than or equal to zero (so allowing a
+ /// negative value to indicate an invalid index).
+ ///
+ /// @throws DuplicateHook A hook with the same name has already been
+ /// registered.
+ static int registerHook(const std::string& name);
+
+ /// @brief Return list of loaded libraries
+ ///
+ /// Returns the names of the loaded libraries.
+ ///
+ /// @return List of loaded library names.
+ static std::vector<std::string> getLibraryNames();
+
+ /// @brief Return list of loaded libraries with its parameters.
+ ///
+ /// Returns the names of the loaded libraries and their parameters.
+ ///
+ /// @return List of loaded libraries (names + parameters)
+ static HookLibsCollection getLibraryInfo();
+
+ /// @brief Validate library list
+ ///
+ /// For each library passed to it, checks that the library can be opened
+ /// and that the "version" function is present and gives the right answer.
+ /// Each library is closed afterwards.
+ ///
+ /// This is used during the configuration parsing - when the list of hooks
+ /// libraries is changed, each of the new libraries is checked before the
+ /// change is committed.
+ ///
+ /// @param libraries List of libraries to be validated.
+ ///
+ /// @return An empty vector if all libraries validated. Otherwise it
+ /// holds the names of the libraries that failed validation.
+ static std::vector<std::string> validateLibraries(
+ const std::vector<std::string>& libraries);
+
+ /// Index numbers for pre-defined hooks.
+ static const int CONTEXT_CREATE = ServerHooks::CONTEXT_CREATE;
+ static const int CONTEXT_DESTROY = ServerHooks::CONTEXT_DESTROY;
+
+ /// @brief Park an object (packet).
+ ///
+ /// The typical use case for parking an object is when the server needs to
+ /// suspend processing of a packet to perform an asynchronous operation,
+ /// before the response is sent to a client. In this case, the object type
+ /// is a pointer to the processed packet. Therefore, further in this
+ /// description we're going to refer to the parked objects as "parked
+ /// packets". However, any other object can be parked if necessary.
+ ///
+ /// The following is the typical flow when packets are parked. The callouts
+ /// responsible for performing an asynchronous operation signal this need
+ /// to the server by returning the status @c NEXT_STEP_PARK, which instructs
+ /// the server to call this function. This function stops processing the
+ /// packet and puts it in, so called, parking lot. In order to be able to
+ /// resume the packet processing when instructed by the hooks library, the
+ /// parked packet is associated with the callback which, when called, will
+ /// resume packet processing.
+ ///
+ /// The hook library must increase a reference count on the parked object
+ /// by calling @c ParkingLotHandle::reference prior to returning the
+ /// @c NEXT_STEP_PARK status. This is important when multiple callouts
+ /// are installed on the same hook point and each of them schedules an
+ /// asynchronous operation. In this case, the packet must not be unparked
+ /// until all hook libraries call @c ParkingLotHandle::unpark to mark
+ /// that respective asynchronous operations are completed.
+ ///
+ /// @tparam Type of the parked object.
+ /// @param hook_name name of the hook point for which the packet is parked.
+ /// @param parked_object packet to be parked.
+ /// @param unpark_callback callback invoked when the packet is unparked.
+ template<typename T>
+ static void park(const std::string& hook_name, T parked_object,
+ std::function<void()> unpark_callback) {
+ ServerHooks::getServerHooks().
+ getParkingLotPtr(hook_name)->park(parked_object, unpark_callback);
+ }
+
+ /// @brief Forces unparking the object (packet).
+ ///
+ /// This method unparks the object regardless of the reference counting
+ /// value. This is used in the situations when the callouts fail to unpark
+ /// the packet for some reason.
+ ///
+ /// @tparam T type of the parked object.
+ /// @param hook_name name of the hook point for which the packet is parked.
+ /// @param parked_object parked object to be unparked.
+ /// @return true if the specified object has been found, false otherwise.
+ template<typename T>
+ static bool unpark(const std::string& hook_name, T parked_object) {
+ return (ServerHooks::getServerHooks().
+ getParkingLotPtr(hook_name)->unpark(parked_object, true));
+ }
+
+ /// @brief Removes parked object without calling a callback.
+ ///
+ /// @tparam T type of the parked object.
+ /// @param hook_name name of the hook point for which the packet is parked.
+ /// @param parked_object parked object to be removed.
+ /// @return true if the specified object has been found false otherwise.
+ template<typename T>
+ static bool drop(const std::string& hook_name, T parked_object) {
+ return (ServerHooks::getServerHooks().
+ getParkingLotPtr(hook_name)->drop(parked_object));
+ }
+
+ /// @brief Increases reference counter for the parked object.
+ ///
+ /// Reference counter must be increased at least to 1 before the @c park()
+ /// method can be called.
+ ///
+ /// @tparam Type of the parked object.
+ /// @param hook_name name of the hook point for which the packet is parked.
+ /// @param parked_object parked object for which reference counter should
+ /// be increased.
+ template<typename T>
+ static void reference(const std::string& hook_name, T parked_object) {
+ ServerHooks::getServerHooks().
+ getParkingLotPtr(hook_name)->reference(parked_object);
+ }
+
+ /// @brief Clears any parking packets.
+ ///
+ /// This method should be called during reconfiguration to ensure there
+ /// are no dangling pointers that could possibly prevent the library
+ /// from being unloaded.
+ static void clearParkingLots() {
+ ServerHooks::getServerHooks().getParkingLotsPtr()->clear();
+ }
+
+ /// @brief Set test mode
+ ///
+ /// If enabled by unit tests will permit to register callouts before calling
+ /// @ref loadLibraries which will return immediately without changing
+ /// current internal state.
+ ///
+ /// @param mode the test mode flag which enables or disabled the
+ /// functionality.
+ static void setTestMode(bool mode);
+
+ /// @brief Get test mode
+ ///
+ /// @return the test mode flag.
+ static bool getTestMode();
+
+private:
+
+ /// @brief Constructor
+ ///
+ /// This is private as the object is a singleton and can only be addressed
+ /// through the getHooksManager() static method.
+ HooksManager();
+
+ /// @brief Get singleton hooks manager
+ ///
+ /// @return Reference to the singleton hooks manager.
+ static HooksManager& getHooksManager();
+
+ //@{
+ /// The following methods correspond to similarly-named static methods,
+ /// but actually do the work on the singleton instance of the HooksManager.
+ /// See the descriptions of the static methods for more details.
+
+ /// @brief Validate library list
+ ///
+ /// @param List of libraries to be validated.
+ ///
+ /// @return An empty string if all libraries validated. Otherwise it is
+ /// the name of the first library that failed validation. The
+ /// configuration code can return this to bindctl as an indication
+ /// of the problem.
+ std::string validateLibrariesInternal(
+ const std::vector<std::string>& libraries) const;
+
+ /// @brief Load and reload libraries
+ ///
+ /// @param libraries List of libraries to be loaded. The order is
+ /// important, as it determines the order that callouts on the same
+ /// hook will be called.
+ ///
+ /// @return true if all libraries loaded without a problem, false if one or
+ /// more libraries failed to load. In the latter case, message will
+ /// be logged that give the reason.
+ bool loadLibrariesInternal(const HookLibsCollection& libraries);
+
+ /// @brief Unload libraries
+ ///
+ /// @return true if all libraries unloaded successfully, false on an error.
+ /// In the latter case, an error message will have been output.
+ bool unloadLibrariesInternal();
+
+ /// @brief Prepare the unloading of libraries
+ void prepareUnloadLibrariesInternal();
+
+ /// @brief Are callouts present?
+ ///
+ /// @param index Hooks index for which callouts are checked.
+ ///
+ /// @return true if callouts are present, false if not.
+ /// @throw NoSuchHook Given index does not correspond to a valid hook.
+ bool calloutsPresentInternal(int index);
+
+ /// @brief Checks if control command handlers are present for the
+ /// specified command.
+ ///
+ /// @param command_name Command name for which handlers' presence should
+ /// be checked.
+ ///
+ /// @return true if there is a hook point associated with the specified
+ /// command and callouts/command handlers are installed for this hook
+ /// point, false otherwise.
+ bool commandHandlersPresentInternal(const std::string& command_name);
+
+ /// @brief Calls the callouts for a given hook
+ ///
+ /// @param index Index of the hook to call.
+ /// @param handle Reference to the CalloutHandle object for the current
+ /// object being processed.
+ void callCalloutsInternal(int index, CalloutHandle& handle);
+
+ /// @brief Calls the callouts/command handlers for a given command name.
+ ///
+ /// @param command_name Command name for which handlers should be called.
+ /// @param handle Reference to the CalloutHandle object for the current
+ /// object being processed.
+ ///
+ /// @throw NoSuchHook if the hook point for the specified command does
+ /// not exist.
+ void callCommandHandlersInternal(const std::string& command_name,
+ CalloutHandle& handle);
+
+ /// @brief Return callout handle
+ ///
+ /// @return Shared pointer to a CalloutHandle object.
+ boost::shared_ptr<CalloutHandle> createCalloutHandleInternal();
+
+ /// @brief Return pre-callouts library handle
+ ///
+ /// @return Reference to library handle associated with pre-library callout
+ /// registration.
+ LibraryHandle& preCalloutsLibraryHandleInternal();
+
+ /// @brief Return post-callouts library handle
+ ///
+ /// @return Reference to library handle associated with post-library callout
+ /// registration.
+ LibraryHandle& postCalloutsLibraryHandleInternal();
+
+ /// @brief Return list of loaded libraries
+ ///
+ /// @return List of loaded library names.
+ std::vector<std::string> getLibraryNamesInternal() const;
+
+ /// @brief Return a collection of library names with parameters.
+ HookLibsCollection getLibraryInfoInternal() const;
+
+ //@}
+
+ // Members
+
+ /// Set of library managers.
+ ///
+ /// @note: This should never be null.
+ boost::shared_ptr<LibraryManagerCollection> lm_collection_;
+
+ /// Callout manager for the set of library managers.
+ ///
+ /// @note: This should never be null.
+ boost::shared_ptr<CalloutManager> callout_manager_;
+
+ /// Test flag to keep @ref callout_manager_ when calling @ref loadLibraries
+ /// from unit tests (called by @ref configureDhcp[46]Server).
+ ///
+ /// @note: This will effectively make @ref loadLibraries return immediately.
+ bool test_mode_;
+};
+
+} // namespace util
+} // namespace hooks
+
+#endif // HOOKS_MANAGER_H