Parcourir la source

[master] Merge branch 'trac3113'

Stephen Morris il y a 11 ans
Parent
commit
3d19eee4db

+ 1 - 0
configure.ac

@@ -181,6 +181,7 @@ AC_HELP_STRING([--enable-static-link],
   [build programs with static link [[default=no]]]),
   [build programs with static link [[default=no]]]),
   [enable_static_link=yes], [enable_static_link=no])
   [enable_static_link=yes], [enable_static_link=no])
 AM_CONDITIONAL(USE_STATIC_LINK, test $enable_static_link = yes)
 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
 # Check validity about some libtool options
 if test $enable_static_link = yes -a $enable_static = no; then
 if test $enable_static_link = yes -a $enable_static = no; then

+ 15 - 5
src/bin/dhcp4/tests/Makefile.am

@@ -40,25 +40,35 @@ if USE_CLANGPP
 AM_CXXFLAGS += -Wno-unused-parameter
 AM_CXXFLAGS += -Wno-unused-parameter
 endif
 endif
 
 
-if USE_STATIC_LINK
-AM_LDFLAGS = -static
-endif
-
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
         $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
         $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 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
 lib_LTLIBRARIES = libco1.la libco2.la
 
 
 libco1_la_SOURCES  = callout_library_1.cc callout_library_common.h
 libco1_la_SOURCES  = callout_library_1.cc callout_library_common.h
 libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco1_la_CPPFLAGS = $(AM_CPPFLAGS)
 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_SOURCES  = callout_library_2.cc callout_library_common.h
 libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco2_la_CPPFLAGS = $(AM_CPPFLAGS)
 libco2_la_CPPFLAGS = $(AM_CPPFLAGS)
+libco2_la_LDFLAGS = -avoid-version -export-dynamic -module
 
 
 TESTS += dhcp4_unittests
 TESTS += dhcp4_unittests
 
 

+ 4 - 16
src/bin/dhcp4/tests/test_libraries.h.in

