const char* const LOAD_FUNCTION_NAME = "load";
const char* const UNLOAD_FUNCTION_NAME = "unload";
const char* const VERSION_FUNCTION_NAME = "version";
+const char* const MULTI_THREADING_COMPATIBLE_FUNCTION_NAME =
+ "multi_threading_compatible";
// Typedefs for pointers to the framework functions.
typedef int (*version_function_ptr)();
typedef int (*load_function_ptr)(isc::hooks::LibraryHandle&);
typedef int (*unload_function_ptr)();
+typedef int (*multi_threading_compatible_function_ptr)();
} // Anonymous namespace
-// File created from ../../../src/lib/hooks/hooks_messages.mes on Fri Feb 08 2019 20:16
+// File created from ../../../src/lib/hooks/hooks_messages.mes on Wed Oct 23 2019 00:13
#include <cstddef>
#include <log/message_types.h>
extern const isc::log::MessageID HOOKS_INCORRECT_VERSION = "HOOKS_INCORRECT_VERSION";
extern const isc::log::MessageID HOOKS_LIBRARY_LOADED = "HOOKS_LIBRARY_LOADED";
extern const isc::log::MessageID HOOKS_LIBRARY_LOADING = "HOOKS_LIBRARY_LOADING";
+extern const isc::log::MessageID HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE = "HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE";
+extern const isc::log::MessageID HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE = "HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE";
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOADED = "HOOKS_LIBRARY_UNLOADED";
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOADING = "HOOKS_LIBRARY_UNLOADING";
extern const isc::log::MessageID HOOKS_LIBRARY_VERSION = "HOOKS_LIBRARY_VERSION";
extern const isc::log::MessageID HOOKS_LOAD_EXCEPTION = "HOOKS_LOAD_EXCEPTION";
extern const isc::log::MessageID HOOKS_LOAD_FRAMEWORK_EXCEPTION = "HOOKS_LOAD_FRAMEWORK_EXCEPTION";
extern const isc::log::MessageID HOOKS_LOAD_SUCCESS = "HOOKS_LOAD_SUCCESS";
+extern const isc::log::MessageID HOOKS_MULTI_THREADING_COMPATIBLE_EXCEPTION = "HOOKS_MULTI_THREADING_COMPATIBLE_EXCEPTION";
extern const isc::log::MessageID HOOKS_NO_LOAD = "HOOKS_NO_LOAD";
extern const isc::log::MessageID HOOKS_NO_UNLOAD = "HOOKS_NO_UNLOAD";
extern const isc::log::MessageID HOOKS_NO_VERSION = "HOOKS_NO_VERSION";
"HOOKS_INCORRECT_VERSION", "hook library %1 is at version %2, require version %3",
"HOOKS_LIBRARY_LOADED", "hooks library %1 successfully loaded",
"HOOKS_LIBRARY_LOADING", "loading hooks library %1",
+ "HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE", "hooks library %1 reports its multi-threading compatibility as %2",
+ "HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE", "hooks library %1 is not compatible with multi-threading",
"HOOKS_LIBRARY_UNLOADED", "hooks library %1 successfully unloaded",
"HOOKS_LIBRARY_UNLOADING", "unloading library %1",
"HOOKS_LIBRARY_VERSION", "hooks library %1 reports its version as %2",
"HOOKS_LOAD_EXCEPTION", "'load' function in hook library %1 threw an exception",
"HOOKS_LOAD_FRAMEWORK_EXCEPTION", "'load' function in hook library %1 threw an exception: reason %2",
"HOOKS_LOAD_SUCCESS", "'load' function in hook library %1 returned success",
+ "HOOKS_MULTI_THREADING_COMPATIBLE_EXCEPTION", "'multi_threading_compatible' function in hook library %1 threw an exception",
"HOOKS_NO_LOAD", "no 'load' function found in hook library %1",
"HOOKS_NO_UNLOAD", "no 'unload' function found in hook library %1",
"HOOKS_NO_VERSION", "no 'version' function found in hook library %1",
-// File created from ../../../src/lib/hooks/hooks_messages.mes on Fri Feb 08 2019 20:16
+// File created from ../../../src/lib/hooks/hooks_messages.mes on Wed Oct 23 2019 00:13
#ifndef HOOKS_MESSAGES_H
#define HOOKS_MESSAGES_H
extern const isc::log::MessageID HOOKS_INCORRECT_VERSION;
extern const isc::log::MessageID HOOKS_LIBRARY_LOADED;
extern const isc::log::MessageID HOOKS_LIBRARY_LOADING;
+extern const isc::log::MessageID HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE;
+extern const isc::log::MessageID HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE;
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOADED;
extern const isc::log::MessageID HOOKS_LIBRARY_UNLOADING;
extern const isc::log::MessageID HOOKS_LIBRARY_VERSION;
extern const isc::log::MessageID HOOKS_LOAD_EXCEPTION;
extern const isc::log::MessageID HOOKS_LOAD_FRAMEWORK_EXCEPTION;
extern const isc::log::MessageID HOOKS_LOAD_SUCCESS;
+extern const isc::log::MessageID HOOKS_MULTI_THREADING_COMPATIBLE_EXCEPTION;
extern const isc::log::MessageID HOOKS_NO_LOAD;
extern const isc::log::MessageID HOOKS_NO_UNLOAD;
extern const isc::log::MessageID HOOKS_NO_VERSION;
If the action is successfully, it will be followed by the
HOOKS_LIBRARY_LOADED informational message.
+% HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE hooks library %1 reports its multi-threading compatibility as %2
+A debug message issued when the "multi_threading_compatible" function was
+called. The returned value (0 means not compatible, others compatible)
+is displayed.
+
+% HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE hooks library %1 is not compatible with multi-threading
+When multi-threading is enabled and the library is not compatible (either
+because the "multi_threading_compatible" function returned 0 or was not
+implemented) this error message is issued. The library must be removed
+from the configuration or the multi-threading disabled.
+
% HOOKS_LIBRARY_UNLOADED hooks library %1 successfully unloaded
This information message is issued when a user-supplied hooks library
has been successfully unloaded.
This is a debug message issued when the "load" function has been found
in a hook library and has been successfully called.
+% HOOKS_MULTI_THREADING_COMPATIBLE_EXCEPTION 'multi_threading_compatible' function in hook library %1 threw an exception
+This error message is issued if the multi_threading_compatible()
+function in the specified hooks library was called and generated an
+exception. The library is considered unusable and will not be loaded.
+
% HOOKS_NO_LOAD no 'load' function found in hook library %1
This is a debug message saying that the specified library was loaded
but no function called "load" was found in it. Providing the library
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2019 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
is built
- load - called when the library is loaded by the server.
- unload - called when the library is unloaded by the server.
+- multi_threading_compatible - defines the compatibility (or not) of
+the user-library and a multi-threaded DHCP service.
-Of these, only "version" is mandatory, although in our example, all three
+Of these, only "version" is mandatory, although in our example, all four
are used.
@subsubsection hooksdgVersionFunction The "version" Function
as an error in the current Kea log but otherwise ignore it.
- As before, the function definitions are enclosed in 'extern "C"' braces.
+@subsubsection hooksdgMultiThreadingCompatibleFuntion The
+"multi_threading_compatible" function
+
+"multi_threading_compatible" is used by the hooks framework to check
+if the libraries it is loading are compatible with the DHCPv4 or DHCPv6
+erver multi-threading configuration. The value 0 means not compatible
+and is the default when the function is not implemented. not 0 values
+mean compatible.
+
+To be compatible means:
+- the code associated with DHCP packet processing callouts e.g.
+pkt4_receive or pkt6_send must be reentrant so the multi-threaded DHCP service
+can simultaneously calls more than once on of these callouts.
+- commands a library registers must be reentrant
+- when a library implements a backend API (e.g. host data source) the service
+methods must be reentrant
+- (shall be modified later) a library must not modify the internal
+configuration of the server, e.g. create or delete a subnet.
+
+In the tutoral, we'll put "multi_threading_compatible" in its own file,
+multi_threading_compatible.cc. The contents are:
+
+@code
+// multi_threading_compatible.cc
+
+extern "C" {
+
+int multi_threading_compatible() {
+ return (0);
+}
+
+}
+@endcode
+
@subsection hooksdgCallouts Callouts
Having sorted out the framework, we now come to the functions that
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2019 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
#include <config.h>
#include <exceptions/exceptions.h>
+#if 0
+#include <util/multi_threading_mgr.h>
+#endif
#include <hooks/hooks.h>
#include <hooks/hooks_log.h>
#include <hooks/callout_manager.h>
: dl_handle_(NULL), index_(-1), manager_(), library_name_(name)
{}
-// Destructor.
+// Destructor.
LibraryManager::~LibraryManager() {
if (manager_) {
// LibraryManager instantiated to load a library, so ensure that
return (false);
}
+// Check the multi-threading compatibility of the library
+
+bool
+LibraryManager::checkMultiThreadingCompatible() const {
+
+ // Compatible with single-threaded.
+#if 0
+ if (!MultiThreadingMgr::instance().getMode()) {
+ return (true);
+ }
+#endif
+
+ // Get the pointer to the "multi_threading_compatible" function.
+ PointerConverter pc(dlsym(dl_handle_, MULTI_THREADING_COMPATIBLE_FUNCTION_NAME));
+ int compatible = 0;
+ if (pc.multiThreadingCompatiblePtr()) {
+ try {
+ compatible = (*pc.multiThreadingCompatiblePtr())();
+ } catch (...) {
+ LOG_ERROR(hooks_logger, HOOKS_MULTI_THREADING_COMPATIBLE_EXCEPTION)
+ .arg(library_name_);
+ return (false);
+ }
+
+ LOG_DEBUG(hooks_logger, HOOKS_DBG_CALLS,
+ HOOKS_LIBRARY_MULTI_THREADING_COMPATIBLE)
+ .arg(library_name_)
+ .arg(compatible);
+ }
+ if (compatible == 0) {
+ LOG_ERROR(hooks_logger, HOOKS_LIBRARY_MULTI_THREADING_NOT_COMPATIBLE)
+ .arg(library_name_);
+ }
+ return (compatible != 0);
+}
+
// Register the standard callouts
void
isc::log::LoggerManager::logDuplicatedMessages();
// Library opened OK, see if a version function is present and if so,
- // check what value it returns.
+ // check what value it returns. Check multi-threading compatibility.
+#if 0
+ if (checkVersion() && checkMultiThreadingCompatible()) {
+#else
if (checkVersion()) {
-
+#endif
// Version OK, so now register the standard callouts and call the
// library's load() function if present.
registerStandardCallouts();
LibraryManager manager(name);
// Try to open it and, if we succeed, check the version.
+#if 0
+ bool validated = manager.openLibrary() && manager.checkVersion() &&
+ checkMultiThreadingCompatible();
+#else
bool validated = manager.openLibrary() && manager.checkVersion();
+#endif
// Regardless of whether the version checked out, close the library. (This
// is a no-op if the library failed to open.)
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2019 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
///
/// 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.
+ /// returns the right number, and the multi-threading compatibility.
///
/// @param name Name of the library to validate
///
/// @brief Loads a library
///
- /// Open the library and check the version. If all is OK, load all standard
- /// symbols then call "load" if present.
+ /// 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.
+ /// 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.
///
- /// @return true if the library loaded successfully, false otherwise. In the
- /// latter case, the library will be unloaded if possible.
+ /// @return true if the library loaded successfully, false otherwise.
+ /// In the latter case, the library will be unloaded if possible.
bool loadLibrary();
/// @brief Unloads a library
/// @return bool true if the check succeeded
bool checkVersion() const;
+ /// @brief Check multi-threading compatibility
+ ///
+ /// If the multi-threading mode is false 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.
+ ///
+ /// @return bool true if the check succeeded
+ bool checkMultiThreadingCompatible() const;
+
/// @brief Register standard callouts
///
/// Loops through the list of hook names and searches the library for
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2019 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
return (pointers_.version_ptr);
}
+ /// @brief Return pointer to multi_threading_compatible function
+ ///
+ /// @return Pointer to the multi_threading_compatible function
+ multi_threading_compatible_function_ptr multiThreadingCompatiblePtr() const {
+ return (pointers_.multi_threading_compatible_ptr);
+ }
+
///@}
private:
load_function_ptr load_ptr; // Pointer to load function
unload_function_ptr unload_ptr; // Pointer to unload function
version_function_ptr version_ptr; // Pointer to version function
+ multi_threading_compatible_function_ptr multi_threading_compatible_ptr;
+ // Pointer to multi_threading_compatible function
} pointers_;
};
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2019 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
///
/// The characteristics of this library are:
///
-/// - All three framework functions are supplied (version(), load() and
-/// unload()), with unload() creating a marker file. The test code checks
-/// for the presence of this file, so verifying that unload() has been run.
+/// - All four framework functions are supplied (version(), load(),
+/// unload() and multi_threading_compatible()), with unload()
+/// creating a marker file. The test code checks for the presence
+/// of this file, so verifying that unload() has been run.
///
/// - One standard and two non-standard callouts are supplied, with the latter
/// being registered by the load() function.
return (0);
}
+int
+multi_threading_compatible() {
+ return (1);
+}
+
};
-// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2019 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
#include <log/message_dictionary.h>
#include <log/message_initializer.h>
+#if 0
+#include <util/multi_threading_mgr.h>
+#endif
+
#include <gtest/gtest.h>
#include <algorithm>
using LibraryManager::openLibrary;
using LibraryManager::closeLibrary;
using LibraryManager::checkVersion;
+ using LibraryManager::checkMultiThreadingCompatible;
using LibraryManager::registerStandardCallouts;
using LibraryManager::runLoad;
using LibraryManager::runUnload;
EXPECT_TRUE(lib_manager.closeLibrary());
}
+// Checks that the code handles the case of a library with no
+// multi_threading_compatible function.
+
+TEST_F(LibraryManagerTest, NoMultiThreadingCompatible) {
+ PublicLibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+#if 0
+ // Not multi-threading compatible: does not matter without MT.
+ EXPECT_TRUE(lib_manager.checkMultiThreadingCompatible());
+
+ // Not multi-threading compatible: does matter with MT.
+ //// set MT
+ EXPECT_FALSE(lib_manager.checkMultiThreadingCompatible());
+#endif
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Checks that the code handles the case of a library with a
+// multi_threading_compatible function returning 0 (not compatible).
+
+TEST_F(LibraryManagerTest, multiThreadingNotCompatible) {
+ PublicLibraryManager lib_manager(std::string(LOAD_ERROR_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+#if 0
+ // Not multi-threading compatible: does not matter without MT.
+ EXPECT_TRUE(lib_manager.checkMultiThreadingCompatible());
+
+ // Not multi-threading compatible: does matter with MT.
+ //// set MT
+ EXPECT_FALSE(lib_manager.checkMultiThreadingCompatible());
+#endif
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Checks that the code handles the case of a library with a
+// multi_threading_compatible function returning 1 (compatible)
+
+TEST_F(LibraryManagerTest, multiThreadingCompatible) {
+ PublicLibraryManager lib_manager(std::string(FULL_CALLOUT_LIBRARY),
+ 0, callout_manager_);
+
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+ // Multi-threading compatible: does not matter without MT.
+ EXPECT_TRUE(lib_manager.checkMultiThreadingCompatible());
+
+ // Multi-threading compatible: does matter with MT.
+ //// set MT
+ EXPECT_TRUE(lib_manager.checkMultiThreadingCompatible());
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
+// Checks that the code handles the case of a library with a
+// multi_threading_compatible function returning 1 (compatible)
+
+TEST_F(LibraryManagerTest, multiThreadingCompatibleException) {
+ PublicLibraryManager lib_manager(std::string(FRAMEWORK_EXCEPTION_LIBRARY),
+ 0, callout_manager_);
+
+ // Open should succeed.
+ EXPECT_TRUE(lib_manager.openLibrary());
+
+#if 0
+ // Throw exception: does not matter without MT.
+ EXPECT_FALSE(lib_manager.checkMultiThreadingCompatible());
+#endif
+
+ // Throw exception: does matter with MT.
+ //// set MT
+ EXPECT_FALSE(lib_manager.checkMultiThreadingCompatible());
+
+ // Tidy up.
+ EXPECT_TRUE(lib_manager.closeLibrary());
+}
+
// Checks the registration of standard callouts.
TEST_F(LibraryManagerTest, RegisterStandardCallouts) {
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2019 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
return (1);
}
+int
+multi_threading_compatible() {
+ return (0);
+}
+
};