BIND 10 master, updated. 582bafeae092fe5a1e67b03a0fcd74eba34dfe7f [master] ChangeLog for trac3113.
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Oct 1 13:26:06 UTC 2013
The branch, master has been updated
via 582bafeae092fe5a1e67b03a0fcd74eba34dfe7f (commit)
via 3d19eee4dbfabc7cf7ae528351ee9e3a334cae92 (commit)
via 6660c4b27472285c5876eabf25ecc5b093861371 (commit)
via 242628300d9d7879e1dd90b2020f20274ee3bcf3 (commit)
via e3454067b2f7f83723befe5728b984e510593d0d (commit)
via d21b3e92d6825acb41512747991b94f145d66199 (commit)
via 9e3e043fd5b34eaf866bd590fae3a3a252ac2bff (commit)
via 390b118ab527c2671062d52100137da674ced5c5 (commit)
via 91eca98edcc0af04cbfa27cb684dd3ed680565b9 (commit)
via 38d091beb6348ef3f74175625ffef8348e39c51c (commit)
from bb0ac07b4621308695146918e37d4f2a68e2a9bd (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 582bafeae092fe5a1e67b03a0fcd74eba34dfe7f
Author: Stephen Morris <stephen at isc.org>
Date: Tue Oct 1 14:23:33 2013 +0100
[master] ChangeLog for trac3113.
commit 3d19eee4dbfabc7cf7ae528351ee9e3a334cae92
Merge: bb0ac07 6660c4b
Author: Stephen Morris <stephen at isc.org>
Date: Tue Oct 1 14:16:40 2013 +0100
[master] Merge branch 'trac3113'
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 8 +-
configure.ac | 1 +
src/bin/dhcp4/tests/Makefile.am | 20 +++-
src/bin/dhcp4/tests/test_libraries.h.in | 20 +---
src/bin/dhcp6/tests/Makefile.am | 20 +++-
src/bin/dhcp6/tests/test_libraries.h.in | 22 +---
src/lib/asiodns/Makefile.am | 3 +-
src/lib/dhcpsrv/tests/Makefile.am | 24 ++--
src/lib/dhcpsrv/tests/test_libraries.h.in | 22 +---
src/lib/hooks/Makefile.am | 2 +-
src/lib/hooks/callout_handle.cc | 5 +-
src/lib/hooks/callout_handle.h | 7 ++
src/lib/hooks/callout_manager.cc | 17 ++-
src/lib/hooks/callout_manager.h | 7 ++
src/{bin/d2/d2_log.h => lib/hooks/hooks.cc} | 24 ++--
src/lib/hooks/hooks.h | 39 ++++++
src/lib/hooks/hooks_maintenance.dox | 108 +++++++++++++++++
src/lib/hooks/hooks_messages.mes | 15 +++
src/lib/hooks/hooks_user.dox | 164 ++++++++++++++++----------
src/lib/hooks/library_manager.cc | 9 ++
src/lib/hooks/tests/Makefile.am | 64 ++++++++--
src/lib/hooks/tests/basic_callout_library.cc | 25 ++--
src/lib/hooks/tests/full_callout_library.cc | 8 +-
src/lib/hooks/tests/load_callout_library.cc | 8 +-
src/lib/hooks/tests/test_libraries.h.in | 39 ++----
src/lib/log/logger.cc | 5 +
src/lib/resolve/Makefile.am | 1 +
src/lib/testutils/Makefile.am | 3 +-
28 files changed, 481 insertions(+), 209 deletions(-)
copy src/{bin/d2/d2_log.h => lib/hooks/hooks.cc} (75%)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index c2f4162..984582c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,16 @@
+683. [bug] stephen
+ Modifications to fix problems running unit tests if they are statically
+ linked. This includes provision of an initialization function that
+ must be called by user-written hooks libraries if they are loaded by a
+ statically-linked image.
+ (Trac #3113, git 3d19eee4dbfabc7cf7ae528351ee9e3a334cae92)
+
682. [func] naokikambe
New statistics items added into b10-xfrin : ixfr_running, axfr_running,
and soa_in_progress. Their values can be obtained by invoking "Stats
show Xfrin" via bindctl when b10-xfrin is running.
(Trac #2274, git ca691626a2be16f08754177bb27983a9f4984702)
-
681. [func] tmark
Added support for prefix delegation configuration to b10-dhcp6
subnets.
diff --git a/configure.ac b/configure.ac
index 9dcd39b..7786ab5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -181,6 +181,7 @@ AC_HELP_STRING([--enable-static-link],
[build programs with static link [[default=no]]]),
[enable_static_link=yes], [enable_static_link=no])
AM_CONDITIONAL(USE_STATIC_LINK, test $enable_static_link = yes)
+AM_COND_IF([USE_STATIC_LINK], [AC_DEFINE([USE_STATIC_LINK], [1], [BIND 10 was statically linked?])])
# Check validity about some libtool options
if test $enable_static_link = yes -a $enable_static = no; then
diff --git a/src/bin/dhcp4/tests/Makefile.am b/src/bin/dhcp4/tests/Makefile.am
index fc7eabf..3b7691f 100644
--- a/src/bin/dhcp4/tests/Makefile.am
+++ b/src/bin/dhcp4/tests/Makefile.am
@@ -40,25 +40,35 @@ if USE_CLANGPP
AM_CXXFLAGS += -Wno-unused-parameter
endif
-if USE_STATIC_LINK
-AM_LDFLAGS = -static
-endif
-
TESTS_ENVIRONMENT = \
$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
TESTS =
if HAVE_GTEST
-# Build shared libraries for testing.
+# Build shared libraries for testing. The libtool way to create a shared library
+# is to specify "-avoid-version -export-dynamic -module" in the library LDFLAGS
+# (see http://www.gnu.org/software/libtool/manual/html_node/Link-mode.html).
+# Use of these switches will guarantee that the .so files are created in the
+# .libs folder and they can be dlopened.
+# Note that the shared libraries with callouts should not be used together with
+# the --enable-static-link option. With this option, the bind10 libraries are
+# statically linked with the program and if the callout invokes the methods
+# which belong to these libraries, the library with the callout will get its
+# own copy of the static objects (e.g. logger, ServerHooks) and that will lead
+# to unexpected errors. For this reason, the --enable-static-link option is
+# ignored for unit tests built here.
+
lib_LTLIBRARIES = libco1.la libco2.la
libco1_la_SOURCES = callout_library_1.cc callout_library_common.h
libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
libco1_la_CPPFLAGS = $(AM_CPPFLAGS)
+libco1_la_LDFLAGS = -avoid-version -export-dynamic -module
libco2_la_SOURCES = callout_library_2.cc callout_library_common.h
libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
libco2_la_CPPFLAGS = $(AM_CPPFLAGS)
+libco2_la_LDFLAGS = -avoid-version -export-dynamic -module
TESTS += dhcp4_unittests
diff --git a/src/bin/dhcp4/tests/test_libraries.h.in b/src/bin/dhcp4/tests/test_libraries.h.in
index 8b03dc2..1cddf00 100644
--- a/src/bin/dhcp4/tests/test_libraries.h.in
+++ b/src/bin/dhcp4/tests/test_libraries.h.in
@@ -19,32 +19,20 @@
namespace {
-
-// Take care of differences in DLL naming between operating systems.
-
-#ifdef OS_OSX
-#define DLL_SUFFIX ".dylib"
-
-#else
#define DLL_SUFFIX ".so"
-#endif
-
-
// Names of the libraries used in these tests. These libraries are built using
// libtool, so we need to look in the hidden ".libs" directory to locate the
// shared library.
// Library with load/unload functions creating marker files to check their
// operation.
-const char* const CALLOUT_LIBRARY_1 = "@abs_builddir@/.libs/libco1"
- DLL_SUFFIX;
-const char* const CALLOUT_LIBRARY_2 = "@abs_builddir@/.libs/libco2"
- DLL_SUFFIX;
+const char* const CALLOUT_LIBRARY_1 = "@abs_builddir@/.libs/libco1.so";
+const char* const CALLOUT_LIBRARY_2 = "@abs_builddir@/.libs/libco2.so";
// Name of a library which is not present.
-const char* const NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere"
- DLL_SUFFIX;
+const char* const NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere.so";
+
} // anonymous namespace
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index 7ea7163..19c6dea 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -36,25 +36,35 @@ if USE_CLANGPP
AM_CXXFLAGS += -Wno-unused-parameter
endif
-if USE_STATIC_LINK
-AM_LDFLAGS = -static
-endif
-
TESTS_ENVIRONMENT = \
$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
TESTS =
if HAVE_GTEST
-# Build shared libraries for testing.
+# Build shared libraries for testing. The libtool way to create a shared library
+# is to specify "-avoid-version -export-dynamic -module" in the library LDFLAGS
+# (see http://www.gnu.org/software/libtool/manual/html_node/Link-mode.html).
+# Use of these switches will guarantee that the .so files are created in the
+# .libs folder and they can be dlopened.
+# Note that the shared libraries with callouts should not be used together with
+# the --enable-static-link option. With this option, the bind10 libraries are
+# statically linked with the program and if the callout invokes the methods
+# which belong to these libraries, the library with the callout will get its
+# own copy of the static objects (e.g. logger, ServerHooks) and that will lead
+# to unexpected errors. For this reason, the --enable-static-link option is
+# ignored for unit tests built here.
+
lib_LTLIBRARIES = libco1.la libco2.la
libco1_la_SOURCES = callout_library_1.cc callout_library_common.h
libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
libco1_la_CPPFLAGS = $(AM_CPPFLAGS)
+libco1_la_LDFLAGS = -avoid-version -export-dynamic -module
libco2_la_SOURCES = callout_library_2.cc callout_library_common.h
libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
libco2_la_CPPFLAGS = $(AM_CPPFLAGS)
+libco2_la_LDFLAGS = -avoid-version -export-dynamic -module
TESTS += dhcp6_unittests
dhcp6_unittests_SOURCES = dhcp6_unittests.cc
diff --git a/src/bin/dhcp6/tests/test_libraries.h.in b/src/bin/dhcp6/tests/test_libraries.h.in
index 8b03dc2..f25d9e2 100644
--- a/src/bin/dhcp6/tests/test_libraries.h.in
+++ b/src/bin/dhcp6/tests/test_libraries.h.in
@@ -19,32 +19,18 @@
namespace {
-
-// Take care of differences in DLL naming between operating systems.
-
-#ifdef OS_OSX
-#define DLL_SUFFIX ".dylib"
-
-#else
-#define DLL_SUFFIX ".so"
-
-#endif
-
-
// Names of the libraries used in these tests. These libraries are built using
// libtool, so we need to look in the hidden ".libs" directory to locate the
// shared library.
// Library with load/unload functions creating marker files to check their
// operation.
-const char* const CALLOUT_LIBRARY_1 = "@abs_builddir@/.libs/libco1"
- DLL_SUFFIX;
-const char* const CALLOUT_LIBRARY_2 = "@abs_builddir@/.libs/libco2"
- DLL_SUFFIX;
+const char* const CALLOUT_LIBRARY_1 = "@abs_builddir@/.libs/libco1.so";
+const char* const CALLOUT_LIBRARY_2 = "@abs_builddir@/.libs/libco2.so";
// Name of a library which is not present.
-const char* const NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere"
- DLL_SUFFIX;
+const char* const NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere.so";
+
} // anonymous namespace
diff --git a/src/lib/asiodns/Makefile.am b/src/lib/asiodns/Makefile.am
index 930c870..5fc436d 100644
--- a/src/lib/asiodns/Makefile.am
+++ b/src/lib/asiodns/Makefile.am
@@ -43,4 +43,5 @@ if USE_CLANGPP
libb10_asiodns_la_CXXFLAGS += -Wno-error
endif
libb10_asiodns_la_CPPFLAGS = $(AM_CPPFLAGS)
-libb10_asiodns_la_LIBADD = $(top_builddir)/src/lib/log/libb10-log.la
+libb10_asiodns_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+libb10_asiodns_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.la
diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am
index 087b28d..546ced9 100644
--- a/src/lib/dhcpsrv/tests/Makefile.am
+++ b/src/lib/dhcpsrv/tests/Makefile.am
@@ -13,11 +13,6 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
# But older GCC compilers don't have the flag.
AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
-if USE_STATIC_LINK
-AM_LDFLAGS = -static
-TEST_LIBS_LDFLAGS = -Bshareable
-endif
-
CLEANFILES = *.gcno *.gcda
TESTS_ENVIRONMENT = \
@@ -25,19 +20,30 @@ TESTS_ENVIRONMENT = \
TESTS =
if HAVE_GTEST
-# Build shared libraries for testing.
+# Build shared libraries for testing. The libtool way to create a shared library
+# is to specify "-avoid-version -export-dynamic -module" in the library LDFLAGS
+# (see http://www.gnu.org/software/libtool/manual/html_node/Link-mode.html).
+# Use of these switches will guarantee that the .so files are created in the
+# .libs folder and they can be dlopened.
+# Note that the shared libraries with callouts should not be used together with
+# the --enable-static-link option. With this option, the bind10 libraries are
+# statically linked with the program and if the callout invokes the methods
+# which belong to these libraries, the library with the callout will get its
+# own copy of the static objects (e.g. logger, ServerHooks) and that will lead
+# to unexpected errors. For this reason, the --enable-static-link option is
+# ignored for unit tests built here.
+
lib_LTLIBRARIES = libco1.la libco2.la
libco1_la_SOURCES = callout_library.cc
libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
libco1_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
-libco1_la_LDFLAGS = $(TEST_LIBS_LDFLAGS)
+libco1_la_LDFLAGS = -avoid-version -export-dynamic -module
libco2_la_SOURCES = callout_library.cc
libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
libco2_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
-libco2_la_LDFLAGS = $(TEST_LIBS_LDFLAGS)
-
+libco2_la_LDFLAGS = -avoid-version -export-dynamic -module
TESTS += libdhcpsrv_unittests
diff --git a/src/lib/dhcpsrv/tests/test_libraries.h.in b/src/lib/dhcpsrv/tests/test_libraries.h.in
index b5e80a0..a2843dd 100644
--- a/src/lib/dhcpsrv/tests/test_libraries.h.in
+++ b/src/lib/dhcpsrv/tests/test_libraries.h.in
@@ -19,32 +19,18 @@
namespace {
-
-// Take care of differences in DLL naming between operating systems.
-
-#ifdef OS_OSX
-#define DLL_SUFFIX ".dylib"
-
-#else
-#define DLL_SUFFIX ".so"
-
-#endif
-
-
// Names of the libraries used in these tests. These libraries are built using
// libtool, so we need to look in the hidden ".libs" directory to locate the
// shared library.
// Library with load/unload functions creating marker files to check their
// operation.
-static const char* CALLOUT_LIBRARY_1 = "@abs_builddir@/.libs/libco1"
- DLL_SUFFIX;
-static const char* CALLOUT_LIBRARY_2 = "@abs_builddir@/.libs/libco2"
- DLL_SUFFIX;
+static const char* CALLOUT_LIBRARY_1 = "@abs_builddir@/.libs/libco1.so";
+static const char* CALLOUT_LIBRARY_2 = "@abs_builddir@/.libs/libco2.so";
// Name of a library which is not present.
-static const char* NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere"
- DLL_SUFFIX;
+static const char* NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere.so";
+
} // anonymous namespace
diff --git a/src/lib/hooks/Makefile.am b/src/lib/hooks/Makefile.am
index 4f81e67..a8d7af1 100644
--- a/src/lib/hooks/Makefile.am
+++ b/src/lib/hooks/Makefile.am
@@ -32,7 +32,7 @@ lib_LTLIBRARIES = libb10-hooks.la
libb10_hooks_la_SOURCES =
libb10_hooks_la_SOURCES += callout_handle.cc callout_handle.h
libb10_hooks_la_SOURCES += callout_manager.cc callout_manager.h
-libb10_hooks_la_SOURCES += hooks.h
+libb10_hooks_la_SOURCES += hooks.h hooks.cc
libb10_hooks_la_SOURCES += hooks_log.cc hooks_log.h
libb10_hooks_la_SOURCES += hooks_manager.cc hooks_manager.h
libb10_hooks_la_SOURCES += library_handle.cc library_handle.h
diff --git a/src/lib/hooks/callout_handle.cc b/src/lib/hooks/callout_handle.cc
index ce9ef82..cbd992c 100644
--- a/src/lib/hooks/callout_handle.cc
+++ b/src/lib/hooks/callout_handle.cc
@@ -30,7 +30,8 @@ namespace hooks {
CalloutHandle::CalloutHandle(const boost::shared_ptr<CalloutManager>& manager,
const boost::shared_ptr<LibraryManagerCollection>& lmcoll)
: lm_collection_(lmcoll), arguments_(), context_collection_(),
- manager_(manager), skip_(false) {
+ manager_(manager), server_hooks_(ServerHooks::getServerHooks()),
+ skip_(false) {
// Call the "context_create" hook. We should be OK doing this - although
// the constructor has not finished running, all the member variables
@@ -148,7 +149,7 @@ CalloutHandle::getHookName() const {
// ... and look up the hook.
string hook = "";
try {
- hook = ServerHooks::getServerHooks().getName(index);
+ hook = server_hooks_.getName(index);
} catch (const NoSuchHook&) {
// Hook index is invalid, so this methods probably called from outside
// a callout being executed via a call to CalloutManager::callCallouts.
diff --git a/src/lib/hooks/callout_handle.h b/src/lib/hooks/callout_handle.h
index eb57fd4..91d7f23 100644
--- a/src/lib/hooks/callout_handle.h
+++ b/src/lib/hooks/callout_handle.h
@@ -28,6 +28,8 @@
namespace isc {
namespace hooks {
+class ServerHooks;
+
/// @brief No such argument
///
/// Thrown if an attempt is made access an argument that does not exist.
@@ -369,6 +371,11 @@ private:
/// Callout manager.
boost::shared_ptr<CalloutManager> manager_;
+ /// Reference to the singleton ServerHooks object. See the
+ /// @ref hooksmgMaintenanceGuide for information as to why the class holds
+ /// a reference instead of accessing the singleton within the code.
+ ServerHooks& server_hooks_;
+
/// "Skip" flag, indicating if the caller should bypass remaining callouts.
bool skip_;
};
diff --git a/src/lib/hooks/callout_manager.cc b/src/lib/hooks/callout_manager.cc
index 166fda1..9dd5c60 100644
--- a/src/lib/hooks/callout_manager.cc
+++ b/src/lib/hooks/callout_manager.cc
@@ -31,7 +31,8 @@ namespace hooks {
// Constructor
CalloutManager::CalloutManager(int num_libraries)
- : current_hook_(-1), current_library_(-1),
+ : server_hooks_(ServerHooks::getServerHooks()),
+ current_hook_(-1), current_library_(-1),
hook_vector_(ServerHooks::getServerHooks().getCount()),
library_handle_(this), pre_library_handle_(this, 0),
post_library_handle_(this, INT_MAX), num_libraries_(num_libraries)
@@ -72,7 +73,7 @@ CalloutManager::registerCallout(const std::string& name, CalloutPtr callout) {
// Get the index associated with this hook (validating the name in the
// process).
- int hook_index = ServerHooks::getServerHooks().getIndex(name);
+ int hook_index = server_hooks_.getIndex(name);
// Iterate through the callout vector for the hook from start to end,
// looking for the first entry where the library index is greater than
@@ -147,21 +148,19 @@ CalloutManager::callCallouts(int hook_index, CalloutHandle& callout_handle) {
if (status == 0) {
LOG_DEBUG(hooks_logger, HOOKS_DBG_EXTENDED_CALLS,
HOOKS_CALLOUT_CALLED).arg(current_library_)
- .arg(ServerHooks::getServerHooks()
- .getName(current_hook_))
+ .arg(server_hooks_.getName(current_hook_))
.arg(PointerConverter(i->second).dlsymPtr());
} else {
LOG_ERROR(hooks_logger, HOOKS_CALLOUT_ERROR)
.arg(current_library_)
- .arg(ServerHooks::getServerHooks()
- .getName(current_hook_))
+ .arg(server_hooks_.getName(current_hook_))
.arg(PointerConverter(i->second).dlsymPtr());
}
} catch (const std::exception& e) {
// Any exception, not just ones based on isc::Exception
LOG_ERROR(hooks_logger, HOOKS_CALLOUT_EXCEPTION)
.arg(current_library_)
- .arg(ServerHooks::getServerHooks().getName(current_hook_))
+ .arg(server_hooks_.getName(current_hook_))
.arg(PointerConverter(i->second).dlsymPtr())
.arg(e.what());
}
@@ -184,7 +183,7 @@ CalloutManager::deregisterCallout(const std::string& name, CalloutPtr callout) {
// Get the index associated with this hook (validating the name in the
// process).
- int hook_index = ServerHooks::getServerHooks().getIndex(name);
+ int hook_index = server_hooks_.getIndex(name);
/// Construct a CalloutEntry matching the current library and the callout
/// we want to remove.
@@ -227,7 +226,7 @@ CalloutManager::deregisterAllCallouts(const std::string& name) {
// Get the index associated with this hook (validating the name in the
// process).
- int hook_index = ServerHooks::getServerHooks().getIndex(name);
+ int hook_index = server_hooks_.getIndex(name);
/// Construct a CalloutEntry matching the current library (the callout
/// pointer is NULL as we are not checking that).
diff --git a/src/lib/hooks/callout_manager.h b/src/lib/hooks/callout_manager.h
index e1b9e57..8ca275b 100644
--- a/src/lib/hooks/callout_manager.h
+++ b/src/lib/hooks/callout_manager.h
@@ -338,6 +338,13 @@ private:
}
};
+ // Member variables
+
+ /// Reference to the singleton ServerHooks object. See the
+ /// @ref hooksmgMaintenanceGuide for information as to why the class holds
+ /// a reference instead of accessing the singleton within the code.
+ ServerHooks& server_hooks_;
+
/// Current hook. When a call is made to callCallouts, this holds the
/// index of the current hook. It is set to an invalid value (-1)
/// otherwise.
diff --git a/src/lib/hooks/hooks.cc b/src/lib/hooks/hooks.cc
new file mode 100644
index 0000000..e5645d5
--- /dev/null
+++ b/src/lib/hooks/hooks.cc
@@ -0,0 +1,34 @@
+// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <hooks/hooks.h>
+#include <log/logger_support.h>
+
+#include <string>
+
+
+namespace isc {
+namespace hooks {
+
+// Load the logging message dictionary if not already loaded
+
+void
+hooksStaticLinkInit() {
+ if (!isc::log::isLoggingInitialized()) {
+ isc::log::initLogger(std::string("userlib"));
+ }
+}
+
+} // namespace hooks
+} // namespace isc
diff --git a/src/lib/hooks/hooks.h b/src/lib/hooks/hooks.h
index a059d79..42dfaca 100644
--- a/src/lib/hooks/hooks.h
+++ b/src/lib/hooks/hooks.h
@@ -15,6 +15,7 @@
#ifndef HOOKS_H
#define HOOKS_H
+#include <config.h>
#include <hooks/callout_handle.h>
#include <hooks/library_handle.h>
@@ -35,4 +36,42 @@ typedef int (*unload_function_ptr)();
} // Anonymous namespace
+namespace isc {
+namespace hooks {
+
+/// @brief User-Library Initialization for Statically-Linked BIND 10
+///
+/// If BIND 10 is statically-linked, a user-created hooks library will not be
+/// able to access symbols in it. In particular, it will not be able to access
+/// singleton objects.
+///
+/// The hooks framework handles some of this. For example, although there is
+/// a singleton ServerHooks object, hooks framework objects store a reference
+/// to it when they are created. When the user library needs to register a
+/// callout (which requires access to the ServerHooks information), it accesses
+/// the ServerHooks object through a pointer passed from the BIND 10 image.
+///
+/// The logging framework is more problematical. Here the code is partly
+/// statically linked (the BIND 10 logging library) and partly shared (the
+/// log4cplus). The state of the former is not accessible to the user library,
+/// but the state of the latter is. So within the user library, we need to
+/// initialize the BIND 10 logging library but not initialize the log4cplus
+/// code. Some of the initialization is done when the library is loaded, but
+/// other parts are done at run-time.
+///
+/// This function - to be called by the user library code in its load() function
+/// when running against a statically linked BIND 10 - initializes the BIND 10
+/// logging library. In particular, it loads the message dictionary with the
+/// text of the BIND 10 messages.
+///
+/// @note This means that the virtual address space is loaded with two copies
+/// of the message dictionary. Depending on how the user libraries are linked,
+/// loading multiple user libraries may involve loading one message dictionary
+/// per library.
+
+void hooksStaticLinkInit();
+
+} // namespace hooks
+} // namespace isc
+
#endif // HOOKS_H
diff --git a/src/lib/hooks/hooks_maintenance.dox b/src/lib/hooks/hooks_maintenance.dox
index c3c4946..51a07dc 100644
--- a/src/lib/hooks/hooks_maintenance.dox
+++ b/src/lib/hooks/hooks_maintenance.dox
@@ -271,4 +271,112 @@
this may mean the server suspending all processing of incoming requests
until all currently executing requests have completed and data object
destroyed, reloading the libraries, then resuming processing.
+
+ @subsection hooksmgStaticLinking Hooks and Statically-Linked BIND 10
+
+ BIND 10 has the configuration option to allow static linking. What this
+ means is that it links against the static BIND 10 libraries and not
+ the shareable ones - although it links against the shareable system
+ libraries like "libc" and "libstdc++" and well as the sharable libraries
+ for third-party packages such as log4cplus and MySql.
+
+ Static linking poses a problem for dynamically-loaded hooks libraries
+ as some of the code in them - in particular the hooks framework and
+ the logging code - depend on global objects created within the BIND
+ 10 libraries. In the normal course of events (BIND 10 linked against
+ shared libraries), when BIND 10 is run and the operating system loads
+ a BIND 10 shared library containing a global object, address space
+ is assigned for it. When the hooks framework loads a user-library
+ linked against the same BIND 10 shared library, the operating system
+ recognises that the library is already loaded (and initialized) and
+ uses its definition of the global object. Thus both the code in the
+ BIND 10 image and the code in the user-written shared library
+ reference the same object.
+
+ If BIND 10 is statically linked, the linker allocates address space
+ in the BIND 10 image for the global object and does not include any
+ reference to the shared library containing it. When BIND 10 now loads
+ the user-written shared library - and so loads the BIND 10 library code
+ containing the global object - the operating system does not know that
+ the object already exists. Instead, it allocates new address space.
+ The version of BIND 10 in memory therefore has two copies of the object:
+ one referenced by code in the BIND 10 image, and one referenced by code
+ in the user-written hooks library. This causes problems - information
+ put in one copy is not available to the other.
+
+ Particular problems were encountered with global objects the hooks library
+ and in the logging library, so some code to alleviate the problem has been
+ included.
+
+ The issue in the hooks library is the singleton @ref
+ isc::hooks::ServerHooks object, used by the user-written hooks library
+ if it attempts to register or deregister callouts. The contents of the
+ singleton - the names of the hook points and their index - are set by
+ the relevant BIND 10 server; this information is not available in the
+ singleton created in the user's hooks library.
+
+ Within the code users by the user's hooks library, the ServerHooks
+ object is used by @ref isc::hooks::CalloutHandle and @ref
+ isc::hooks::CalloutManager objects. Both these objects are passed to the
+ hooks library code when a callout is called: the former directly through
+ the callout argument list, the latter indirectly as a pointer to it is
+ stored in the CalloutHandle. This allows a solution to the problem:
+ instead of accessing the singleton via ServerHooks::getServerHooks(),
+ the constructors of these objects store a reference to the singleton
+ ServerHooks when they are created and use that reference to access
+ ServerHooks data. Since both CalloutHandle and CalloutManager are
+ created in the statically-linked BIND 10 server, use of the reference
+ means that it is the singleton within the server - and not the one
+ within the user's hooks library - that is referenced.
+
+ The solution of the logging problem is not so straightforward. Within
+ BIND 10, there are two logging components, the BIND 10 logging framework
+ and the log4cplus libraries. Owing to static linking, there are two
+ instances of the former; but as static linking uses shared libraries of
+ third-party products, there is one instance of the latter. What further
+ complicates matters is that initialization of the logging framework is
+ in two parts: static initialization and run-time initialization.
+
+ The logging initialization comprises the following:
+
+ -# Static initialization of the log4cplus global variables.
+ -# Static initialization of messages in the various BIND 10 libraries.
+ -# Static initialization of logging framework.
+ -# Run-time initialization of the logging framework.
+ -# Run-time initialization of log4cplus
+
+ As both the BIND 10 server and the user-written hooks libraries use the
+ log4cplus shared library, item 1 - the static initialization of the log4cplus
+ global variables is performed once.
+
+ The next two tasks - static initialization of the messages in the BIND
+ 10 libraries and the static initialization of the logging framework -
+ are performed twice, once in the context of the BIND 10 server and
+ once in the context of the hooks library. For this reason, run-time
+ initialization of the logging framework needs to be performed twice,
+ once in the context of the BIND 10 server and once in the context of the
+ user-written hooks library. However, the standard logging framework
+ initialization code also performs the last task, initialization of
+ log4cplus, something that causes problems if executed more than once.
+
+ To get round this, the function isc::hooks::hooksStaticLinkInit()
+ has been written. It executes the only part of the logging framework
+ run-time initialization that actually pertains to the logging framework
+ and not log4cplus, namely loading the message dictionary with the
+ statically-initialized messages in the BIND 10 libraries.
+ This should be executed by any hooks library linking against a statically
+ initialized BIND 10. (In fact, running it against a dynamically-linked
+ BIND 10 should have no effect, as the load operation discards any duplicate
+ message entries.) The hooks library tests do this, the code being
+ copnditionally compiled within a test of the USE_STATIC_LINK macro, set
+ by the configure script.
+
+ @note Not everything is completely rosy with logging and static linking.
+ In particular, there appears to be an issue with the scenario where a
+ user-written hooks library is run by a statically-linked BIND 10 and then
+ unloaded. As far as can be determined, on unload the system attempts to
+ delete the same logger twice. This is alleviated by explictly clearing
+ the loggerptr_ variable in the isc::log::Logger destructor, but there
+ is a suspicion that some memory might be lost in these circumstances.
+ This is still under investigation.
*/
diff --git a/src/lib/hooks/hooks_messages.mes b/src/lib/hooks/hooks_messages.mes
index ebaed41..53090ab 100644
--- a/src/lib/hooks/hooks_messages.mes
+++ b/src/lib/hooks/hooks_messages.mes
@@ -109,6 +109,14 @@ was called. The function threw an exception (an error indication)
during execution, which is an error condition. The library has been
unloaded and no callouts from it will be installed.
+% HOOKS_LOAD_FRAMEWORK_EXCEPTION 'load' function in hook library %1 threw an exception: reason %2
+A "load" function was found in the library named in the message and
+was called. Either the hooks framework or the function threw an
+exception (an error indication) during execution, which is an error
+condition; the cause of the exception is recorded in the message.
+The library has been unloaded and no callouts from it will be
+installed.
+
% HOOKS_LOAD_SUCCESS 'load' function in hook library %1 returned success
This is a debug message issued when the "load" function has been found
in a hook library and has been successfully called.
@@ -152,6 +160,13 @@ called, but in the process generated an exception (an error indication).
The unload process continued after this message and the library has
been unloaded.
+% HOOKS_UNLOAD_FRAMEWORK_EXCEPTION 'unload' function in hook library %1 threw an exception, reason %2
+During the unloading of a library, an "unload" function was found.
+It was called, but in the process either it or the hooks framework
+generated an exception (an error indication); the cause of the error
+is recorded in the message. The unload process continued after
+this message and the library has been unloaded.
+
% HOOKS_UNLOAD_SUCCESS 'unload' function in hook library %1 returned success
This is a debug message issued when an "unload" function has been found
in a hook library during the unload process, called, and returned success.
diff --git a/src/lib/hooks/hooks_user.dox b/src/lib/hooks/hooks_user.dox
index 8aa75c1..9c56861 100644
--- a/src/lib/hooks/hooks_user.dox
+++ b/src/lib/hooks/hooks_user.dox
@@ -156,7 +156,7 @@ int version() {
return (BIND10_HOOKS_VERSION);
}
-};
+}
@endcode
The file "hooks/hooks.h" is specified relative to the BIND 10 libraries
@@ -211,6 +211,8 @@ extern std::fstream interesting;
#include <hooks/hooks.h>
#include "library_common.h"
+using namespace isc::hooks;
+
// "Interesting clients" log file handle definition.
std::fstream interesting;
@@ -229,7 +231,7 @@ int unload() {
return (0);
}
-};
+}
@endcode
Notes:
@@ -276,7 +278,7 @@ All callouts are declared with the signature:
@code
extern "C" {
int callout(CalloutHandle& handle);
-};
+}
@endcode
(As before, the callout is declared with "C" linkage.) Information is passed
@@ -454,16 +456,15 @@ hardware address of the incoming packet, classify it, and write it,
together with the assigned IP address, to a log file. Although we could
do this in one callout, for this example we'll use two:
-- pkt_rcvd - a callout on this hook is invoked when a packet has been
-received and has been parsed. It is passed a single argument, "query"
+- pkt4_receive - a callout on this hook is invoked when a packet has been
+received and has been parsed. It is passed a single argument, "query4"
which is an isc::dhcp::Pkt4 object (representing a DHCP v4 packet).
We will do the classification here.
-- v4_lease_write_post - called when the lease (an assignment of an IPv4
-address to a client for a fixed period of time) has been written to the
-database. It is passed two arguments, the query ("query")
-and the response (called "reply"). This is the point at which the
-example code will write the hardware and IP addresses to the log file.
+- pkt4_send - called when a response is just about to be sent back to
+the client. It is passed a single argument "response4". This is the
+point at which the example code will write the hardware and IP addresses
+to the log file.
The standard for naming callouts is to give them the same name as
the hook. If this is done, the callouts will be automatically found
@@ -473,7 +474,7 @@ case, so the code for the first callout (used to classify the client's
hardware address) is:
@code
-// pkt_rcvd.cc
+// pkt_receive4.cc
#include <hooks/hooks.h>
#include <dhcp/pkt4.h>
@@ -482,47 +483,51 @@ hardware address) is:
#include <string>
using namespace isc::dhcp;
+using namespace isc::hooks;
using namespace std;
extern "C" {
-// This callout is called at the "pkt_rcvd" hook.
-int pkt_rcvd(CalloutHandle& handle) {
+// This callout is called at the "pkt4_receive" hook.
+int pkt4_receive(CalloutHandle& handle) {
// A pointer to the packet is passed to the callout via a "boost" smart
// pointer. The include file "pkt4.h" typedefs a pointer to the Pkt4
// object as Pkt4Ptr. Retrieve a pointer to the object.
- Pkt4Ptr query_ptr;
- handle.getArgument("query", query_ptr);
+ Pkt4Ptr query4_ptr;
+ handle.getArgument("query4", query4_ptr);
// Point to the hardware address.
- HwAddrPtr hwaddr_ptr = query_ptr->getHWAddr();
+ HWAddrPtr hwaddr_ptr = query4_ptr->getHWAddr();
// The hardware address is held in a public member variable. We'll classify
// it as interesting if the sum of all the bytes in it is divisible by 4.
// (This is a contrived example after all!)
long sum = 0;
for (int i = 0; i < hwaddr_ptr->hwaddr_.size(); ++i) {
- sum += hwaddr_ptr->hwadr_[i];
+ sum += hwaddr_ptr->hwaddr_[i];
}
// Classify it.
if (sum % 4 == 0) {
// Store the text form of the hardware address in the context to pass
// to the next callout.
- handle.setContext("hwaddr", hwaddr_ptr->hwaddr_.toText());
+ string hwaddr = hwaddr_ptr->toText();
+ handle.setContext("hwaddr", hwaddr);
}
return (0);
};
+
+}
@endcode
-The pct_rcvd callout placed the hardware address of an interesting client in
+The pkt4_receive callout placed the hardware address of an interesting client in
the "hwaddr" context for the packet. Turning now to the callout that will
write this information to the log file:
@code
-// v4_lease_write.cc
+// pkt4_send.cc
#include <hooks/hooks.h>
#include <dhcp/pkt4.h>
@@ -531,28 +536,28 @@ write this information to the log file:
#include <string>
using namespace isc::dhcp;
+using namespace isc::hooks;
using namespace std;
extern "C" {
-// This callout is called at the "v4_lease_write_post" hook.
-int v4_lease_write_post(CalloutHandle& handle) {
+// This callout is called at the "pkt4_send" hook.
+int pkt4_send(CalloutHandle& handle) {
// Obtain the hardware address of the "interesting" client. We have to
// use a try...catch block here because if the client was not interesting,
// no information would be set and getArgument would thrown an exception.
string hwaddr;
- try (handle.getArgument("hwaddr", hwaddr) {
+ try {
+ handle.getContext("hwaddr", hwaddr);
- // getArgument didn't throw so the client is interesting. Get a pointer
- // to the reply. Note that the argument list for this hook also
- // contains a pointer to the query: we don't need to access that in this
- // example.
- Pkt4Ptr reply;
- handle.getArgument("reply", reply);
+ // getContext didn't throw so the client is interesting. Get a pointer
+ // to the reply.
+ Pkt4Ptr response4_ptr;
+ handle.getArgument("response4", response4_ptr);
// Get the string form of the IP address.
- string ipaddr = reply->getYiaddr().toText();
+ string ipaddr = response4_ptr->getYiaddr().toText();
// Write the information to the log file.
interesting << hwaddr << " " << ipaddr << "\n";
@@ -561,16 +566,15 @@ int v4_lease_write_post(CalloutHandle& handle) {
flush(interesting);
} catch (const NoSuchCalloutContext&) {
-
- // No such element in the per-request context with the name
- // "hwaddr". We will do nothing, so just dismiss the exception.
-
- }
+ // No such element in the per-request context with the name "hwaddr".
+ // This means that the request was not an interesting, so do nothing
+ // and dismiss the exception.
+ }
return (0);
}
-};
+}
@endcode
@subsection hooksdgBuild Building the Library
@@ -586,9 +590,9 @@ command line needed to create the library using the Gnu C++ compiler on a
Linux system is:
@code
-g++ -I /usr/include/bind10 -L /usr/lib/bind10 -fpic -shared -o example.so \
- load_unload.cc pkt_rcvd.cc v4_lease_write.cc version.cc \
- -lb10-dhcp++ -lb10-util -lb10-exceptions
+g++ -I /usr/include/bind10 -L /usr/lib/bind10/lib -fpic -shared -o example.so \
+ load_unload.cc pkt4_receive.cc pkt4_send.cc version.cc \
+ -lb10-dhcpsrv -lb10-dhcp++ -lb10-hooks -lb10-log -lb10-util -lb10-exceptions
@endcode
Notes:
@@ -621,6 +625,11 @@ module, the following bindctl commands must be executed:
The DHCPv4 server will load the library and execute the callouts each time a
request is received.
+ at note The above assumes that the hooks library will be used with a version of
+BIND 10 that is dynamically-linked. For information regarding running
+hooks libraries against a statically-linked BIND 10, see
+ at ref hooksdgStaticallyLinkedBind10.
+
@section hooksdgAdvancedTopics Advanced Topics
@subsection hooksdgContextCreateDestroy Context Creation and Destruction
@@ -633,12 +642,12 @@ to initialize per-request context. The second is called after all
server-defined hooks have been processed, and is to allow a library to
tidy up.
-As an example, the v4_lease_write example above required that the code
+As an example, the pkt4_send example above required that the code
check for an exception being thrown when accessing the "hwaddr" context
item in case it was not set. An alternative strategy would have been to
provide a callout for the "context_create" hook and set the context item
"hwaddr" to an empty string. Instead of needing to handle an exception,
-v4_lease_write would be guaranteed to get something when looking for
+pkt4_send would be guaranteed to get something when looking for
the hwaddr item and so could write or not write the output depending on
the value.
@@ -662,8 +671,8 @@ Here it is assumed that the hooks library is performing some form of
security checking on the packet and needs to maintain information in
a user-specified "SecurityInformation" object. (The details of this
fictitious object are of no concern here.) The object is created in
-the context_create callout and used in both the pkt4_rcvd and the
-v4_lease_write_post callouts.
+the context_create callout and used in both the pkt4_receive and the
+pkt4_send callouts.
@code
// Storing information in a "raw" pointer. Assume that the
@@ -682,7 +691,7 @@ int context_create(CalloutHandle& handle) {
}
// Callouts that use the context
-int pktv_rcvd(CalloutHandle& handle) {
+int pkt4_receive(CalloutHandle& handle) {
// Retrieve the pointer to the SecurityInformation object
SecurityInformation si;
handle.getContext("security_information", si);
@@ -695,7 +704,7 @@ int pktv_rcvd(CalloutHandle& handle) {
// altered, so there is no need to call setContext() again.
}
-int v4_lease_write_post(CalloutHandle& handle) {
+int pkt4_send(CalloutHandle& handle) {
// Retrieve the pointer to the SecurityInformation object
SecurityInformation si;
handle.getContext("security_information", si);
@@ -741,9 +750,9 @@ int context_create(CalloutHandle& handle) {
}
// Other than the data type, a shared pointer has similar semantics to a "raw"
-// pointer. Only the code from pkt_rcvd is shown here.
+// pointer. Only the code from pkt4_receive is shown here.
-int pktv_rcvd(CalloutHandle& handle) {
+int pkt4_receive(CalloutHandle& handle) {
// Retrieve the pointer to the SecurityInformation object
boost::shared_ptr<SecurityInformation> si;
handle.setContext("security_information", si);
@@ -773,7 +782,7 @@ As briefly mentioned in @ref hooksdgExampleCallouts, the standard is for
callouts in the user library to have the same name as the name of the
hook to which they are being attached. This convention was followed
in the tutorial, e.g. the callout that needed to be attached to the
-"pkt_rcvd" hook was named pkt_rcvd.
+"pkt4_receive" hook was named pkt4_receive.
The reason for this convention is that when the library is loaded, the
hook framework automatically searches the library for functions with
@@ -805,7 +814,7 @@ The following sections cover some of the ways in which these can be used.
The example in the tutorial used standard names for the callouts. As noted
above, it is possible to use non-standard names. Suppose, instead of the
-callout names "pkt_rcvd" and "v4_lease_write", we had named our callouts
+callout names "pkt4_receive" and "pkt4_send", we had named our callouts
"classify" and "write_data". The hooks framework would not have registered
these callouts, so we would have needed to do it ourself. The place to
do this is the "load" framework function, and its code would have had to
@@ -815,8 +824,8 @@ been modified to:
int load(LibraryHandle& libhandle) {
// Register the callouts on the hooks. We assume that a header file
// declares the "classify" and "write_data" functions.
- libhandle.registerCallout("pkt_rcvd", classify);
- libhandle.registerCallout("v4_lease_write", write_data);
+ libhandle.registerCallout("pkt4_receive", classify);
+ libhandle.registerCallout("pkt4_send", write_data);
// Open the log file
interesting.open("/data/clients/interesting.log",
@@ -839,8 +848,8 @@ To register multiple callouts on a hook, just call
LibraryHandle::registerCallout multiple times on the same hook, e.g.
@code
- libhandle.registerCallout("pkt_rcvd", classify);
- libhandle.registerCallout("pkt_rcvd", write_data);
+ libhandle.registerCallout("pkt4_receive", classify);
+ libhandle.registerCallout("pkt4_receive", write_data);
@endcode
The hooks framework will call the callouts in the order they are
@@ -859,16 +868,16 @@ is able to be registered on a hook multiple times.
Using our contrived example again, the DHCPv4 server processes one request
to completion before it starts processing the next. With this knowledge,
we could alter the logic of the code so that the callout attached to the
-"pkt_rcvd" hook registers the callout doing the logging when it detects
+"pkt4_receive" hook registers the callout doing the logging when it detects
an interesting packet, and the callout doing the logging deregisters
itself in its execution. The relevant modifications to the code in
the tutorial are shown below:
@code
-// pkt_rcvd.cc
+// pkt4_receive.cc
// :
-int pkt_rcvd(CalloutHandle& handle) {
+int pkt4_receive(CalloutHandle& handle) {
:
:
@@ -880,7 +889,7 @@ int pkt_rcvd(CalloutHandle& handle) {
handle.setContext("hwaddr", hwaddr_ptr->hwaddr_.toText());
// Register the callback to log the data.
- handle.getLibraryHandle().registerCallout("v4_lease_write", write_data);
+ handle.getLibraryHandle().registerCallout("pkt4_send", write_data);
}
return (0);
@@ -888,7 +897,7 @@ int pkt_rcvd(CalloutHandle& handle) {
@endcode
@code
-// v4_lease_write.cc
+// pkt4_send.cc
:
int write_data(CalloutHandle& handle) {
@@ -912,9 +921,9 @@ int write_data(CalloutHandle& handle) {
flush(interesting);
// We've logged the data, so deregister ourself. This callout will not
- // be called again until it is registered by pkt_rcvd.
+ // be called again until it is registered by pkt4_receive.
- handle.getLibraryHandle().deregisterCallout("v4_lease_write", write_data);
+ handle.getLibraryHandle().deregisterCallout("pkt4_send", write_data);
return (0);
}
@@ -1028,4 +1037,39 @@ appear between "check" and "validate". On the other hand, if it were
"logpkt" that registered the new callout, "double_check" would appear
after "validate".
+ at subsection hooksdgStaticallyLinkedBind10 Running Against a Statically-Linked BIND 10
+
+If BIND 10 is built with the --enable-static-link switch (set when
+running the "configure" script), no shared BIND 10 libraries are built;
+instead, archive libraries are created and BIND 10 is linked to them.
+If you create a hooks library also linked against these archive libraries,
+when the library is loaded you end up with two copies of the library code,
+one in BIND 10 and one in your library.
+
+To run successfully, your library needs to perform run-time initialization
+of the BIND 10 code in your library (something performed by BIND 10
+in the case of shared libraries). To do this, call the function
+isc::hooks::hooksStaticLinkInit() as the first statement of the load()
+function. (If your library does not include a load() function, you need
+to add one.) For example:
+
+ at code
+#include <hooks/hooks.h>
+
+extern "C" {
+
+int version() {
+ return (BIND10_HOOKS_VERSION);
+}
+
+int load() {
+ isc::hooks::hooksStaticLinkInit();
+ :
+}
+
+// Other callout functions
+ :
+
+}
+ at endcode
*/
diff --git a/src/lib/hooks/library_manager.cc b/src/lib/hooks/library_manager.cc
index 70c76ba..4b04005 100644
--- a/src/lib/hooks/library_manager.cc
+++ b/src/lib/hooks/library_manager.cc
@@ -12,6 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <exceptions/exceptions.h>
#include <hooks/hooks.h>
#include <hooks/hooks_log.h>
#include <hooks/callout_manager.h>
@@ -179,6 +180,10 @@ LibraryManager::runLoad() {
try {
manager_->setLibraryIndex(index_);
status = (*pc.loadPtr())(manager_->getLibraryHandle());
+ } catch (const isc::Exception& ex) {
+ LOG_ERROR(hooks_logger, HOOKS_LOAD_FRAMEWORK_EXCEPTION)
+ .arg(library_name_).arg(ex.what());
+ return (false);
} catch (...) {
LOG_ERROR(hooks_logger, HOOKS_LOAD_EXCEPTION).arg(library_name_);
return (false);
@@ -217,6 +222,10 @@ LibraryManager::runUnload() {
int status = -1;
try {
status = (*pc.unloadPtr())();
+ } catch (const isc::Exception& ex) {
+ LOG_ERROR(hooks_logger, HOOKS_UNLOAD_FRAMEWORK_EXCEPTION)
+ .arg(library_name_).arg(ex.what());
+ return (false);
} catch (...) {
// Exception generated. Note a warning as the unload will occur
// anyway.
diff --git a/src/lib/hooks/tests/Makefile.am b/src/lib/hooks/tests/Makefile.am
index 37fe238..36b6287 100644
--- a/src/lib/hooks/tests/Makefile.am
+++ b/src/lib/hooks/tests/Makefile.am
@@ -9,6 +9,15 @@ AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
# But older GCC compilers don't have the flag.
AM_CXXFLAGS = $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+# BIND 10 libraries against which the test user libraries are linked.
+HOOKS_LIB = $(top_builddir)/src/lib/hooks/libb10-hooks.la
+LOG_LIB = $(top_builddir)/src/lib/log/libb10-log.la
+EXCEPTIONS_LIB = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+UTIL_LIB = $(top_builddir)/src/lib/util/libb10-util.la
+THREADS_LIB = $(top_builddir)/src/lib/util/threads/libb10-threads.la
+
+ALL_LIBS = $(HOOKS_LIB) $(LOG_LIB) $(EXCEPTIONS_LIB) $(UTIL_LIB) $(THREADS_LIB)
+
if USE_CLANGPP
# see ../Makefile.am
AM_CXXFLAGS += -Wno-unused-parameter
@@ -22,7 +31,19 @@ TESTS_ENVIRONMENT = \
TESTS =
if HAVE_GTEST
-# Build shared libraries for testing.
+# Build shared libraries for testing. The libtool way to create a shared library
+# is to specify "-avoid-version -export-dynamic -module" in the library LDFLAGS
+# (see http://www.gnu.org/software/libtool/manual/html_node/Link-mode.html).
+# Use of these switches will guarantee that the .so files are created in the
+# .libs folder and they can be dlopened.
+# Note that the shared libraries with callouts should not be used together with
+# the --enable-static-link option. With this option, the bind10 libraries are
+# statically linked with the program and if the callout invokes the methods
+# which belong to these libraries, the library with the callout will get its
+# own copy of the static objects (e.g. logger, ServerHooks) and that will lead
+# to unexpected errors. For this reason, the --enable-static-link option is
+# ignored for unit tests built here.
+
lib_LTLIBRARIES = libnvl.la libivl.la libfxl.la libbcl.la liblcl.la liblecl.la \
libucl.la libfcl.la
@@ -30,43 +51,54 @@ lib_LTLIBRARIES = libnvl.la libivl.la libfxl.la libbcl.la liblcl.la liblecl.la \
libnvl_la_SOURCES = no_version_library.cc
libnvl_la_CXXFLAGS = $(AM_CXXFLAGS)
libnvl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libnvl_la_LDFLAGS = -avoid-version -export-dynamic -module
# Incorrect version function
libivl_la_SOURCES = incorrect_version_library.cc
libivl_la_CXXFLAGS = $(AM_CXXFLAGS)
libivl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libivl_la_LDFLAGS = -avoid-version -export-dynamic -module
# All framework functions throw an exception
-libfxl_la_SOURCES = framework_exception_library.cc
+libfxl_la_SOURCES = framework_exception_library.cc
libfxl_la_CXXFLAGS = $(AM_CXXFLAGS)
libfxl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libfxl_la_LDFLAGS = -avoid-version -export-dynamic -module
# The basic callout library - contains standard callouts
libbcl_la_SOURCES = basic_callout_library.cc
libbcl_la_CXXFLAGS = $(AM_CXXFLAGS)
libbcl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libbcl_la_LDFLAGS = -avoid-version -export-dynamic -module
+libbcl_la_LIBADD = $(ALL_LIBS)
# The load callout library - contains a load function
liblcl_la_SOURCES = load_callout_library.cc
liblcl_la_CXXFLAGS = $(AM_CXXFLAGS)
liblcl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+liblcl_la_LDFLAGS = -avoid-version -export-dynamic -module
+liblcl_la_LIBADD = $(ALL_LIBS)
# The load error callout library - contains a load function that returns
# an error.
liblecl_la_SOURCES = load_error_callout_library.cc
liblecl_la_CXXFLAGS = $(AM_CXXFLAGS)
liblecl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+liblecl_la_LDFLAGS = -avoid-version -export-dynamic -module
# The unload callout library - contains an unload function that
# creates a marker file.
libucl_la_SOURCES = unload_callout_library.cc
libucl_la_CXXFLAGS = $(AM_CXXFLAGS)
libucl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libucl_la_LDFLAGS = -avoid-version -export-dynamic -module
# The full callout library - contains all three framework functions.
libfcl_la_SOURCES = full_callout_library.cc
libfcl_la_CXXFLAGS = $(AM_CXXFLAGS)
libfcl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libfcl_la_LDFLAGS = -avoid-version -export-dynamic -module
+libfcl_la_LIBADD = $(ALL_LIBS)
TESTS += run_unittests
run_unittests_SOURCES = run_unittests.cc
@@ -85,18 +117,28 @@ nodist_run_unittests_SOURCES += test_libraries.h
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
if USE_STATIC_LINK
-# If specified, only link unit tests static - the test libraries must be
-# build as shared libraries.
-run_unittests_LDFLAGS += -static
+run_unittests_LDFLAGS += -static
endif
-run_unittests_LDADD = $(AM_LDADD) $(GTEST_LDADD)
+run_unittests_LDADD = $(AM_LDADD) $(GTEST_LDADD)
+run_unittests_LDADD += $(ALL_LIBS)
+run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+
+# As noted in configure.ac, libtool doesn't work perfectly with Darwin: it embeds the
+# final install path in dynamic libraries and loadable modules refer to that path even
+# if its loaded within the source tree, so preventing tests from working - but only
+# when linking statically. The solution used in other Makefiles (setting the path
+# to the dynamic libraries via an environment variable) don't seem to work. What does
+# work is to run the unit test using libtool and specifying paths via -dlopen switches.
+# So... If running in an environment where we have to set the library path AND if
+# linking statically, override the "check" target and run the unit tests ourselves.
+if USE_STATIC_LINK
+if SET_ENV_LIBRARY_PATH
+check-TESTS:
+ $(LIBTOOL) --mode=execute -dlopen $(HOOKS_LIB) -dlopen $(LOG_LIB) -dlopen $(EXCEPTIONS_LIB) -dlopen $(UTIL_LIB) -dlopen $(THREADS_LIB) ./run_unittests
+endif
+endif
-run_unittests_LDADD += $(top_builddir)/src/lib/hooks/libb10-hooks.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
endif
noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/hooks/tests/basic_callout_library.cc b/src/lib/hooks/tests/basic_callout_library.cc
index 253de80..0a81f23 100644
--- a/src/lib/hooks/tests/basic_callout_library.cc
+++ b/src/lib/hooks/tests/basic_callout_library.cc
@@ -24,16 +24,16 @@
/// - A context_create callout is supplied.
///
/// - Three "standard" callouts are supplied corresponding to the hooks
-/// "hookpt_one", "hookpt_two", "hookpt_three". All do some trivial calculations
-/// on the arguments supplied to it and the context variables, returning
-/// intermediate results through the "result" argument. The result of
-/// executing all four callouts in order is:
+/// "hookpt_one", "hookpt_two", "hookpt_three". All do some trivial
+/// calculations on the arguments supplied to it and the context variables,
+/// returning intermediate results through the "result" argument. The result
+/// of executing all four callouts in order is:
///
/// @f[ (10 + data_1) * data_2 - data_3 @f]
///
/// ...where data_1, data_2 and data_3 are the values passed in arguments of
-/// the same name to the three callouts (data_1 passed to hookpt_one, data_2 to
-/// hookpt_two etc.) and the result is returned in the argument "result".
+/// the same name to the three callouts (data_1 passed to hookpt_one, data_2
+/// to hookpt_two etc.) and the result is returned in the argument "result".
#include <hooks/hooks.h>
#include <fstream>
@@ -104,12 +104,21 @@ hookpt_three(CalloutHandle& handle) {
return (0);
}
-// Framework functions. Only version() is supplied here.
+// Framework functions.
int
version() {
return (BIND10_HOOKS_VERSION);
}
-};
+// load() initializes the user library if the main image was statically linked.
+int
+load(isc::hooks::LibraryHandle&) {
+#ifdef USE_STATIC_LINK
+ hooksStaticLinkInit();
+#endif
+ return (0);
+}
+
+}
diff --git a/src/lib/hooks/tests/full_callout_library.cc b/src/lib/hooks/tests/full_callout_library.cc
index 33d5660..3a87f54 100644
--- a/src/lib/hooks/tests/full_callout_library.cc
+++ b/src/lib/hooks/tests/full_callout_library.cc
@@ -34,8 +34,8 @@
/// @f[ ((7 * data_1) - data_2) * data_3 @f]
///
/// ...where data_1, data_2 and data_3 are the values passed in arguments of
-/// the same name to the three callouts (data_1 passed to hookpt_one, data_2 to
-/// hookpt_two etc.) and the result is returned in the argument "result".
+/// the same name to the three callouts (data_1 passed to hookpt_one, data_2
+/// to hookpt_two etc.) and the result is returned in the argument "result".
#include <hooks/hooks.h>
#include <hooks/tests/marker_file.h>
@@ -116,6 +116,10 @@ version() {
int
load(LibraryHandle& handle) {
+ // Initialize if the main image was statically linked
+#ifdef USE_STATIC_LINK
+ hooksStaticLinkInit();
+#endif
// Register the non-standard functions
handle.registerCallout("hookpt_two", hook_nonstandard_two);
handle.registerCallout("hookpt_three", hook_nonstandard_three);
diff --git a/src/lib/hooks/tests/load_callout_library.cc b/src/lib/hooks/tests/load_callout_library.cc
index ae9f470..59a58b5 100644
--- a/src/lib/hooks/tests/load_callout_library.cc
+++ b/src/lib/hooks/tests/load_callout_library.cc
@@ -30,8 +30,8 @@
/// @f[ ((5 * data_1) + data_2) * data_3 @f]
///
/// ...where data_1, data_2 and data_3 are the values passed in arguments of
-/// the same name to the three callouts (data_1 passed to hookpt_one, data_2 to
-/// hookpt_two etc.) and the result is returned in the argument "result".
+/// the same name to the three callouts (data_1 passed to hookpt_one, data_2
+/// to hookpt_two etc.) and the result is returned in the argument "result".
#include <hooks/hooks.h>
@@ -108,6 +108,10 @@ version() {
}
int load(LibraryHandle& handle) {
+ // Initialize the user library if the main image was statically linked
+#ifdef USE_STATIC_LINK
+ hooksStaticLinkInit();
+#endif
// Register the non-standard functions
handle.registerCallout("hookpt_two", hook_nonstandard_two);
handle.registerCallout("hookpt_three", hook_nonstandard_three);
diff --git a/src/lib/hooks/tests/test_libraries.h.in b/src/lib/hooks/tests/test_libraries.h.in
index bb6a24a..7b5e0e4 100644
--- a/src/lib/hooks/tests/test_libraries.h.in
+++ b/src/lib/hooks/tests/test_libraries.h.in
@@ -19,60 +19,41 @@
namespace {
-
-// Take care of differences in DLL naming between operating systems.
-
-#ifdef OS_OSX
-#define DLL_SUFFIX ".dylib"
-
-#else
-#define DLL_SUFFIX ".so"
-
-#endif
-
-
// Names of the libraries used in these tests. These libraries are built using
// libtool, so we need to look in the hidden ".libs" directory to locate the
// .so file. Note that we access the .so file - libtool creates this as a
// like to the real shared library.
// Basic library with context_create and three "standard" callouts.
-static const char* BASIC_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libbcl"
- DLL_SUFFIX;
+static const char* BASIC_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libbcl.so";
// Library with context_create and three "standard" callouts, as well as
// load() and unload() functions.
-static const char* FULL_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libfcl"
- DLL_SUFFIX;
+static const char* FULL_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libfcl.so";
// Library where the all framework functions throw an exception
-static const char* FRAMEWORK_EXCEPTION_LIBRARY = "@abs_builddir@/.libs/libfxl"
- DLL_SUFFIX;
+static const char* FRAMEWORK_EXCEPTION_LIBRARY = "@abs_builddir@/.libs/libfxl.so";
// Library where the version() function returns an incorrect result.
-static const char* INCORRECT_VERSION_LIBRARY = "@abs_builddir@/.libs/libivl"
- DLL_SUFFIX;
+static const char* INCORRECT_VERSION_LIBRARY = "@abs_builddir@/.libs/libivl.so";
// Library where some of the callout registration is done with the load()
// function.
-static const char* LOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/liblcl"
- DLL_SUFFIX;
+static const char* LOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/liblcl.so";
// Library where the load() function returns an error.
static const char* LOAD_ERROR_CALLOUT_LIBRARY =
- "@abs_builddir@/.libs/liblecl" DLL_SUFFIX;
+ "@abs_builddir@/.libs/liblecl.so";
// Name of a library which is not present.
-static const char* NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere"
- DLL_SUFFIX;
+static const char* NOT_PRESENT_LIBRARY = "@abs_builddir@/.libs/libnothere.so";
// Library that does not include a version function.
-static const char* NO_VERSION_LIBRARY = "@abs_builddir@/.libs/libnvl"
- DLL_SUFFIX;
+static const char* NO_VERSION_LIBRARY = "@abs_builddir@/.libs/libnvl.so";
// Library where there is an unload() function.
-static const char* UNLOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libucl"
- DLL_SUFFIX;
+static const char* UNLOAD_CALLOUT_LIBRARY = "@abs_builddir@/.libs/libucl.so";
+
} // anonymous namespace
diff --git a/src/lib/log/logger.cc b/src/lib/log/logger.cc
index a04267c..f7d6799 100644
--- a/src/lib/log/logger.cc
+++ b/src/lib/log/logger.cc
@@ -43,6 +43,11 @@ void Logger::initLoggerImpl() {
Logger::~Logger() {
delete loggerptr_;
+
+ // The next statement is required for the BIND 10 hooks framework, where
+ // a statically-linked BIND 10 loads and unloads multiple libraries. See
+ // the hooks documentation for more details.
+ loggerptr_ = 0;
}
// Get Name of Logger
diff --git a/src/lib/resolve/Makefile.am b/src/lib/resolve/Makefile.am
index 6c04744..eae202e 100644
--- a/src/lib/resolve/Makefile.am
+++ b/src/lib/resolve/Makefile.am
@@ -38,6 +38,7 @@ libb10_resolve_la_LIBADD = $(top_builddir)/src/lib/dns/libb10-dns++.la
libb10_resolve_la_LIBADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
libb10_resolve_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.la
libb10_resolve_la_LIBADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
+libb10_resolve_la_LIBADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
# The message file should be in the distribution.
EXTRA_DIST = resolve_messages.mes
diff --git a/src/lib/testutils/Makefile.am b/src/lib/testutils/Makefile.am
index 2281b6d..574cc78 100644
--- a/src/lib/testutils/Makefile.am
+++ b/src/lib/testutils/Makefile.am
@@ -11,7 +11,8 @@ libb10_testutils_la_SOURCES = srv_test.h srv_test.cc
libb10_testutils_la_SOURCES += dnsmessage_test.h dnsmessage_test.cc
libb10_testutils_la_SOURCES += mockups.h
libb10_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
-libb10_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+libb10_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+libb10_testutils_la_LIBADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
endif
EXTRA_DIST = portconfig.h socket_request.h
More information about the bind10-changes
mailing list