@@ -19,32 +19,20 @@
 
 
 namespace {
 namespace {
 
 
-
-// Take care of differences in DLL naming between operating systems.
-
-#ifdef OS_OSX
-#define DLL_SUFFIX ".dylib"
-
-#else
 #define DLL_SUFFIX ".so"
 #define DLL_SUFFIX ".so"
 
 
-#endif
-
-
 // Names of the libraries used in these tests.  These libraries are built using
 // 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
 // libtool, so we need to look in the hidden ".libs" directory to locate the
 // shared library.
 // shared library.
 
 
 // Library with load/unload functions creating marker files to check their
 // Library with load/unload functions creating marker files to check their
 // operation.
 // 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.
 // 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
 } // anonymous namespace
 
 
 
 

+ 15 - 5
src/bin/dhcp6/tests/Makefile.am

@@ -36,25 +36,35 @@ if USE_CLANGPP
 AM_CXXFLAGS += -Wno-unused-parameter
 AM_CXXFLAGS += -Wno-unused-parameter
 endif
 endif
 
 
-if USE_STATIC_LINK
-AM_LDFLAGS = -static
-endif
-
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
         $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
         $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 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
 lib_LTLIBRARIES = libco1.la libco2.la
 
 
 libco1_la_SOURCES  = callout_library_1.cc callout_library_common.h
 libco1_la_SOURCES  = callout_library_1.cc callout_library_common.h
 libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco1_la_CPPFLAGS = $(AM_CPPFLAGS)
 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_SOURCES  = callout_library_2.cc callout_library_common.h
 libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco2_la_CPPFLAGS = $(AM_CPPFLAGS)
 libco2_la_CPPFLAGS = $(AM_CPPFLAGS)
+libco2_la_LDFLAGS = -avoid-version -export-dynamic -module
 
 
 TESTS += dhcp6_unittests
 TESTS += dhcp6_unittests
 dhcp6_unittests_SOURCES  = dhcp6_unittests.cc
 dhcp6_unittests_SOURCES  = dhcp6_unittests.cc

+ 4 - 18
src/bin/dhcp6/tests/test_libraries.h.in

@@ -19,32 +19,18 @@
 
 
 namespace {
 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
 // 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
 // libtool, so we need to look in the hidden ".libs" directory to locate the
 // shared library.
 // shared library.
 
 
 // Library with load/unload functions creating marker files to check their
 // Library with load/unload functions creating marker files to check their
 // operation.
 // 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.
 // 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
 } // anonymous namespace
 
 
 
 

+ 2 - 1
src/lib/asiodns/Makefile.am

@@ -43,4 +43,5 @@ if USE_CLANGPP
 libb10_asiodns_la_CXXFLAGS += -Wno-error
 libb10_asiodns_la_CXXFLAGS += -Wno-error
 endif
 endif
 libb10_asiodns_la_CPPFLAGS = $(AM_CPPFLAGS)
 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

+ 15 - 9
src/lib/dhcpsrv/tests/Makefile.am

@@ -13,11 +13,6 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 # But older GCC compilers don't have the flag.
 # But older GCC compilers don't have the flag.
 AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
 AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
 
 
-if USE_STATIC_LINK
-AM_LDFLAGS = -static
-TEST_LIBS_LDFLAGS = -Bshareable
-endif
-
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
@@ -25,19 +20,30 @@ TESTS_ENVIRONMENT = \
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 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
 lib_LTLIBRARIES = libco1.la libco2.la
 
 
 libco1_la_SOURCES  = callout_library.cc
 libco1_la_SOURCES  = callout_library.cc
 libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco1_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco1_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 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_SOURCES  = callout_library.cc
 libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco2_la_CXXFLAGS = $(AM_CXXFLAGS)
 libco2_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 libco2_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
-libco2_la_LDFLAGS = $(TEST_LIBS_LDFLAGS)
-
+libco2_la_LDFLAGS = -avoid-version -export-dynamic -module
 
 
 TESTS += libdhcpsrv_unittests
 TESTS += libdhcpsrv_unittests
 
 

+ 4 - 18
src/lib/dhcpsrv/tests/test_libraries.h.in

@@ -19,32 +19,18 @@
 
 
 namespace {
 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
 // 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
 // libtool, so we need to look in the hidden ".libs" directory to locate the
 // shared library.
 // shared library.
 
 
 // Library with load/unload functions creating marker files to check their
 // Library with load/unload functions creating marker files to check their
 // operation.
 // 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.
 // 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
 } // anonymous namespace
 
 
 
 

+ 1 - 1
src/lib/hooks/Makefile.am

@@ -32,7 +32,7 @@ lib_LTLIBRARIES = libb10-hooks.la
 libb10_hooks_la_SOURCES  =
 libb10_hooks_la_SOURCES  =
 libb10_hooks_la_SOURCES += callout_handle.cc callout_handle.h
 libb10_hooks_la_SOURCES += callout_handle.cc callout_handle.h
 libb10_hooks_la_SOURCES += callout_manager.cc callout_manager.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_log.cc hooks_log.h
 libb10_hooks_la_SOURCES += hooks_manager.cc hooks_manager.h
 libb10_hooks_la_SOURCES += hooks_manager.cc hooks_manager.h
 libb10_hooks_la_SOURCES += library_handle.cc library_handle.h
 libb10_hooks_la_SOURCES += library_handle.cc library_handle.h

+ 3 - 2
src/lib/hooks/callout_handle.cc

@@ -30,7 +30,8 @@ namespace hooks {
 CalloutHandle::CalloutHandle(const boost::shared_ptr<CalloutManager>& manager,
 CalloutHandle::CalloutHandle(const boost::shared_ptr<CalloutManager>& manager,
                     const boost::shared_ptr<LibraryManagerCollection>& lmcoll)
                     const boost::shared_ptr<LibraryManagerCollection>& lmcoll)
     : lm_collection_(lmcoll), arguments_(), context_collection_(),
     : 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
     // Call the "context_create" hook.  We should be OK doing this - although
     // the constructor has not finished running, all the member variables
     // the constructor has not finished running, all the member variables
@@ -148,7 +149,7 @@ CalloutHandle::getHookName() const {
     // ... and look up the hook.
     // ... and look up the hook.
     string hook = "";
     string hook = "";
     try {
     try {
-        hook = ServerHooks::getServerHooks().getName(index);
+        hook = server_hooks_.getName(index);
     } catch (const NoSuchHook&) {
     } catch (const NoSuchHook&) {
         // Hook index is invalid, so this methods probably called from outside
         // Hook index is invalid, so this methods probably called from outside
         // a callout being executed via a call to CalloutManager::callCallouts.
         // a callout being executed via a call to CalloutManager::callCallouts.

+ 7 - 0
src/lib/hooks/callout_handle.h

@@ -28,6 +28,8 @@
 namespace isc {
 namespace isc {
 namespace hooks {
 namespace hooks {
 
 
+class ServerHooks;
+
 /// @brief No such argument
 /// @brief No such argument
 ///
 ///
 /// Thrown if an attempt is made access an argument that does not exist.
 /// Thrown if an attempt is made access an argument that does not exist.
@@ -369,6 +371,11 @@ private:
     /// Callout manager.
     /// Callout manager.
     boost::shared_ptr<CalloutManager> 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.
     /// "Skip" flag, indicating if the caller should bypass remaining callouts.
     bool skip_;
     bool skip_;
 };
 };

+ 8 - 9
src/lib/hooks/callout_manager.cc

@@ -31,7 +31,8 @@ namespace hooks {
 
 
 // Constructor
 // Constructor
 CalloutManager::CalloutManager(int num_libraries)
 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()),
       hook_vector_(ServerHooks::getServerHooks().getCount()),
       library_handle_(this), pre_library_handle_(this, 0),
       library_handle_(this), pre_library_handle_(this, 0),
       post_library_handle_(this, INT_MAX), num_libraries_(num_libraries)
       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
     // Get the index associated with this hook (validating the name in the
     // process).
     // 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,
     // Iterate through the callout vector for the hook from start to end,
     // looking for the first entry where the library index is greater than
     // 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) {
                 if (status == 0) {
                     LOG_DEBUG(hooks_logger, HOOKS_DBG_EXTENDED_CALLS,
                     LOG_DEBUG(hooks_logger, HOOKS_DBG_EXTENDED_CALLS,
                               HOOKS_CALLOUT_CALLED).arg(current_library_)
                               HOOKS_CALLOUT_CALLED).arg(current_library_)
-                        .arg(ServerHooks::getServerHooks()
-                            .getName(current_hook_))
+                        .arg(server_hooks_.getName(current_hook_))
                         .arg(PointerConverter(i->second).dlsymPtr());
                         .arg(PointerConverter(i->second).dlsymPtr());
                 } else {
                 } else {
                     LOG_ERROR(hooks_logger, HOOKS_CALLOUT_ERROR)
                     LOG_ERROR(hooks_logger, HOOKS_CALLOUT_ERROR)
                         .arg(current_library_)
                         .arg(current_library_)
-                        .arg(ServerHooks::getServerHooks()
-                            .getName(current_hook_))
+                        .arg(server_hooks_.getName(current_hook_))
                         .arg(PointerConverter(i->second).dlsymPtr());
                         .arg(PointerConverter(i->second).dlsymPtr());
                 }
                 }
             } catch (const std::exception& e) {
             } catch (const std::exception& e) {
                 // Any exception, not just ones based on isc::Exception
                 // Any exception, not just ones based on isc::Exception
                 LOG_ERROR(hooks_logger, HOOKS_CALLOUT_EXCEPTION)
                 LOG_ERROR(hooks_logger, HOOKS_CALLOUT_EXCEPTION)
                     .arg(current_library_)
                     .arg(current_library_)
-                    .arg(ServerHooks::getServerHooks().getName(current_hook_))
+                    .arg(server_hooks_.getName(current_hook_))
                     .arg(PointerConverter(i->second).dlsymPtr())
                     .arg(PointerConverter(i->second).dlsymPtr())
                     .arg(e.what());
                     .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
     // Get the index associated with this hook (validating the name in the
     // process).
     // 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
     /// Construct a CalloutEntry matching the current library and the callout
     /// we want to remove.
     /// 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
     // Get the index associated with this hook (validating the name in the
     // process).
     // process).
-    int hook_index = ServerHooks::getServerHooks().getIndex(name);
+    int hook_index = server_hooks_.getIndex(name);
 
 
     /// Construct a CalloutEntry matching the current library (the callout
     /// Construct a CalloutEntry matching the current library (the callout
     /// pointer is NULL as we are not checking that).
     /// pointer is NULL as we are not checking that).

+ 7 - 0
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
     /// 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)
     /// index of the current hook.  It is set to an invalid value (-1)
     /// otherwise.
     /// otherwise.

+ 34 - 0
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

+ 39 - 0
src/lib/hooks/hooks.h

@@ -15,6 +15,7 @@
 #ifndef HOOKS_H
 #ifndef HOOKS_H
 #define HOOKS_H
 #define HOOKS_H
 
 
+#include <config.h>
 #include <hooks/callout_handle.h>
 #include <hooks/callout_handle.h>
 #include <hooks/library_handle.h>
 #include <hooks/library_handle.h>
 
 
@@ -35,4 +36,42 @@ typedef int (*unload_function_ptr)();
 
 
 } // Anonymous namespace
 } // 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
 #endif  // HOOKS_H

+ 108 - 0
src/lib/hooks/hooks_maintenance.dox

@@ -271,4 +271,112 @@
  this may mean the server suspending all processing of incoming requests
  this may mean the server suspending all processing of incoming requests
  until all currently executing requests have completed and data object
  until all currently executing requests have completed and data object
  destroyed, reloading the libraries, then resuming processing.
  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.
 */
 */

+ 15 - 0
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
 during execution, which is an error condition.  The library has been
 unloaded and no callouts from it will be installed.
 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
 % HOOKS_LOAD_SUCCESS 'load' function in hook library %1 returned success
 This is a debug message issued when the "load" function has been found
 This is a debug message issued when the "load" function has been found
 in a hook library and has been successfully called.
 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
 The unload process continued after this message and the library has
 been unloaded.
 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
 % HOOKS_UNLOAD_SUCCESS 'unload' function in hook library %1 returned success
 This is a debug message issued when an "unload" function has been found
 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.
 in a hook library during the unload process, called, and returned success.

+ 104 - 60
src/lib/hooks/hooks_user.dox

@@ -156,7 +156,7 @@ int version() {
     return (BIND10_HOOKS_VERSION);
     return (BIND10_HOOKS_VERSION);
 }
 }
 
 
-};
+}
 @endcode
 @endcode
 
 
 The file "hooks/hooks.h" is specified relative to the BIND 10 libraries
 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 <hooks/hooks.h>
 #include "library_common.h"
 #include "library_common.h"
 
 
+using namespace isc::hooks;
+
 // "Interesting clients" log file handle definition.
 // "Interesting clients" log file handle definition.
 std::fstream interesting;
 std::fstream interesting;
 
 
@@ -229,7 +231,7 @@ int unload() {
     return (0);
     return (0);
 }
 }
 
 
