BIND 10 trac2980, updated. ba91cff481836c5c8c1993174727646213cea60b [2980] Added pre-callout and post-callout function registration
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Jun 24 18:43:31 UTC 2013
The branch, trac2980 has been updated
via ba91cff481836c5c8c1993174727646213cea60b (commit)
via d72ba709f11dee0d0bb90868fc042bd8caaf8626 (commit)
via b4bf719aa55ad684dbfa5faa39aa93ebf89bac18 (commit)
from 49ee4eaf84ad72a044cf4957af016d1e8e15cab0 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit ba91cff481836c5c8c1993174727646213cea60b
Author: Stephen Morris <stephen at isc.org>
Date: Mon Jun 24 19:42:48 2013 +0100
[2980] Added pre-callout and post-callout function registration
commit d72ba709f11dee0d0bb90868fc042bd8caaf8626
Author: Stephen Morris <stephen at isc.org>
Date: Mon Jun 24 14:01:46 2013 +0100
[2980] Added conditional initialization.
commit b4bf719aa55ad684dbfa5faa39aa93ebf89bac18
Author: Stephen Morris <stephen at isc.org>
Date: Mon Jun 24 12:02:07 2013 +0100
[2980] Added HooksManager load/unload libraries methods
-----------------------------------------------------------------------
Summary of changes:
src/lib/hooks/callout_handle.cc | 21 +-
src/lib/hooks/callout_handle.h | 22 +-
src/lib/hooks/callout_manager.cc | 20 +-
src/lib/hooks/callout_manager.h | 122 +++++++--
src/lib/hooks/hooks_manager.cc | 124 ++++++---
src/lib/hooks/hooks_manager.h | 119 ++++++---
src/lib/hooks/library_handle.cc | 41 ++-
src/lib/hooks/library_handle.h | 17 +-
src/lib/hooks/library_manager.h | 2 +-
src/lib/hooks/tests/callout_manager_unittest.cc | 126 ++++++++-
src/lib/hooks/tests/hooks_manager_unittest.cc | 313 ++++++++++++++++++++---
11 files changed, 803 insertions(+), 124 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/hooks/callout_handle.cc b/src/lib/hooks/callout_handle.cc
index 27d76d7..5776a96 100644
--- a/src/lib/hooks/callout_handle.cc
+++ b/src/lib/hooks/callout_handle.cc
@@ -27,8 +27,10 @@ namespace isc {
namespace hooks {
// Constructor.
-CalloutHandle::CalloutHandle(const boost::shared_ptr<CalloutManager>& manager)
- : arguments_(), context_collection_(), manager_(manager), skip_(false) {
+CalloutHandle::CalloutHandle(const boost::shared_ptr<CalloutManager>& manager,
+ const boost::shared_ptr<LibraryManagerCollection>& lmcoll)
+ : lm_collection_(lmcoll), arguments_(), context_collection_(),
+ manager_(manager), skip_(false) {
// Call the "context_create" hook. We should be OK doing this - although
// the constructor has not finished running, all the member variables
@@ -43,6 +45,21 @@ CalloutHandle::~CalloutHandle() {
// the destructor is being called, all the member variables are still in
// existence.
manager_->callCallouts(ServerHooks::CONTEXT_DESTROY, *this);
+
+ // Explicitly clear the argument and context objects. This should free up
+ // all memory that could have been allocated by libraries that were loaded.
+ arguments_.clear();
+ context_collection_.clear();
+
+ // Normal destruction of the remaining variables will include the
+ // of the reference count on the library manager collection (which holds
+ // the libraries that could have allocated memory in the argument and
+ // context members). When that goes to zero, the libraries will be
+ // unloaded: however, at that point nothing in the hooks framework will
+ // access memory in the libraries' address space. It is possible that some
+ // other data structure in the server (the program using the hooks library)
+ // still references address space, but that is outside the scope of this
+ // framework.
}
// Return the name of all argument items.
diff --git a/src/lib/hooks/callout_handle.h b/src/lib/hooks/callout_handle.h
index 3792c58..36a90f8 100644
--- a/src/lib/hooks/callout_handle.h
+++ b/src/lib/hooks/callout_handle.h
@@ -54,6 +54,7 @@ public:
class CalloutManager;
class LibraryHandle;
+class LibraryManagerCollection;
/// @brief Per-packet callout handle
///
@@ -110,12 +111,27 @@ public:
/// Creates the object and calls the callouts on the "context_create"
/// hook.
///
+ /// Of the two arguments passed, only the pointer to the callout manager is
+ /// actively used. The second argument, the pointer to the library manager
+ /// collection, is used for lifetime control: after use, the callout handle
+ /// may contain pointers to memory allocated by the loaded libraries. The
+ /// used of a shared pointer to the collection of library managers means
+ /// that the libraries that could have allocated memory in a callout handle
+ /// will not be unloaded until all such handles have been destroyed. This
+ /// issue is discussed in more detail in the documentation for
+ /// isc::hooks::LibraryManager.
+ ///
/// @param manager Pointer to the callout manager object.
- CalloutHandle(const boost::shared_ptr<CalloutManager>& manager);
+ /// @param lmcoll Pointer to the library manager collection. This has a
+ /// null default for testing purposes.
+ CalloutHandle(const boost::shared_ptr<CalloutManager>& manager,
+ const boost::shared_ptr<LibraryManagerCollection>& lmcoll =
+ boost::shared_ptr<LibraryManagerCollection>());
/// @brief Destructor
///
/// Calls the context_destroy callback to release any per-packet context.
+ /// It also clears stored data to avoid problems during member destruction.
~CalloutHandle();
/// @brief Set argument
@@ -339,6 +355,10 @@ private:
const ElementCollection& getContextForLibrary() const;
// Member variables
+
+ /// Pointer to the collection of libraries for which this handle has been
+ /// created.
+ boost::shared_ptr<LibraryManagerCollection> lm_collection_;
/// Collection of arguments passed to the callouts
ElementCollection arguments_;
diff --git a/src/lib/hooks/callout_manager.cc b/src/lib/hooks/callout_manager.cc
index 0547a19..36ebc04 100644
--- a/src/lib/hooks/callout_manager.cc
+++ b/src/lib/hooks/callout_manager.cc
@@ -19,6 +19,7 @@
#include <boost/static_assert.hpp>
#include <algorithm>
+#include <climits>
#include <functional>
#include <utility>
@@ -27,7 +28,24 @@ using namespace std;
namespace isc {
namespace hooks {
-// Set the number of libraries handles by the CalloutManager.
+// Check that the index of a library is valid. It can range from 1 - n
+// (n is the number of libraries) or it can be 0 (pre-user library callouts)
+// of INT_MAX (post-user library callouts). It can also be -1 to indicate
+// an invalid value.
+
+void
+CalloutManager::checkLibraryIndex(int library_index) const {
+ if (((library_index >= -1) && (library_index <= num_libraries_)) ||
+ (library_index == INT_MAX)) {
+ return;
+ } else {
+ isc_throw(NoSuchLibrary, "library index " << library_index <<
+ " is not valid for the number of loaded libraries (" <<
+ num_libraries_ << ")");
+ }
+}
+
+// Set the number of libraries handled by the CalloutManager.
void
CalloutManager::setNumLibraries(int num_libraries) {
diff --git a/src/lib/hooks/callout_manager.h b/src/lib/hooks/callout_manager.h
index 39e374e..25803d2 100644
--- a/src/lib/hooks/callout_manager.h
+++ b/src/lib/hooks/callout_manager.h
@@ -21,6 +21,7 @@
#include <boost/shared_ptr.hpp>
+#include <climits>
#include <map>
#include <string>
@@ -37,7 +38,6 @@ public:
isc::Exception(file, line, what) {}
};
-
/// @brief Callout Manager
///
/// This class manages the registration, deregistration and execution of the
@@ -64,9 +64,47 @@ public:
/// functions use the "current library index" in their processing.
///
/// These two items of data are supplied when an object of this class is
-/// constructed.
+/// constructed. The latter (number of libraries) can be updated after the
+/// class is constructed. (Such an update is used during library loading where
+/// the CalloutManager has to be constructed before the libraries are loaded,
+/// but one of the libraries subsequently fails to load.)
+///
+/// The library index is important because it determines in what order callouts
+/// on a particular hook are called. For each hook, the CalloutManager
+/// maintains a vector of callouts, ordered by library index. When a callout
+/// is added to the list, it is added at the end of the callouts associated
+/// with the current library. To clarify this further, suppose that three
+/// libraries are loaded, A (assigned an index 1), B (assigned an index 2) and
+/// C (assigned an index 3). Suppose A registers two callouts on a given hook,
+/// A1 and A2 (in that order) B registers B1 and B2 (in that order) and C
+/// registers C1 and C2 (in that order). Internally, the callouts are stored
+/// in the order A1, A2, B1, B2, C1, and C2: this is also the order in which
+/// the are called. If B now registers another callout (B3), it is added to
+/// the vector after the list of callouts associated with B: the new order is
+/// therefore A1, A2, B1, B2, B3, C1 and C2.
+///
+/// Indexes range between 1 and n (where n is the number of the libraries
+/// loaded) and are assigned to libraries based on the order the libraries
+/// presented to the hooks framework for loading (something that occurs in the
+/// isc::util::HooksManager) class. However, two other indexes are recognised,
+/// 0 and n+1. These are used when the server itself registers callouts - the
+/// server is able to register callouts that get called before any user-library
+/// callouts, and callouts that get called after user-library callouts. In other
+/// words, assuming the callouts on a hook are A1, A2, B1, B2, B3, C2, C2 as
+/// before, and that the server registers Spre (to run before the
+/// user-registered callouts) and Spost (to run after them), the callouts are
+/// stored (and executed) in the order Spre, A1, A2, B1, B2, B3, C2, C2, Spost.
+/// In summary, the index values are:
///
-/// Note that the callout function do not access the library manager: instead,
+/// - < 0: invalid.
+/// - 0: used for server-registered callouts that are called before
+/// user-registered callouts.
+/// - 1 - n: callouts from user-libraries.
+/// - INT_MAX: used for server-registered callouts called after
+/// user-registered callouts.
+/// - > n + 1: invalid
+///
+/// Note that the callout functions do not access the CalloutManager: instead,
/// they use a LibraryHandle object. This contains an internal pointer to
/// the CalloutManager, but provides a restricted interface. In that way,
/// callouts are unable to affect callouts supplied by other libraries.
@@ -99,7 +137,8 @@ public:
CalloutManager(int num_libraries = 0)
: current_hook_(-1), current_library_(-1),
hook_vector_(ServerHooks::getServerHooks().getCount()),
- library_handle_(this), num_libraries_(num_libraries)
+ library_handle_(this), pre_library_handle_(this, 0),
+ post_library_handle_(this, INT_MAX), num_libraries_(num_libraries)
{
// Check that the number of libraries is OK. (This does a redundant
// set of the number of libraries, but it's only a single assignment
@@ -191,9 +230,14 @@ public:
/// constructor, in some cases that is only an estimate and the number
/// can only be determined after the CalloutManager is created.
///
+ /// @note If the number if libraries is reset, it must be done *before*
+ /// any callouts are registered.
+ ///
/// @param num_libraries Number of libraries served by this CalloutManager.
///
/// @throw BadValue Number of libraries must be >= 0.
+ /// @throw LibraryCountChanged Number of libraries has been changed after
+ /// callouts have been registered.
void setNumLibraries(int num_libraries);
/// @brief Get number of libraries
@@ -224,9 +268,14 @@ public:
/// @brief Set current library index
///
- /// Sets the current library index. This must be in the range 0 to
- /// (numlib - 1), where "numlib" is the number of libraries loaded in the
- /// system, this figure being passed to this object at construction time.
+ /// Sets the current library index. This has the following valid values:
+ ///
+ /// - -1: invalidate current index.
+ /// - 0: pre-user library callout.
+ /// - 1 - numlib: user-library callout (where "numlib" is the number of
+ /// libraries loaded in the system, this figure being passed to this
+ /// object at construction time).
+ /// - INT_MAX: post-user library callout.
///
/// @param library_index New library index.
///
@@ -236,6 +285,19 @@ public:
current_library_ = library_index;
}
+ /// @defgroup calloutManagerLibraryHandles Callout manager library handles
+ ///
+ /// The CalloutManager offers three library handles:
+ ///
+ /// - a "standard" one, used to register and deregister callouts for
+ /// the library index that is marked as current in the CalloutManager.
+ /// When a callout is called, it is passed this one.
+ /// - a pre-library callout handle, used by the server to register
+ // callouts to run prior to user-library callouts.
+ /// - a post-library callout handle, used by the server to register
+ /// callouts to run after the user-library callouts.
+ //@{
+
/// @brief Return library handle
///
/// The library handle is available to the user callout via the callout
@@ -244,11 +306,33 @@ public:
/// library of which it is part, whilst denying access to anything that
/// may affect other libraries.
///
- /// @return Reference to callout handle for this manager
+ /// @return Reference to library handle for this manager
LibraryHandle& getLibraryHandle() {
return (library_handle_);
}
+ /// @brief Return pre-user callouts library handle
+ ///
+ /// The LibraryHandle to affect callouts that will run before the
+ /// user-library callouts.
+ ///
+ /// @return Reference to pre-user library handle for this manager
+ LibraryHandle& getPreLibraryHandle() {
+ return (pre_library_handle_);
+ }
+
+ /// @brief Return post-user callouts library handle
+ ///
+ /// The LibraryHandle to affect callouts that will run before the
+ /// user-library callouts.
+ ///
+ /// @return Reference to post-user library handle for this manager
+ LibraryHandle& getPostLibraryHandle() {
+ return (post_library_handle_);
+ }
+
+ //@}
+
private:
/// @brief Check library index
///
@@ -256,15 +340,11 @@ private:
/// the hook registration functions.
///
/// @param library_index Value to check for validity as a library index.
+ /// Valid values are 0 - numlib+1 and -1: see @ref setLibraryIndex
+ /// for the meaning of the various values.
///
/// @throw NoSuchLibrary Library index is not valid.
- void checkLibraryIndex(int library_index) const {
- if ((library_index < 0) || (library_index >= num_libraries_)) {
- isc_throw(NoSuchLibrary, "library index " << library_index <<
- " is not valid for the number of loaded libraries (" <<
- num_libraries_ << ")");
- }
- }
+ void checkLibraryIndex(int library_index) const;
/// @brief Compare two callout entries for library equality
///
@@ -301,8 +381,18 @@ private:
std::vector<CalloutVector> hook_vector_;
/// LibraryHandle object user by the callout to access the callout
- /// registration methods on this CalloutManager object.
+ /// registration methods on this CalloutManager object. The object is set
+ /// such that the index of the library associated with any operation is
+ /// whatever is currently set in the CalloutManager.
LibraryHandle library_handle_;
+
+ /// LibraryHandle for callouts to be registered as being called before
+ /// the user-registered callouts.
+ LibraryHandle pre_library_handle_;
+
+ /// LibraryHandle for callouts to be registered as being called after
+ /// the user-registered callouts.
+ LibraryHandle post_library_handle_;
/// Number of libraries.
int num_libraries_;
diff --git a/src/lib/hooks/hooks_manager.cc b/src/lib/hooks/hooks_manager.cc
index 0b304d6..39e1fc5 100644
--- a/src/lib/hooks/hooks_manager.cc
+++ b/src/lib/hooks/hooks_manager.cc
@@ -12,9 +12,6 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-// TODO - This is a temporary implementation of the hooks manager - it is
-// likely to be completely rewritte
-
#include <hooks/callout_handle.h>
#include <hooks/callout_manager.h>
#include <hooks/callout_manager.h>
@@ -46,20 +43,71 @@ HooksManager::getHooksManager() {
return (manager);
}
-// Perform conditional initialization if nothing is loaded.
+// Are callouts present?
+
+bool
+HooksManager::calloutsPresentInternal(int index) {
+ conditionallyInitialize();
+ return (callout_manager_->calloutsPresent(index));
+}
+
+bool
+HooksManager::calloutsPresent(int index) {
+ return (getHooksManager().calloutsPresentInternal(index));
+}
+
+// Call the callouts
void
-HooksManager::conditionallyInitialize() {
- if (!lm_collection_) {
+HooksManager::callCalloutsInternal(int index, CalloutHandle& handle) {
+ conditionallyInitialize();
+ return (callout_manager_->callCallouts(index, handle));
+}
+
+void
+HooksManager::callCallouts(int index, CalloutHandle& handle) {
+ return (getHooksManager().callCalloutsInternal(index, handle));
+}
+
+// Load the libraries. This will delete the previously-loaded libraries
+// (if present) and load new ones.
+
+bool
+HooksManager::loadLibrariesInternal(const std::vector<std::string>& libraries) {
+ // Unload current set of libraries (if any are loaded).
+ unloadLibrariesInternal();
+
+ // Create the library manager and load the libraries.
+ lm_collection_.reset(new LibraryManagerCollection(libraries));
+ bool status = lm_collection_->loadLibraries();
+
+ // ... and obtain the callout manager for them.
+ callout_manager_ = lm_collection_->getCalloutManager();
+
+ return (status);
+}
+
+bool
+HooksManager::loadLibraries(const std::vector<std::string>& libraries) {
+ return (getHooksManager().loadLibrariesInternal(libraries));
+}
- // Nothing present, so create the collection with any empty set of
- // libraries, and get the CalloutManager.
- vector<string> libraries;
- lm_collection_.reset(new LibraryManagerCollection(libraries));
- lm_collection_->loadLibraries();
+// Unload the libraries. This just deletes all internal objects which will
+// cause the libraries to be unloaded.
- callout_manager_ = lm_collection_->getCalloutManager();
- }
+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();
+}
+
+void HooksManager::unloadLibraries() {
+ getHooksManager().unloadLibrariesInternal();
}
// Create a callout handle
@@ -68,7 +116,7 @@ boost::shared_ptr<CalloutHandle>
HooksManager::createCalloutHandleInternal() {
conditionallyInitialize();
return (boost::shared_ptr<CalloutHandle>(
- new CalloutHandle(callout_manager_)));
+ new CalloutHandle(callout_manager_, lm_collection_)));
}
boost::shared_ptr<CalloutHandle>
@@ -76,34 +124,50 @@ HooksManager::createCalloutHandle() {
return (getHooksManager().createCalloutHandleInternal());
}
-// Are callouts present?
+// Perform conditional initialization if nothing is loaded.
-bool
-HooksManager::calloutsPresentInternal(int index) {
- conditionallyInitialize();
- return (callout_manager_->calloutsPresent(index));
+void
+HooksManager::performConditionalInitialization() {
+
+ // Nothing present, so create the collection with any empty set of
+ // libraries, and get the CalloutManager.
+ vector<string> libraries;
+ lm_collection_.reset(new LibraryManagerCollection(libraries));
+ lm_collection_->loadLibraries();
+
+ callout_manager_ = lm_collection_->getCalloutManager();
}
-bool
-HooksManager::calloutsPresent(int index) {
- return (getHooksManager().calloutsPresentInternal(index));
+// Shell around ServerHooks::registerHook()
+
+int
+HooksManager::registerHook(const std::string& name) {
+ return (ServerHooks::getServerHooks().registerHook(name));
}
-// Call the callouts
+// Return pre- and post- library handles.
-void
-HooksManager::callCalloutsInternal(int index, CalloutHandle& handle) {
+isc::hooks::LibraryHandle&
+HooksManager::preCalloutsLibraryHandleInternal() {
conditionallyInitialize();
- return (callout_manager_->callCallouts(index, handle));
+ return (callout_manager_->getPreLibraryHandle());
}
-void
-HooksManager::callCallouts(int index, CalloutHandle& handle) {
- return (getHooksManager().callCalloutsInternal(index, handle));
+isc::hooks::LibraryHandle&
+HooksManager::preCalloutsLibraryHandle() {
+ return (getHooksManager().preCalloutsLibraryHandleInternal());
}
+isc::hooks::LibraryHandle&
+HooksManager::postCalloutsLibraryHandleInternal() {
+ conditionallyInitialize();
+ return (callout_manager_->getPostLibraryHandle());
+}
-
+isc::hooks::LibraryHandle&
+HooksManager::postCalloutsLibraryHandle() {
+ return (getHooksManager().postCalloutsLibraryHandleInternal());
+}
} // namespace util
} // namespace isc
diff --git a/src/lib/hooks/hooks_manager.h b/src/lib/hooks/hooks_manager.h
index 2048309..03aa521 100644
--- a/src/lib/hooks/hooks_manager.h
+++ b/src/lib/hooks/hooks_manager.h
@@ -15,6 +15,8 @@
#ifndef HOOKS_MANAGER_H
#define HOOKS_MANAGER_H
+#include <hooks/server_hooks.h>
+
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
@@ -47,12 +49,6 @@ public:
/// @return Reference to the singleton hooks manager.
static HooksManager& getHooksManager();
- /// @brief Reset hooks manager
- ///
- /// Resets the hooks manager to the initial state. This should only be
- /// called by test functions, so causes a warning message to be output.
- void reset() {}
-
/// @brief Load and reload libraries
///
/// Loads the list of libraries into the server address space. For each
@@ -73,7 +69,7 @@ public:
/// @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 loadLibraries(const std::vector<std::string>& /* libraries */) {return false;}
+ static bool loadLibraries(const std::vector<std::string>& libraries);
/// @brief Unload libraries
///
@@ -88,7 +84,7 @@ public:
///
/// @return true if all libraries unloaded successfully, false on an error.
/// In the latter case, an error message will have been output.
- bool unloadLibraries() {return false;}
+ static void unloadLibraries();
/// @brief Are callouts present?
///
@@ -120,16 +116,15 @@ public:
/// callouts on a hook that are called _before_ any callouts belonging
/// to a library.
///
- /// @note This library handle is valid only after loadLibraries() is
- /// called and before another call to loadLibraries(). Its use
- /// at any other time may cause severe problems.
+ /// @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.
///
- /// TODO: This is also invalidated by a call to obtaining the
- /// post-callout function.
- ///
- /// @return Shared pointer to library handle associated with pre-library
- /// callout registration.
- boost::shared_ptr<LibraryHandle> preCalloutLibraryHandle() const;
+ /// @return Reference to library handle associated with pre-library callout
+ /// registration.
+ static LibraryHandle& preCalloutsLibraryHandle();
/// @brief Return post-callouts library handle
///
@@ -137,16 +132,15 @@ public:
/// callouts on a hook that are called _after any callouts belonging
/// to a library.
///
- /// @note This library handle is valid only after loadLibraries() is
- /// called and before another call to loadLibraries(). Its use
- /// at any other time may cause severe problems.
- ///
- /// TODO: This is also invalidated by a call to obtaining the
- /// pret-callout function.
+ /// @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 Shared pointer to library handle associated with post-library
- /// callout registration.
- boost::shared_ptr<LibraryHandle> postCalloutLibraryHandle() const;
+ /// @return Reference to library handle associated with post-library callout
+ /// registration.
+ static LibraryHandle& postCalloutsLibraryHandle();
/// @brief Return callout handle
///
@@ -159,6 +153,28 @@ public:
/// @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);
+
+ /// Index numbers for pre-defined hooks.
+ static const int CONTEXT_CREATE = ServerHooks::CONTEXT_CREATE;
+ static const int CONTEXT_DESTROY = ServerHooks::CONTEXT_DESTROY;
+
private:
/// @brief Constructor
@@ -168,8 +184,23 @@ private:
HooksManager();
//@{
- /// The following correspond to the each of the static methods above
- /// but operate on the current instance.
+ /// 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 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 std::vector<std::string>& libraries);
+
+ /// @brief Unload libraries
+ void unloadLibrariesInternal();
/// @brief Are callouts present?
///
@@ -188,14 +219,30 @@ private:
/// @brief Return callout handle
///
- /// @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.
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 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,
@@ -204,7 +251,15 @@ private:
/// whenever any hooks execution function is invoked (checking callouts,
/// calling callouts or returning a callout handle). If the HooksManager
/// is unitialised, it will initialize it with an "empty set" of libraries.
- void conditionallyInitialize();
+ ///
+ /// 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();
+ }
+ }
// Members
diff --git a/src/lib/hooks/library_handle.cc b/src/lib/hooks/library_handle.cc
index 8a78707..7f43116 100644
--- a/src/lib/hooks/library_handle.cc
+++ b/src/lib/hooks/library_handle.cc
@@ -22,17 +22,54 @@ namespace hooks {
void
LibraryHandle::registerCallout(const std::string& name, CalloutPtr callout) {
+ // Reset library index if required, saving the current value.
+ int saved_index = callout_manager_->getLibraryIndex();
+ if (index_ >= 0) {
+ callout_manager_->setLibraryIndex(index_);
+ }
+
+ // Register the callout.
callout_manager_->registerCallout(name, callout);
+
+ // Restore the library index if required. We know that the saved index
+ // is valid for the number of libraries (or is -1, which is an internal
+ // state indicating there is no current library index) as we obtained it
+ // from the callout manager.
+ if (index_ >= 0) {
+ callout_manager_->setLibraryIndex(saved_index);
+ }
}
bool
LibraryHandle::deregisterCallout(const std::string& name, CalloutPtr callout) {
- return (callout_manager_->deregisterCallout(name, callout));
+ int saved_index = callout_manager_->getLibraryIndex();
+ if (index_ >= 0) {
+ callout_manager_->setLibraryIndex(index_);
+ }
+
+ bool status = callout_manager_->deregisterCallout(name, callout);
+
+ if (index_ >= 0) {
+ callout_manager_->setLibraryIndex(saved_index);
+ }
+
+ return (status);
}
bool
LibraryHandle::deregisterAllCallouts(const std::string& name) {
- return (callout_manager_->deregisterAllCallouts(name));
+ int saved_index = callout_manager_->getLibraryIndex();
+ if (index_ >= 0) {
+ callout_manager_->setLibraryIndex(index_);
+ }
+
+ bool status = callout_manager_->deregisterAllCallouts(name);
+
+ if (index_ >= 0) {
+ callout_manager_->setLibraryIndex(saved_index);
+ }
+
+ return (status);
}
} // namespace util
diff --git a/src/lib/hooks/library_handle.h b/src/lib/hooks/library_handle.h
index 1f20986..6cf522c 100644
--- a/src/lib/hooks/library_handle.h
+++ b/src/lib/hooks/library_handle.h
@@ -58,7 +58,18 @@ public:
/// object. Note that the "raw" pointer is safe - the only
/// instance of the LibraryHandle in the system is as a member of
/// the CalloutManager to which it points.
- LibraryHandle(CalloutManager* manager) : callout_manager_(manager)
+ ///
+ /// @param index Index of the library to which the LibraryHandle applies.
+ /// If negative, the library index as set in the CalloutManager is
+ /// used. Otherwise the current library index is saved, this value
+ /// is set as the current index, the registration call is made, and
+ /// the CalloutManager's library index is reset. Note: although -1
+ /// is a valid argument value for
+ /// isc::hooks::CalloutManager::setLibraryIndex(), in this class is
+ /// is used as a sentinel to indicate that the library index in
+ /// isc::util::CalloutManager should not be set or reset.
+ LibraryHandle(CalloutManager* manager, int index = -1)
+ : callout_manager_(manager), index_(index)
{}
/// @brief Register a callout on a hook
@@ -107,6 +118,10 @@ public:
private:
/// Back pointer to the collection object for the library
CalloutManager* callout_manager_;
+
+ /// Library index to which this handle applies. -1 indicates that it
+ /// applies to whatever index is current in the CalloutManager.
+ int index_;
};
} // namespace util
diff --git a/src/lib/hooks/library_manager.h b/src/lib/hooks/library_manager.h
index 4120cdf..318f2d9 100644
--- a/src/lib/hooks/library_manager.h
+++ b/src/lib/hooks/library_manager.h
@@ -39,7 +39,7 @@ class LibraryManager;
/// On unload, it calls the "unload" method if one was located, clears the
/// callouts from all hooks and closes the library.
///
-/// @note Caution needs to be exercised whtn using the unload method. During
+/// @note Caution needs to be exercised when using the unload method. During
/// 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
diff --git a/src/lib/hooks/tests/callout_manager_unittest.cc b/src/lib/hooks/tests/callout_manager_unittest.cc
index f57d17d..9f1f3ca 100644
--- a/src/lib/hooks/tests/callout_manager_unittest.cc
+++ b/src/lib/hooks/tests/callout_manager_unittest.cc
@@ -22,6 +22,7 @@
#include <gtest/gtest.h>
#include <algorithm>
+#include <climits>
#include <string>
#include <vector>
@@ -207,14 +208,25 @@ TEST_F(CalloutManagerTest, NumberOfLibraries) {
// Check that we can only set the current library index to the correct values.
TEST_F(CalloutManagerTest, CheckLibraryIndex) {
- // Check valid indexes
- for (int i = 0; i < 4; ++i) {
+ // Check valid indexes. As the callout manager is sized for 10 libraries,
+ // we expect:
+ //
+ // -1 to be valid as it is the standard "invalid" value.
+ // 0 to be valid for the pre-user library callouts
+ // 1-10 to be valid for the user-library callouts
+ // INT_MAX to be valid for the post-user library callouts
+ //
+ // All other values to be invalid.
+ for (int i = -1; i < 11; ++i) {
EXPECT_NO_THROW(getCalloutManager()->setLibraryIndex(i));
+ EXPECT_EQ(i, getCalloutManager()->getLibraryIndex());
}
+ EXPECT_NO_THROW(getCalloutManager()->setLibraryIndex(INT_MAX));
+ EXPECT_EQ(INT_MAX, getCalloutManager()->getLibraryIndex());
// Check invalid ones
- EXPECT_THROW(getCalloutManager()->setLibraryIndex(-1), NoSuchLibrary);
- EXPECT_THROW(getCalloutManager()->setLibraryIndex(15), NoSuchLibrary);
+ EXPECT_THROW(getCalloutManager()->setLibraryIndex(-2), NoSuchLibrary);
+ EXPECT_THROW(getCalloutManager()->setLibraryIndex(11), NoSuchLibrary);
}
// Check that we can only register callouts on valid hook names.
@@ -761,6 +773,112 @@ TEST_F(CalloutManagerTest, LibraryHandleRegistration) {
EXPECT_EQ(1, callout_value_);
}
+// A repeat of the test above, but using the alternate constructor for the
+// LibraryHandle.
+TEST_F(CalloutManagerTest, LibraryHandleAlternateConstructor) {
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(alpha_index_));
+
+ // Set up so that hooks "alpha" and "beta" have callouts attached from a
+ // different libraries.
+ LibraryHandle lh0(getCalloutManager().get(), 0);
+ lh0.registerCallout("alpha", callout_one);
+ lh0.registerCallout("alpha", callout_two);
+
+ LibraryHandle lh1(getCalloutManager().get(), 1);
+ lh1.registerCallout("alpha", callout_three);
+ lh1.registerCallout("alpha", callout_four);
+
+ // Check all is as expected.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Check that calling the callouts returns as expected. (This is also a
+ // test of the callCallouts method.)
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+
+ // Deregister a callout on library index 0 (after we check we can't
+ // deregister it through library index 1).
+ EXPECT_FALSE(lh1.deregisterCallout("alpha", callout_two));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1234, callout_value_);
+
+ EXPECT_TRUE(lh0.deregisterCallout("alpha", callout_two));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(134, callout_value_);
+
+ // Deregister all callouts on library index 1.
+ EXPECT_TRUE(lh1.deregisterAllCallouts("alpha"));
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(1, callout_value_);
+}
+
+// Check that the pre- and post- user callout library handles work
+// appropriately with no user libraries.
+
+TEST_F(CalloutManagerTest, LibraryHandlePrePostNoLibraries) {
+ // Create a local callout manager and callout handle to reflect no libraries
+ // being loaded.
+ boost::shared_ptr<CalloutManager> manager(new CalloutManager(0));
+ CalloutHandle handle(manager);
+
+ // Ensure that no callouts are attached to any of the hooks.
+ EXPECT_FALSE(manager->calloutsPresent(alpha_index_));
+
+ // Setup the pre-and post callouts.
+ manager->getPostLibraryHandle().registerCallout("alpha", callout_four);
+ manager->getPreLibraryHandle().registerCallout("alpha", callout_one);
+ // Check all is as expected.
+ EXPECT_TRUE(manager->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(manager->calloutsPresent(beta_index_));
+ EXPECT_FALSE(manager->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(manager->calloutsPresent(delta_index_));
+
+ // Check that calling the callouts returns as expected.
+ callout_value_ = 0;
+ manager->callCallouts(alpha_index_, handle);
+ EXPECT_EQ(14, callout_value_);
+
+ // Deregister the pre- library callout.
+ EXPECT_TRUE(manager->getPreLibraryHandle().deregisterAllCallouts("alpha"));
+ callout_value_ = 0;
+ manager->callCallouts(alpha_index_, handle);
+ EXPECT_EQ(4, callout_value_);
+}
+
+// Repeat the tests with one user library.
+
+TEST_F(CalloutManagerTest, LibraryHandlePrePostUserLibrary) {
+
+ // Setup the pre-, library and post callouts.
+ getCalloutManager()->getPostLibraryHandle().registerCallout("alpha",
+ callout_four);
+ getCalloutManager()->getPreLibraryHandle().registerCallout("alpha",
+ callout_one);
+
+ // ... and set up a callout in between, on library number 2.
+ LibraryHandle lh1(getCalloutManager().get(), 2);
+ lh1.registerCallout("alpha", callout_five);
+
+ // Check all is as expected.
+ EXPECT_TRUE(getCalloutManager()->calloutsPresent(alpha_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(beta_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(gamma_index_));
+ EXPECT_FALSE(getCalloutManager()->calloutsPresent(delta_index_));
+
+ // Check that calling the callouts returns as expected.
+ callout_value_ = 0;
+ getCalloutManager()->callCallouts(alpha_index_, getCalloutHandle());
+ EXPECT_EQ(154, callout_value_);
+}
+
// The setting of the hook index is checked in the handles_unittest
// set of tests, as access restrictions mean it is not easily tested
// on its own.
diff --git a/src/lib/hooks/tests/hooks_manager_unittest.cc b/src/lib/hooks/tests/hooks_manager_unittest.cc
index 0d827ae..c1a3600 100644
--- a/src/lib/hooks/tests/hooks_manager_unittest.cc
+++ b/src/lib/hooks/tests/hooks_manager_unittest.cc
@@ -14,6 +14,7 @@
#include <hooks/callout_handle.h>
#include <hooks/hooks_manager.h>
+#include <hooks/server_hooks.h>
#include <hooks/tests/common_test_class.h>
#include <hooks/tests/test_libraries.h>
@@ -41,9 +42,17 @@ public:
/// Reset the hooks manager. The hooks manager is a singleton, so needs
/// to be reset for each test.
HooksManagerTest() {
- HooksManager::getHooksManager().reset();
+ HooksManager::unloadLibraries();
}
+ /// @brief Destructor
+ ///
+ /// Unload all libraries.
+ ~HooksManagerTest() {
+ HooksManager::unloadLibraries();
+ }
+
+
/// @brief Call callouts test
///
/// See the header for HooksCommonTestClass::execute for details.
@@ -91,9 +100,9 @@ public:
}
};
-/*
+
// This is effectively the same test as for LibraryManager, but using the
-// LibraryManagerCollection object.
+// HooksManager object.
TEST_F(HooksManagerTest, LoadLibraries) {
@@ -102,14 +111,8 @@ TEST_F(HooksManagerTest, LoadLibraries) {
library_names.push_back(std::string(FULL_CALLOUT_LIBRARY));
library_names.push_back(std::string(BASIC_CALLOUT_LIBRARY));
- // Set up the library manager collection and get the callout manager we'll
- // be using.
- PublicLibraryManagerCollection lm_collection(library_names);
-
// Load the libraries.
- EXPECT_TRUE(lm_collection.loadLibraries());
- boost::shared_ptr<CalloutManager> manager =
- lm_collection.getCalloutManager();
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
// Execute the callouts. The first library implements the calculation.
//
@@ -124,18 +127,18 @@ TEST_F(HooksManagerTest, LoadLibraries) {
//
// r3 = ((10 * d1 + d1) - d2) * d2 * d3 - d3
{
- SCOPED_TRACE("Doing calculation with libraries loaded");
- executeCallCallouts(manager, 10, 3, 33, 2, 62, 3, 183);
+ SCOPED_TRACE("Calculation with libraries loaded");
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
}
// Try unloading the libraries.
- EXPECT_NO_THROW(lm_collection.unloadLibraries());
+ EXPECT_NO_THROW(HooksManager::unloadLibraries());
// Re-execute the calculation - callouts can be called but as nothing
// happens, the result should always be -1.
{
- SCOPED_TRACE("Doing calculation with libraries not loaded");
- executeCallCallouts(manager, -1, 3, -1, 22, -1, 83, -1);
+ SCOPED_TRACE("Calculation with libraries not loaded");
+ executeCallCallouts(-1, 3, -1, 22, -1, 83, -1);
}
}
@@ -143,7 +146,7 @@ TEST_F(HooksManagerTest, LoadLibraries) {
// an error when loaded. It is expected that the failing library will not be
// loaded, but others will be.
-TEST_F(LibraryManagerCollectionTest, LoadLibrariesWithError) {
+TEST_F(HooksManagerTest, LoadLibrariesWithError) {
// Set up the list of libraries to be loaded.
std::vector<std::string> library_names;
@@ -151,18 +154,9 @@ TEST_F(LibraryManagerCollectionTest, LoadLibrariesWithError) {
library_names.push_back(std::string(INCORRECT_VERSION_LIBRARY));
library_names.push_back(std::string(BASIC_CALLOUT_LIBRARY));
- // Set up the library manager collection and get the callout manager we'll
- // be using.
- PublicLibraryManagerCollection lm_collection(library_names);
-
- // Load the libraries. We expect a failure status to be returned as
- // one of the libraries failed to load.
- EXPECT_FALSE(lm_collection.loadLibraries());
- boost::shared_ptr<CalloutManager> manager =
- lm_collection.getCalloutManager();
-
- // Expect only two libraries were loaded.
- EXPECT_EQ(2, manager->getNumLibraries());
+ // Load the libraries. We expect a failure return because one of the
+ // libraries fails to load.
+ EXPECT_FALSE(HooksManager::loadLibraries(library_names));
// Execute the callouts. The first library implements the calculation.
//
@@ -177,21 +171,236 @@ TEST_F(LibraryManagerCollectionTest, LoadLibrariesWithError) {
//
// r3 = ((10 * d1 + d1) - d2) * d2 * d3 - d3
{
- SCOPED_TRACE("Doing calculation with libraries loaded");
- executeCallCallouts(manager, 10, 3, 33, 2, 62, 3, 183);
+ SCOPED_TRACE("Calculation with libraries loaded");
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
}
// Try unloading the libraries.
- EXPECT_NO_THROW(lm_collection.unloadLibraries());
+ EXPECT_NO_THROW(HooksManager::unloadLibraries());
// Re-execute the calculation - callouts can be called but as nothing
// happens, the result should always be -1.
{
- SCOPED_TRACE("Doing calculation with libraries not loaded");
- executeCallCallouts(manager, -1, 3, -1, 22, -1, 83, -1);
+ SCOPED_TRACE("Calculation with libraries not loaded");
+ executeCallCallouts(-1, 3, -1, 22, -1, 83, -1);
+ }
+}
+
+// Test that we can unload a set of libraries while we have a CalloutHandle
+// created on them in existence, and can delete the handle afterwards.
+
+TEST_F(HooksManagerTest, CalloutHandleUnloadLibrary) {
+
+ // Set up the list of libraries to be loaded.
+ std::vector<std::string> library_names;
+ library_names.push_back(std::string(FULL_CALLOUT_LIBRARY));
+
+ // Load the libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Execute the callouts. Thiis library implements:
+ //
+ // r3 = (7 * d1 - d2) * d3
+ {
+ SCOPED_TRACE("Calculation with full callout library loaded");
+ executeCallCallouts(7, 4, 28, 8, 20, 2, 40);
+ }
+
+ // Get an outstanding callout handle on this library.
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+
+ // Execute once of the callouts again to ensure that the handle contains
+ // memory allocated by the library.
+ HooksManager::callCallouts(ServerHooks::CONTEXT_CREATE, *handle);
+
+ // Unload the libraries.
+ HooksManager::unloadLibraries();
+
+ // Deleting the callout handle should not cause a segmentation fault.
+ handle.reset();
+}
+
+// Test that we can load a new set of libraries while we have a CalloutHandle
+// created on them in existence, and can delete the handle afterwards.
+
+TEST_F(HooksManagerTest, CalloutHandleLoadLibrary) {
+
+ // Set up the list of libraries to be loaded.
+ std::vector<std::string> library_names;
+ library_names.push_back(std::string(FULL_CALLOUT_LIBRARY));
+
+ // Load the libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Execute the callouts. Thiis library implements:
+ //
+ // r3 = (7 * d1 - d2) * d3
+ {
+ SCOPED_TRACE("Calculation with full callout library loaded");
+ executeCallCallouts(7, 4, 28, 8, 20, 2, 40);
+ }
+
+ // Get an outstanding callout handle on this library and execute one of
+ // the callouts again to ensure that the handle contains memory allocated
+ // by the library.
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+ HooksManager::callCallouts(ServerHooks::CONTEXT_CREATE, *handle);
+
+ // Load a new library that implements the calculation
+ //
+ // r3 = (10 + d1) * d2 - d3
+ std::vector<std::string> new_library_names;
+ new_library_names.push_back(std::string(BASIC_CALLOUT_LIBRARY));
+
+ // Load the libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(new_library_names));
+
+ // Execute the calculation. Note that we still have the CalloutHandle
+ // for the old library: however, this should not affect the new calculation.
+ {
+ SCOPED_TRACE("Calculation with basic callout library loaded");
+ executeCallCallouts(10, 7, 17, 3, 51, 16, 35);
+ }
+
+ // Deleting the old callout handle should not cause a segmentation fault.
+ handle.reset();
+}
+
+// This is effectively the same test as the LoadLibraries test.
+
+TEST_F(HooksManagerTest, ReloadSameLibraries) {
+
+ // Set up the list of libraries to be loaded.
+ std::vector<std::string> library_names;
+ library_names.push_back(std::string(FULL_CALLOUT_LIBRARY));
+ library_names.push_back(std::string(BASIC_CALLOUT_LIBRARY));
+
+ // Load the libraries.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Execute the callouts. See the LoadLibraries test for an explanation of
+ // the calculation.
+ {
+ SCOPED_TRACE("Calculation with libraries loaded");
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
+ }
+
+ // Try reloading the libraries and re-execute the calculation - we should
+ // get the same results.
+ EXPECT_NO_THROW(HooksManager::loadLibraries(library_names));
+ {
+ SCOPED_TRACE("Calculation with libraries reloaded");
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
+ }
+}
+
+TEST_F(HooksManagerTest, ReloadLibrariesReverseOrder) {
+
+ // Set up the list of libraries to be loaded and load them.
+ std::vector<std::string> library_names;
+ library_names.push_back(std::string(FULL_CALLOUT_LIBRARY));
+ library_names.push_back(std::string(BASIC_CALLOUT_LIBRARY));
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Execute the callouts. The first library implements the calculation.
+ //
+ // r3 = (7 * d1 - d2) * d3
+ //
+ // The last-loaded library implements the calculation
+ //
+ // r3 = (10 + d1) * d2 - d3
+ //
+ // Putting the processing for each library together in the given order
+ // gives.
+ //
+ // r3 = ((10 * d1 + d1) - d2) * d2 * d3 - d3
+ {
+ SCOPED_TRACE("Calculation with libraries loaded");
+ executeCallCallouts(10, 3, 33, 2, 62, 3, 183);
+ }
+
+ // Reload the libraries in the reverse order.
+ std::reverse(library_names.begin(), library_names.end());
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // The calculation in the reverse order gives:
+ //
+ // r3 = ((((7 + d1) * d1) * d2 - d2) - d3) * d3
+ {
+ SCOPED_TRACE("Calculation with libraries loaded in reverse order");
+ executeCallCallouts(7, 3, 30, 3, 87, 7, 560);
}
}
-*/
+
+// Local callouts for the test of server-registered callouts.
+
+namespace {
+
+ int
+testPreCallout(CalloutHandle& handle) {
+ handle.setArgument("result", static_cast<int>(1027));
+ return (0);
+}
+
+int
+testPostCallout(CalloutHandle& handle) {
+ int result;
+ handle.getArgument("result", result);
+ result *= 2;
+ handle.setArgument("result", result);
+ return (0);
+}
+
+}
+
+// The next test registers the pre and post- callouts above for hook lm_two,
+// and checks they are called.
+
+TEST_F(HooksManagerTest, PrePostCalloutTest) {
+
+ // Load a single library.
+ std::vector<std::string> library_names;
+ library_names.push_back(std::string(FULL_CALLOUT_LIBRARY));
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+
+ // Load the pre- and post- callouts.
+ HooksManager::preCalloutsLibraryHandle().registerCallout("lm_two",
+ testPreCallout);
+ HooksManager::postCalloutsLibraryHandle().registerCallout("lm_two",
+ testPostCallout);
+
+ // Execute the callouts. lm_two implements the calculation:
+ //
+ // "result - data_2"
+ //
+ // With the pre- and post- callouts above, the result expected is
+ //
+ // (1027 - data_2) * 2
+ CalloutHandlePtr handle = HooksManager::createCalloutHandle();
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(lm_two_index_, *handle);
+
+ int result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(2024, result);
+
+ // ... and check that the pre- and post- callout functions don't survive a
+ // reload.
+ EXPECT_TRUE(HooksManager::loadLibraries(library_names));
+ handle = HooksManager::createCalloutHandle();
+
+ handle->setArgument("result", static_cast<int>(0));
+ handle->setArgument("data_2", static_cast<int>(15));
+
+ HooksManager::callCallouts(lm_two_index_, *handle);
+
+ result = 0;
+ handle->getArgument("result", result);
+ EXPECT_EQ(-15, result);
+}
+
// Check that everything works even with no libraries loaded. First that
// calloutsPresent() always returns false.
@@ -206,4 +415,40 @@ TEST_F(HooksManagerTest, NoLibrariesCallCallouts) {
executeCallCallouts(-1, 3, -1, 22, -1, 83, -1);
}
+// Test the encapsulation of the ServerHooks::registerHook() method.
+
+TEST_F(HooksManagerTest, RegisterHooks) {
+ ServerHooks::getServerHooks().reset();
+ EXPECT_EQ(2, ServerHooks::getServerHooks().getCount());
+
+ // Check that the hook indexes are as expected. (Use temporary variables
+ // as it appears that Google test can't access the constants.)
+ int sh_cc = ServerHooks::CONTEXT_CREATE;
+ int hm_cc = HooksManager::CONTEXT_CREATE;
+ EXPECT_EQ(sh_cc, hm_cc);
+
+ int sh_cd = ServerHooks::CONTEXT_DESTROY;
+ int hm_cd = HooksManager::CONTEXT_DESTROY;
+ EXPECT_EQ(sh_cd, hm_cd);
+
+ // Register a few hooks and check we have the indexes as expected.
+ EXPECT_EQ(2, HooksManager::registerHook(string("alpha")));
+ EXPECT_EQ(3, HooksManager::registerHook(string("beta")));
+ EXPECT_EQ(4, HooksManager::registerHook(string("gamma")));
+ EXPECT_THROW(static_cast<void>(HooksManager::registerHook(string("alpha"))),
+ DuplicateHook);
+
+ // ... an check the hooks are as we expect.
+ EXPECT_EQ(5, ServerHooks::getServerHooks().getCount());
+ vector<string> names = ServerHooks::getServerHooks().getHookNames();
+ sort(names.begin(), names.end());
+
+ EXPECT_EQ(string("alpha"), names[0]);
+ EXPECT_EQ(string("beta"), names[1]);
+ EXPECT_EQ(string("context_create"), names[2]);
+ EXPECT_EQ(string("context_destroy"), names[3]);
+ EXPECT_EQ(string("gamma"), names[4]);
+}
+
+
} // Anonymous namespace
More information about the bind10-changes
mailing list