-};
+}
 @endcode
 @endcode
 
 
 Notes:
 Notes:
@@ -276,7 +278,7 @@ All callouts are declared with the signature:
 @code
 @code
 extern "C" {
 extern "C" {
 int callout(CalloutHandle& handle);
 int callout(CalloutHandle& handle);
-};
+}
 @endcode
 @endcode
 
 
 (As before, the callout is declared with "C" linkage.)  Information is passed
 (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
 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:
 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).
 which is an isc::dhcp::Pkt4 object (representing a DHCP v4 packet).
 We will do the classification here.
 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 standard for naming callouts is to give them the same name as
 the hook.  If this is done, the callouts will be automatically found
 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:
 hardware address) is:
 
 
 @code
 @code
-// pkt_rcvd.cc
+// pkt_receive4.cc
 
 
 #include <hooks/hooks.h>
 #include <hooks/hooks.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt4.h>
@@ -482,47 +483,51 @@ hardware address) is:
 #include <string>
 #include <string>
 
 
 using namespace isc::dhcp;
 using namespace isc::dhcp;
+using namespace isc::hooks;
 using namespace std;
 using namespace std;
 
 
 extern "C" {
 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
     // 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
     // pointer. The include file "pkt4.h" typedefs a pointer to the Pkt4
     // object as Pkt4Ptr.  Retrieve a pointer to the object.
     // 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.
     // 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
     // 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.
     // it as interesting if the sum of all the bytes in it is divisible by 4.
     //  (This is a contrived example after all!)
     //  (This is a contrived example after all!)
     long sum = 0;
     long sum = 0;
     for (int i = 0; i < hwaddr_ptr->hwaddr_.size(); ++i) {
     for (int i = 0; i < hwaddr_ptr->hwaddr_.size(); ++i) {
-        sum += hwaddr_ptr->hwadr_[i];
+        sum += hwaddr_ptr->hwaddr_[i];
     }
     }
 
 
     // Classify it.
     // Classify it.
     if (sum % 4 == 0) {
     if (sum % 4 == 0) {
         // Store the text form of the hardware address in the context to pass
         // Store the text form of the hardware address in the context to pass
         // to the next callout.
         // to the next callout.
-        handle.setContext("hwaddr", hwaddr_ptr->hwaddr_.toText());
+        string hwaddr = hwaddr_ptr->toText();
+        handle.setContext("hwaddr", hwaddr);
     }
     }
 
 
     return (0);
     return (0);
 };
 };
+
+}
 @endcode
 @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
 the "hwaddr" context for the packet.  Turning now to the callout that will
 write this information to the log file:
 write this information to the log file:
 
 
 @code
 @code
-// v4_lease_write.cc
+// pkt4_send.cc
 
 
 #include <hooks/hooks.h>
 #include <hooks/hooks.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt4.h>
@@ -531,28 +536,28 @@ write this information to the log file:
 #include <string>
 #include <string>
 
 
 using namespace isc::dhcp;
 using namespace isc::dhcp;
+using namespace isc::hooks;
 using namespace std;
 using namespace std;
 
 
 extern "C" {
 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
     // Obtain the hardware address of the "interesting" client.  We have to
     // use a try...catch block here because if the client was not interesting,
     // use a try...catch block here because if the client was not interesting,
     // no information would be set and getArgument would thrown an exception.
     // no information would be set and getArgument would thrown an exception.
     string hwaddr;
     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.
         // 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.
         // Write the information to the log file.
         interesting << hwaddr << " " << ipaddr << "\n";
         interesting << hwaddr << " " << ipaddr << "\n";
@@ -561,16 +566,15 @@ int v4_lease_write_post(CalloutHandle& handle) {
         flush(interesting);
         flush(interesting);
 
 
     } catch (const NoSuchCalloutContext&) {
     } 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);
     return (0);
 }
 }
 
 
-};
+}
 @endcode
 @endcode
 
 
 @subsection hooksdgBuild Building the Library
 @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:
 Linux system is:
 
 
 @code
 @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
 @endcode
 
 
 Notes:
 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
 The DHCPv4 server will load the library and execute the callouts each time a
 request is received.
 request is received.
 
 
+@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
+@ref hooksdgStaticallyLinkedBind10.
+
 @section hooksdgAdvancedTopics Advanced Topics
 @section hooksdgAdvancedTopics Advanced Topics
 
 
 @subsection hooksdgContextCreateDestroy Context Creation and Destruction
 @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
 server-defined hooks have been processed, and is to allow a library to
 tidy up.
 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
 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
 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
 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,
 "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 hwaddr item and so could write or not write the output depending on
 the value.
 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
 security checking on the packet and needs to maintain information in
 a user-specified "SecurityInformation" object. (The details of this
 a user-specified "SecurityInformation" object. (The details of this
 fictitious object are of no concern here.) The object is created in
 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
 @code
 // Storing information in a "raw" pointer.  Assume that the
 // Storing information in a "raw" pointer.  Assume that the
@@ -682,7 +691,7 @@ int context_create(CalloutHandle& handle) {
 }
 }
 
 
 // Callouts that use the context
 // Callouts that use the context
-int pktv_rcvd(CalloutHandle& handle) {
+int pkt4_receive(CalloutHandle& handle) {
     // Retrieve the pointer to the SecurityInformation object
     // Retrieve the pointer to the SecurityInformation object
     SecurityInformation si;
     SecurityInformation si;
     handle.getContext("security_information", 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.
     // 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
     // Retrieve the pointer to the SecurityInformation object
     SecurityInformation si;
     SecurityInformation si;
     handle.getContext("security_information", 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"
 // 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
     // Retrieve the pointer to the SecurityInformation object
     boost::shared_ptr<SecurityInformation> si;
     boost::shared_ptr<SecurityInformation> si;
     handle.setContext("security_information", 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
 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
 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
 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
 The reason for this convention is that when the library is loaded, the
 hook framework automatically searches the library for functions with
 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
 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
 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
 "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
 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
 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) {
 int load(LibraryHandle& libhandle) {
     // Register the callouts on the hooks. We assume that a header file
     // Register the callouts on the hooks. We assume that a header file
     // declares the "classify" and "write_data" functions.
     // 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
     // Open the log file
     interesting.open("/data/clients/interesting.log",
     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.
 LibraryHandle::registerCallout multiple times on the same hook, e.g.
 
 
 @code
 @code
-    libhandle.registerCallout("pkt_rcvd", classify);
-    libhandle.registerCallout("pkt_rcvd", write_data);
+    libhandle.registerCallout("pkt4_receive", classify);
+    libhandle.registerCallout("pkt4_receive", write_data);
 @endcode
 @endcode
 
 
 The hooks framework will call the callouts in the order they are
 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
 Using our contrived example again, the DHCPv4 server processes one request
 to completion before it starts processing the next.  With this knowledge,
 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
 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
 an interesting packet, and the callout doing the logging deregisters
 itself in its execution.  The relevant modifications to the code in
 itself in its execution.  The relevant modifications to the code in
 the tutorial are shown below:
 the tutorial are shown below:
 
 
 @code
 @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());
         handle.setContext("hwaddr", hwaddr_ptr->hwaddr_.toText());
 
 
         // Register the callback to log the data.
         // Register the callback to log the data.
-        handle.getLibraryHandle().registerCallout("v4_lease_write", write_data);
+        handle.getLibraryHandle().registerCallout("pkt4_send", write_data);
     }
     }
 
 
     return (0);
     return (0);
@@ -888,7 +897,7 @@ int pkt_rcvd(CalloutHandle& handle) {
 @endcode
 @endcode
 
 
 @code
 @code
-// v4_lease_write.cc
+// pkt4_send.cc
         :
         :
 
 
 int write_data(CalloutHandle& handle) {
 int write_data(CalloutHandle& handle) {
@@ -912,9 +921,9 @@ int write_data(CalloutHandle& handle) {
     flush(interesting);
     flush(interesting);
 
 
     // We've logged the data, so deregister ourself.  This callout will not
     // 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);
     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
 "logpkt" that registered the new callout, "double_check" would appear
 after "validate".
 after "validate".
 
 
+@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:
+
+@code
+#include <hooks/hooks.h>
+
+extern "C" {
+
+int version() {
+    return (BIND10_HOOKS_VERSION);
+}
+
+int load() {
+    isc::hooks::hooksStaticLinkInit();
+        :
+}
+
+// Other callout functions
+        :
+
+}
+@endcode
 */
 */

+ 9 - 0
src/lib/hooks/library_manager.cc

@@ -12,6 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#include <exceptions/exceptions.h>
 #include <hooks/hooks.h>
 #include <hooks/hooks.h>
 #include <hooks/hooks_log.h>
 #include <hooks/hooks_log.h>
 #include <hooks/callout_manager.h>
 #include <hooks/callout_manager.h>
@@ -179,6 +180,10 @@ LibraryManager::runLoad() {
         try {
         try {
             manager_->setLibraryIndex(index_);
             manager_->setLibraryIndex(index_);
             status = (*pc.loadPtr())(manager_->getLibraryHandle());
             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 (...) {
         } catch (...) {
             LOG_ERROR(hooks_logger, HOOKS_LOAD_EXCEPTION).arg(library_name_);
             LOG_ERROR(hooks_logger, HOOKS_LOAD_EXCEPTION).arg(library_name_);
             return (false);
             return (false);
@@ -217,6 +222,10 @@ LibraryManager::runUnload() {
         int status = -1;
         int status = -1;
         try {
         try {
             status = (*pc.unloadPtr())();
             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 (...) {
         } catch (...) {
             // Exception generated.  Note a warning as the unload will occur
             // Exception generated.  Note a warning as the unload will occur
             // anyway.
             // anyway.

+ 53 - 11
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.     
 # But older GCC compilers don't have the flag.     
 AM_CXXFLAGS  = $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
 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
 if USE_CLANGPP
 # see ../Makefile.am
 # see ../Makefile.am
 AM_CXXFLAGS += -Wno-unused-parameter
 AM_CXXFLAGS += -Wno-unused-parameter
@@ -22,7 +31,19 @@ TESTS_ENVIRONMENT = \
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 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 \
 lib_LTLIBRARIES = libnvl.la libivl.la libfxl.la libbcl.la liblcl.la liblecl.la \
                   libucl.la libfcl.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_SOURCES  = no_version_library.cc
 libnvl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libnvl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libnvl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 libnvl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libnvl_la_LDFLAGS  = -avoid-version -export-dynamic -module
 
 
 # Incorrect version function
 # Incorrect version function
 libivl_la_SOURCES  = incorrect_version_library.cc
 libivl_la_SOURCES  = incorrect_version_library.cc
 libivl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libivl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libivl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 libivl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libivl_la_LDFLAGS  = -avoid-version -export-dynamic -module
 
 
 # All framework functions throw an exception
 # 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_CXXFLAGS = $(AM_CXXFLAGS)
 libfxl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 libfxl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libfxl_la_LDFLAGS  = -avoid-version -export-dynamic -module
 
 
 # The basic callout library - contains standard callouts
 # The basic callout library - contains standard callouts
 libbcl_la_SOURCES  = basic_callout_library.cc
 libbcl_la_SOURCES  = basic_callout_library.cc
 libbcl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libbcl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libbcl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 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
 # The load callout library - contains a load function
 liblcl_la_SOURCES  = load_callout_library.cc
 liblcl_la_SOURCES  = load_callout_library.cc
 liblcl_la_CXXFLAGS = $(AM_CXXFLAGS)
 liblcl_la_CXXFLAGS = $(AM_CXXFLAGS)
 liblcl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 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
 # The load error callout library - contains a load function that returns
 # an error.
 # an error.
 liblecl_la_SOURCES  = load_error_callout_library.cc
 liblecl_la_SOURCES  = load_error_callout_library.cc
 liblecl_la_CXXFLAGS = $(AM_CXXFLAGS)
 liblecl_la_CXXFLAGS = $(AM_CXXFLAGS)
 liblecl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 liblecl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+liblecl_la_LDFLAGS  = -avoid-version -export-dynamic -module
 
 
 # The unload callout library - contains an unload function that
 # The unload callout library - contains an unload function that
 # creates a marker file.
 # creates a marker file.
 libucl_la_SOURCES  = unload_callout_library.cc
 libucl_la_SOURCES  = unload_callout_library.cc
 libucl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libucl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libucl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 libucl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libucl_la_LDFLAGS  = -avoid-version -export-dynamic -module
 
 
 # The full callout library - contains all three framework functions.
 # The full callout library - contains all three framework functions.
 libfcl_la_SOURCES  = full_callout_library.cc
 libfcl_la_SOURCES  = full_callout_library.cc
 libfcl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libfcl_la_CXXFLAGS = $(AM_CXXFLAGS)
 libfcl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
 libfcl_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libfcl_la_LDFLAGS  = -avoid-version -export-dynamic -module
+libfcl_la_LIBADD   = $(ALL_LIBS)
 
 
 TESTS += run_unittests
 TESTS += run_unittests
 run_unittests_SOURCES  = run_unittests.cc
 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_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
 if USE_STATIC_LINK
 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
 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
 endif
 
 
 noinst_PROGRAMS = $(TESTS)
 noinst_PROGRAMS = $(TESTS)

+ 17 - 8
src/lib/hooks/tests/basic_callout_library.cc

@@ -24,16 +24,16 @@
 /// - A context_create callout is supplied.
 /// - A context_create callout is supplied.
 ///
 ///
 /// - Three "standard" callouts are supplied corresponding to the hooks
 /// - 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]
 ///   @f[ (10 + data_1) * data_2 - data_3 @f]
 ///
 ///
 ///   ...where data_1, data_2 and data_3 are the values passed in arguments of
 ///   ...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/hooks.h>
 #include <fstream>
 #include <fstream>
@@ -104,12 +104,21 @@ hookpt_three(CalloutHandle& handle) {
     return (0);
     return (0);
 }
 }
 
 
-// Framework functions.  Only version() is supplied here.
+// Framework functions.
 
 
 int
 int
 version() {
 version() {
     return (BIND10_HOOKS_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);
+}
+
+}
 
 

+ 6 - 2
src/lib/hooks/tests/full_callout_library.cc

@@ -34,8 +34,8 @@
 ///   @f[ ((7 * data_1) - data_2) * data_3 @f]
 ///   @f[ ((7 * data_1) - data_2) * data_3 @f]
 ///
 ///
 ///   ...where data_1, data_2 and data_3 are the values passed in arguments of
 ///   ...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/hooks.h>
 #include <hooks/tests/marker_file.h>
 #include <hooks/tests/marker_file.h>
@@ -116,6 +116,10 @@ version() {
 
 
 int
 int
 load(LibraryHandle& handle) {
 load(LibraryHandle& handle) {
+    // Initialize if the main image was statically linked
+#ifdef USE_STATIC_LINK
+    hooksStaticLinkInit();
+#endif
     // Register the non-standard functions
     // Register the non-standard functions
     handle.registerCallout("hookpt_two", hook_nonstandard_two);
     handle.registerCallout("hookpt_two", hook_nonstandard_two);
     handle.registerCallout("hookpt_three", hook_nonstandard_three);
     handle.registerCallout("hookpt_three", hook_nonstandard_three);

+ 6 - 2
src/lib/hooks/tests/load_callout_library.cc

@@ -30,8 +30,8 @@
 ///   @f[ ((5 * data_1) + data_2) * data_3 @f]
 ///   @f[ ((5 * data_1) + data_2) * data_3 @f]
 ///
 ///
 ///   ...where data_1, data_2 and data_3 are the values passed in arguments of
 ///   ...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/hooks.h>
 
 
@@ -108,6 +108,10 @@ version() {
 }
 }
 
 
 int load(LibraryHandle& handle) {
 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
     // Register the non-standard functions
     handle.registerCallout("hookpt_two", hook_nonstandard_two);
     handle.registerCallout("hookpt_two", hook_nonstandard_two);
     handle.registerCallout("hookpt_three", hook_nonstandard_three);
     handle.registerCallout("hookpt_three", hook_nonstandard_three);

+ 10 - 29
src/lib/hooks/tests/test_libraries.h.in

@@ -19,60 +19,41 @@
 
 
 namespace {
 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
 // 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
 // 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
 // .so file.  Note that we access the .so file - libtool creates this as a
 // like to the real shared library.
 // like to the real shared library.
 
 
 // Basic library with context_create and three "standard" callouts.
 // 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
 // Library with context_create and three "standard" callouts, as well as
 // load() and unload() functions.
 // 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
 // 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.
 // 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()
 // Library where some of the callout registration is done with the load()
 // function.
 // 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.
 // Library where the load() function returns an error.
 static const char* LOAD_ERROR_CALLOUT_LIBRARY =
 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.
 // 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.
 // 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.
 // 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
 } // anonymous namespace
 
 
 
 

+ 5 - 0
src/lib/log/logger.cc

@@ -43,6 +43,11 @@ void Logger::initLoggerImpl() {
 
 
 Logger::~Logger() {
 Logger::~Logger() {
     delete loggerptr_;
     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
 // Get Name of Logger

+ 1 - 0
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/exceptions/libb10-exceptions.la
 libb10_resolve_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.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/asiodns/libb10-asiodns.la
+libb10_resolve_la_LIBADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
 
 
 # The message file should be in the distribution.
 # The message file should be in the distribution.
 EXTRA_DIST = resolve_messages.mes
 EXTRA_DIST = resolve_messages.mes

+ 2 - 1
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 += dnsmessage_test.h dnsmessage_test.cc
 libb10_testutils_la_SOURCES += mockups.h
 libb10_testutils_la_SOURCES += mockups.h
 libb10_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 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
 endif
 
 
 EXTRA_DIST = portconfig.h socket_request.h
 EXTRA_DIST = portconfig.h socket_request.h