Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
19c93b08
Commit
19c93b08
authored
Jul 05, 2013
by
Tomek Mrugalski
🛰
Browse files
[2995] Merge branch 'trac2980' into trac2995
- Also code updated to match changes from 2980 Conflicts: src/lib/hooks/callout_handle.h
parents
bdeeb21d
43ea555f
Changes
38
Expand all
Hide whitespace changes
Inline
Side-by-side
configure.ac
View file @
19c93b08
...
...
@@ -1402,8 +1402,8 @@ AC_OUTPUT([doc/version.ent
src/lib/cc/session_config.h.pre
src/lib/cc/tests/session_unittests_config.h
src/lib/datasrc/datasrc_config.h.pre
src/lib/hooks/tests/library_manager_unittest.cc
src/lib/hooks/tests/marker_file.h
src/lib/hooks/tests/test_libraries.h
src/lib/log/tests/console_test.sh
src/lib/log/tests/destination_test.sh
src/lib/log/tests/init_logger_test.sh
...
...
doc/Doxyfile
View file @
19c93b08
...
...
@@ -679,6 +679,7 @@ INPUT = ../src/lib/exceptions \
../src/lib/cache \
../src/lib/server_common/ \
../src/bin/sockcreator/ \
../src/lib/hooks/ \
../src/lib/util/ \
../src/lib/util/io/ \
../src/lib/util/threads/ \
...
...
doc/devel/mainpage.dox
View file @
19c93b08
// Copyright (C) 2012-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.
/**
*
* @mainpage BIND10 Developer's Guide
*
* Welcome to BIND10 Developer's Guide. This documentation is addressed
* at existing and prospecting developers and programmers, who would like
* to gain insight into internal workings of BIND 10. It could also be useful
* for existing and prospective contributors.
* at existing and prospecting developers and programmers and provides
* information needed to both extend and maintain BIND 10.
*
* If you wish to write "hook" code - code that is loaded by BIND 10 at
* run-time and modifies its behavior you should read the section
* @ref hookDevelopersGuide.
*
* BIND 10 maintanenace information is divided into a number of sections
* depending on focus. DNS-specific issues are covered in the
* @ref dnsMaintenanceGuide while information on DHCP-specific topics can
* be found in the @ref dhcpMaintenanceGuide. General BIND 10 topics, not
* specific to any protocol, are discussed in @ref miscellaneousTopics.
*
* If you are a user or system administrator, rather than software engineer,
* you should read <a href="http://bind10.isc.org/docs/bind10-guide.html">BIND10
...
...
@@ -13,13 +35,15 @@
*
* Regardless of your field of expertise, you are encouraged to visit
* <a href="http://bind10.isc.org/">BIND10 webpage (http://bind10.isc.org)</a>
* @section hooksFramework Hooks Framework
* - @subpage hooksComponentDeveloperGuide
*
* @section
DNS
* @section
dnsMaintenanceGuide DNS Maintenance Guide
* - Authoritative DNS (todo)
* - Recursive resolver (todo)
* - @subpage DataScrubbing
*
* @section
DHCP
* @section
dhcpMaintenanceGuide DHCP Maintenance Guide
* - @subpage dhcp4
* - @subpage dhcpv4Session
* - @subpage dhcpv4ConfigParser
...
...
@@ -40,7 +64,7 @@
* - @subpage dhcpDatabaseBackends
* - @subpage perfdhcpInternals
*
* @section misc Miscellaneous topics
* @section misc
ellaneousTopics
Miscellaneous topics
* - @subpage LoggingApi
* - @subpage LoggingApiOverview
* - @subpage LoggingApiLoggerNames
...
...
@@ -48,7 +72,10 @@
* - @subpage SocketSessionUtility
* - <a href="./doxygen-error.log">Documentation warnings and errors</a>
*
* @todo: Move this logo to the right (and possibly up). Not sure what
* is the best way to do it in Doxygen, without using CSS hacks.
* @image html isc-logo.png
*/
/*
* @todo: Move the logo to the right (and possibly up). Not sure what
* is the best way to do it in Doxygen, without using CSS hacks.
*/
src/bin/dhcp6/dhcp6_srv.cc
View file @
19c93b08
...
...
@@ -37,7 +37,6 @@
#include <util/io_utilities.h>
#include <util/range_utilities.h>
#include <util/encode/hex.h>
#include <hooks/server_hooks.h>
#include <hooks/hooks_manager.h>
#include <hooks/callout_handle.h>
...
...
@@ -113,13 +112,13 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
alloc_engine_
.
reset
(
new
AllocEngine
(
AllocEngine
::
ALLOC_ITERATIVE
,
100
));
// Register hook points
hook_index_pkt6_receive_
=
ServerHooks
::
getServerHooks
().
registerHook
(
"pkt6_receive"
);
hook_index_subnet6_select_
=
ServerHooks
::
getServerHooks
().
registerHook
(
"subnet6_select"
);
hook_index_pkt6_send_
=
ServerHooks
::
getServerHooks
().
registerHook
(
"pkt6_send"
);
hook_index_pkt6_receive_
=
HooksManager
::
registerHook
(
"pkt6_receive"
);
hook_index_subnet6_select_
=
HooksManager
::
registerHook
(
"subnet6_select"
);
hook_index_pkt6_send_
=
HooksManager
::
registerHook
(
"pkt6_send"
);
/// @todo call loadLibraries() when handling configuration changes
vector
<
string
>
libraries
;
// no libraries at this time
HooksManager
::
getHooksManager
().
loadLibraries
(
libraries
);
HooksManager
::
loadLibraries
(
libraries
);
}
catch
(
const
std
::
exception
&
e
)
{
LOG_ERROR
(
dhcp6_logger
,
DHCP6_SRV_CONSTRUCT_ERROR
).
arg
(
e
.
what
());
...
...
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
View file @
19c93b08
...
...
@@ -36,7 +36,6 @@
#include <util/range_utilities.h>
#include <hooks/server_hooks.h>
#include <hooks/callout_manager.h>
#include <hooks/hooks_manager.h>
#include <boost/scoped_ptr.hpp>
...
...
@@ -1912,9 +1911,6 @@ public:
// clear static buffers
resetCalloutBuffers
();
// Let's pretent we're the library 0
EXPECT_NO_THROW
(
HooksManager
::
getCalloutManager
()
->
setLibraryIndex
(
0
));
}
~
HooksDhcpv6SrvTest
()
{
...
...
@@ -2116,8 +2112,8 @@ vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
TEST_F
(
HooksDhcpv6SrvTest
,
simple_pkt6_receive
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"pkt6_receive"
,
pkt6_receive_callout
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"pkt6_receive"
,
pkt6_receive_callout
));
// Let's create a simple SOLICIT
Pkt6Ptr
sol
=
Pkt6Ptr
(
captureSimpleSolicit
());
...
...
@@ -2149,8 +2145,8 @@ TEST_F(HooksDhcpv6SrvTest, simple_pkt6_receive) {
TEST_F
(
HooksDhcpv6SrvTest
,
valueChange_pkt6_receive
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"pkt6_receive"
,
pkt6_receive_change_clientid
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"pkt6_receive"
,
pkt6_receive_change_clientid
));
// Let's create a simple SOLICIT
Pkt6Ptr
sol
=
Pkt6Ptr
(
captureSimpleSolicit
());
...
...
@@ -2185,8 +2181,8 @@ TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_receive) {
TEST_F
(
HooksDhcpv6SrvTest
,
deleteClientId_pkt6_receive
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"pkt6_receive"
,
pkt6_receive_delete_clientid
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"pkt6_receive"
,
pkt6_receive_delete_clientid
));
// Let's create a simple SOLICIT
Pkt6Ptr
sol
=
Pkt6Ptr
(
captureSimpleSolicit
());
...
...
@@ -2209,8 +2205,8 @@ TEST_F(HooksDhcpv6SrvTest, deleteClientId_pkt6_receive) {
TEST_F
(
HooksDhcpv6SrvTest
,
skip_pkt6_receive
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"pkt6_receive"
,
pkt6_receive_skip
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"pkt6_receive"
,
pkt6_receive_skip
));
// Let's create a simple SOLICIT
Pkt6Ptr
sol
=
Pkt6Ptr
(
captureSimpleSolicit
());
...
...
@@ -2234,8 +2230,8 @@ TEST_F(HooksDhcpv6SrvTest, skip_pkt6_receive) {
TEST_F
(
HooksDhcpv6SrvTest
,
simple_pkt6_send
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"pkt6_send"
,
pkt6_send_callout
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"pkt6_send"
,
pkt6_send_callout
));
// Let's create a simple SOLICIT
Pkt6Ptr
sol
=
Pkt6Ptr
(
captureSimpleSolicit
());
...
...
@@ -2270,8 +2266,8 @@ TEST_F(HooksDhcpv6SrvTest, simple_pkt6_send) {
TEST_F
(
HooksDhcpv6SrvTest
,
valueChange_pkt6_send
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"pkt6_send"
,
pkt6_send_change_serverid
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"pkt6_send"
,
pkt6_send_change_serverid
));
// Let's create a simple SOLICIT
Pkt6Ptr
sol
=
Pkt6Ptr
(
captureSimpleSolicit
());
...
...
@@ -2307,8 +2303,8 @@ TEST_F(HooksDhcpv6SrvTest, valueChange_pkt6_send) {
TEST_F
(
HooksDhcpv6SrvTest
,
deleteServerId_pkt6_send
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"pkt6_send"
,
pkt6_send_delete_serverid
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"pkt6_send"
,
pkt6_send_delete_serverid
));
// Let's create a simple SOLICIT
Pkt6Ptr
sol
=
Pkt6Ptr
(
captureSimpleSolicit
());
...
...
@@ -2338,8 +2334,8 @@ TEST_F(HooksDhcpv6SrvTest, deleteServerId_pkt6_send) {
TEST_F
(
HooksDhcpv6SrvTest
,
skip_pkt6_send
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"pkt6_send"
,
pkt6_send_skip
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"pkt6_send"
,
pkt6_send_skip
));
// Let's create a simple REQUEST
Pkt6Ptr
sol
=
Pkt6Ptr
(
captureSimpleSolicit
());
...
...
@@ -2362,8 +2358,8 @@ TEST_F(HooksDhcpv6SrvTest, skip_pkt6_send) {
TEST_F
(
HooksDhcpv6SrvTest
,
subnet6_select
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"subnet6_select"
,
subnet6_select_callout
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"subnet6_select"
,
subnet6_select_callout
));
// Configure 2 subnets, both directly reachable over local interface
// (let's not complicate the matter with relays)
...
...
@@ -2430,8 +2426,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
TEST_F
(
HooksDhcpv6SrvTest
,
subnet_select_change
)
{
// Install pkt6_receive_callout
EXPECT_NO_THROW
(
HooksManager
::
get
Callout
Manager
()
->
registerCallout
(
"subnet6_select"
,
subnet6_select_different_subnet_callout
));
EXPECT_NO_THROW
(
HooksManager
::
pre
Callout
sLibraryHandle
().
registerCallout
(
"subnet6_select"
,
subnet6_select_different_subnet_callout
));
// Configure 2 subnets, both directly reachable over local interface
// (let's not complicate the matter with relays)
...
...
src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
View file @
19c93b08
...
...
@@ -1154,10 +1154,8 @@ TEST_F(HookAllocEngine6Test, lease6_select) {
HooksManager
::
getHooksManager
().
loadLibraries
(
libraries
);
// Install pkt6_receive_callout
ASSERT_TRUE
(
HooksManager
::
getCalloutManager
());
EXPECT_NO_THROW
(
HooksManager
::
getCalloutManager
()
->
setLibraryIndex
(
0
));
EXPECT_NO_THROW
(
HooksManager
::
getCalloutManager
()
->
registerCallout
(
"lease6_select"
,
lease6_select_callout
));
EXPECT_NO_THROW
(
HooksManager
::
preCalloutsLibraryHandle
().
registerCallout
(
"lease6_select"
,
lease6_select_callout
));
CalloutHandlePtr
callout_handle
=
HooksManager
::
getHooksManager
().
createCalloutHandle
();
...
...
@@ -1217,10 +1215,8 @@ TEST_F(HookAllocEngine6Test, change_lease6_select) {
HooksManager
::
getHooksManager
().
loadLibraries
(
libraries
);
// Install a callout
ASSERT_TRUE
(
HooksManager
::
getCalloutManager
());
EXPECT_NO_THROW
(
HooksManager
::
getCalloutManager
()
->
setLibraryIndex
(
0
));
EXPECT_NO_THROW
(
HooksManager
::
getCalloutManager
()
->
registerCallout
(
"lease6_select"
,
lease6_select_different_callout
));
EXPECT_NO_THROW
(
HooksManager
::
preCalloutsLibraryHandle
().
registerCallout
(
"lease6_select"
,
lease6_select_different_callout
));
// Normally, dhcpv6_srv would passed the handle when calling allocateAddress6,
// but in tests we need to create it on our own.
...
...
src/lib/hooks/Makefile.am
View file @
19c93b08
...
...
@@ -31,10 +31,11 @@ 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_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
libb10_hooks_la_SOURCES
+=
library_manager.cc library_manager.h
libb10_hooks_la_SOURCES
+=
library_manager_collection.cc library_manager_collection.h
libb10_hooks_la_SOURCES
+=
server_hooks.cc server_hooks.h
libb10_hooks_la_SOURCES
+=
hooks_manager.cc hooks_manager.h
nodist_libb10_hooks_la_SOURCES
=
hooks_messages.cc hooks_messages.h
...
...
src/lib/hooks/callout_handle.cc
View file @
19c93b08
...
...
@@ -27,8 +27,10 @@ namespace isc {
namespace
hooks
{
// Constructor.
CalloutHandle
::
CalloutHandle
(
const
boost
::
shared_ptr
<
CalloutManager
>&
manager
)
:
arguments_
(),
context_collection_
(),
manager_
(
manager
),
skip_
(
false
)
{
CalloutHandle
::
CalloutHandle
(
const
boost
::
shared_ptr
<
CalloutManager
>&
manager
,
const
boost
::
shared_ptr
<
LibraryManagerCollection
>&
lmcoll
)
:
lm_collection_
(
lmcoll
),
arguments_
(),
context_collection_
(),
manager_
(
manager
),
skip_
(
false
)
{
// Call the "context_create" hook. We should be OK doing this - although
// the constructor has not finished running, all the member variables
...
...
@@ -43,6 +45,24 @@ CalloutHandle::~CalloutHandle() {
// the destructor is being called, all the member variables are still in
// existence.
manager_
->
callCallouts
(
ServerHooks
::
CONTEXT_DESTROY
,
*
this
);
// Explicitly clear the argument and context objects. This should free up
// all memory that could have been allocated by libraries that were loaded.
arguments_
.
clear
();
context_collection_
.
clear
();
// Normal destruction of the remaining variables will include the
// destruction of lm_collection_, an action that decrements the reference
// count on the library manager collection (which holds the libraries that
// could have allocated memory in the argument and context members.) When
// that goes to zero, the libraries will be unloaded: at that point nothing
// in the hooks framework will be pointing to memory in the libraries'
// address space.
//
// It is possible that some other data structure in the server (the program
// using the hooks library) still references the address space and attempts
// to access it causing a segmentation fault. That issue is outside the
// scope of this framework and is not addressed by it.
}
// Return the name of all argument items.
...
...
@@ -130,8 +150,9 @@ CalloutHandle::getHookName() const {
try
{
hook
=
ServerHooks
::
getServerHooks
().
getName
(
index
);
}
catch
(
const
NoSuchHook
&
)
{
// Hook index is invalid, so probably called outside of a callout.
// This is a no-op.
// Hook index is invalid, so this methods probably called from outside
// a callout being executed via a call to CalloutManager::callCallouts.
// In this case, the empty string is returned.
}
return
(
hook
);
...
...
src/lib/hooks/callout_handle.h
View file @
19c93b08
...
...
@@ -54,6 +54,7 @@ public:
class
CalloutManager
;
class
LibraryHandle
;
class
LibraryManagerCollection
;
/// @brief Per-packet callout handle
///
...
...
@@ -79,11 +80,11 @@ class LibraryHandle;
/// "context_destroy" callout. The information is accessed through the
/// {get,set}Context() methods.
///
/// - Per-library handle
. Allows the callout to dynamically register and
/// deregister callouts.
(
In the latter
case, only functions registered by
/// functions in the same library as the
callout doing the deregistration
/// can be removed: callouts registered by
other libraries cannot be
/// modified.
)
/// - Per-library handle
(LibraryHandle). The library handle allows the
///
callout to dynamically register and
deregister callouts. In the latter
///
case, only functions registered by
functions in the same library as the
///
callout doing the deregistration
can be removed: callouts registered by
///
other libraries cannot be
modified.
class
CalloutHandle
{
public:
...
...
@@ -110,12 +111,27 @@ public:
/// Creates the object and calls the callouts on the "context_create"
/// hook.
///
/// Of the two arguments passed, only the pointer to the callout manager is
/// actively used. The second argument, the pointer to the library manager
/// collection, is used for lifetime control: after use, the callout handle
/// may contain pointers to memory allocated by the loaded libraries. The
/// used of a shared pointer to the collection of library managers means
/// that the libraries that could have allocated memory in a callout handle
/// will not be unloaded until all such handles have been destroyed. This
/// issue is discussed in more detail in the documentation for
/// isc::hooks::LibraryManager.
///
/// @param manager Pointer to the callout manager object.
CalloutHandle
(
const
boost
::
shared_ptr
<
CalloutManager
>&
manager
);
/// @param lmcoll Pointer to the library manager collection. This has a
/// null default for testing purposes.
CalloutHandle
(
const
boost
::
shared_ptr
<
CalloutManager
>&
manager
,
const
boost
::
shared_ptr
<
LibraryManagerCollection
>&
lmcoll
=
boost
::
shared_ptr
<
LibraryManagerCollection
>
());
/// @brief Destructor
///
/// Calls the context_destroy callback to release any per-packet context.
/// It also clears stored data to avoid problems during member destruction.
~
CalloutHandle
();
/// @brief Set argument
...
...
@@ -152,7 +168,7 @@ public:
value
=
boost
::
any_cast
<
T
>
(
element_ptr
->
second
);
}
/// @brief Get argument names
///
/// Returns a vector holding the names of arguments in the argument
...
...
@@ -257,7 +273,7 @@ public:
value
=
boost
::
any_cast
<
T
>
(
element_ptr
->
second
);
}
/// @brief Get context names
///
/// Returns a vector holding the names of items in the context associated
...
...
@@ -340,6 +356,10 @@ private:
// Member variables
/// Pointer to the collection of libraries for which this handle has been
/// created.
boost
::
shared_ptr
<
LibraryManagerCollection
>
lm_collection_
;
/// Collection of arguments passed to the callouts
ElementCollection
arguments_
;
...
...
@@ -353,10 +373,10 @@ private:
bool
skip_
;
};
///
a
shared pointer to CalloutHandle object
///
A
shared pointer to
a
CalloutHandle object
.
typedef
boost
::
shared_ptr
<
CalloutHandle
>
CalloutHandlePtr
;
}
// namespace
util
}
// namespace
hooks
}
// namespace isc
...
...
src/lib/hooks/callout_manager.cc
View file @
19c93b08
...
...
@@ -19,6 +19,7 @@
#include <boost/static_assert.hpp>
#include <algorithm>
#include <climits>
#include <functional>
#include <utility>
...
...
@@ -27,12 +28,41 @@ using namespace std;
namespace
isc
{
namespace
hooks
{
// Check that the index of a library is valid. It can range from 1 - n
// (n is the number of libraries), 0 (pre-user library callouts), or INT_MAX
// (post-user library callouts). It can also be -1 to indicate an invalid
// value.
void
CalloutManager
::
checkLibraryIndex
(
int
library_index
)
const
{
if
(((
library_index
>=
-
1
)
&&
(
library_index
<=
num_libraries_
))
||
(
library_index
==
INT_MAX
))
{
return
;
}
isc_throw
(
NoSuchLibrary
,
"library index "
<<
library_index
<<
" is not valid for the number of loaded libraries ("
<<
num_libraries_
<<
")"
);
}
// Set the number of libraries handled by the CalloutManager.
void
CalloutManager
::
setNumLibraries
(
int
num_libraries
)
{
if
(
num_libraries
<
0
)
{
isc_throw
(
isc
::
BadValue
,
"number of libraries passed to the "
"CalloutManager must be >= 0"
);
}
num_libraries_
=
num_libraries
;
}
// Register a callout for the current library.
void
CalloutManager
::
registerCallout
(
const
std
::
string
&
name
,
CalloutPtr
callout
)
{
// Note the registration.
LOG_DEBUG
(
hooks_logger
,
HOOKS_DBG_CALLS
,
HOOKS_
REGISTER_CALLOUT
)
LOG_DEBUG
(
hooks_logger
,
HOOKS_DBG_CALLS
,
HOOKS_
CALLOUT_REGISTRATION
)
.
arg
(
current_library_
).
arg
(
name
);
// Sanity check that the current library index is set to a valid value.
...
...
@@ -108,15 +138,24 @@ CalloutManager::callCallouts(int hook_index, CalloutHandle& callout_handle) {
current_library_
=
i
->
first
;
// Call the callout
// @todo Log the return status if non-zero
int
status
=
(
*
i
->
second
)(
callout_handle
);
if
(
status
==
0
)
{
LOG_DEBUG
(
hooks_logger
,
HOOKS_DBG_EXTENDED_CALLS
,
HOOKS_CALLOUT
)
.
arg
(
current_library_
)
.
arg
(
ServerHooks
::
getServerHooks
().
getName
(
current_hook_
))
.
arg
(
reinterpret_cast
<
void
*>
(
i
->
second
));
}
else
{
LOG_WARN
(
hooks_logger
,
HOOKS_CALLOUT_ERROR
)
try
{
int
status
=
(
*
i
->
second
)(
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
(
reinterpret_cast
<
void
*>
(
i
->
second
));
}
else
{
LOG_ERROR
(
hooks_logger
,
HOOKS_CALLOUT_ERROR
)
.
arg
(
current_library_
)
.
arg
(
ServerHooks
::
getServerHooks
()
.
getName
(
current_hook_
))
.
arg
(
reinterpret_cast
<
void
*>
(
i
->
second
));
}
}
catch
(...)
{
// 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
(
reinterpret_cast
<
void
*>
(
i
->
second
));
...
...
@@ -170,7 +209,7 @@ CalloutManager::deregisterCallout(const std::string& name, CalloutPtr callout) {
bool
removed
=
initial_size
!=
hook_vector_
[
hook_index
].
size
();
if
(
removed
)
{
LOG_DEBUG
(
hooks_logger
,
HOOKS_DBG_EXTENDED_CALLS
,
HOOKS_DEREGISTER
_CALLOUT
).
arg
(
current_library_
).
arg
(
name
);
HOOKS_
CALLOUT_
DEREGISTER
ED
).
arg
(
current_library_
).
arg
(
name
);
}
return
(
removed
);
...
...
@@ -205,7 +244,7 @@ CalloutManager::deregisterAllCallouts(const std::string& name) {
bool
removed
=
initial_size
!=
hook_vector_
[
hook_index
].
size
();
if
(
removed
)
{
LOG_DEBUG
(
hooks_logger
,
HOOKS_DBG_EXTENDED_CALLS
,
HOOKS_
DEREGISTER_
ALL_CALLOUTS
).
arg
(
current_library_
)
HOOKS_ALL_CALLOUTS
_DEREGISTERED
).
arg
(
current_library_
)
.
arg
(
name
);
}
...
...
src/lib/hooks/callout_manager.h
View file @
19c93b08
...
...
@@ -21,6 +21,7 @@
#include <boost/shared_ptr.hpp>
#include <climits>
#include <map>
#include <string>
...
...
@@ -37,11 +38,11 @@ public:
isc
::
Exception
(
file
,
line
,
what
)
{}
};
/// @brief Callout Manager
///
/// This class manages the registration, deregistration and execution of the
/// library callouts.
/// library callouts. It is part of the hooks framework used by the BIND 10
/// server, and is not for use by user-written code in a hooks library.
///
/// In operation, the class needs to know two items of data:
///
...
...
@@ -59,14 +60,51 @@ public:
/// deregister callouts in the same library (including themselves): they
/// cannot affect callouts registered by another library. When calling a
/// callout, the callout manager maintains the idea of a "current library
/// index": if the callout calls one of the callout registration functions
/// index": if the callout calls one of the callout registration functions
/// (indirectly via the @ref LibraryHandle object), the registration
/// functions use the "current library index" in their processing.
///
/// These two items of data are supplied when an object of this class is
/// constructed.
/// constructed. The latter (number of libraries) can be updated after the
/// class is constructed. (Such an update is used during library loading where
/// the CalloutManager has to be constructed before the libraries are loaded,
/// but one of the libraries subsequently fails to load.)
///
/// The library index is important because it determines in what order callouts
/// on a particular hook are called. For each hook, the CalloutManager
/// maintains a vector of callouts ordered by library index. When a callout
/// is added to the list, it is added at the end of the callouts associated
/// with the current library. To clarify this further, suppose that three
/// libraries are loaded, A (assigned an index 1), B (assigned an index 2) and
/// C (assigned an index 3). Suppose A registers two callouts on a given hook,
/// A1 and A2 (in that order) B registers B1 and B2 (in that order) and C
/// registers C1 and C2 (in that order). Internally, the callouts are stored
/// in the order A1, A2, B1, B2, C1, and C2: this is also the order in which
/// the are called. If B now registers another callout (B3), it is added to
/// the vector after the list of callouts associated with B: the new order is
/// therefore A1, A2, B1, B2, B3, C1 and C2.
///
/// Indexes range between 1 and n (where n is the number of the libraries
/// loaded) and are assigned to libraries based on the order the libraries
/// presented to the hooks framework for loading (something that occurs in the
/// isc::util::HooksManager) class. However, two other indexes are recognised,
/// 0 and INT_MAX. These are used when the server itself registers callouts -
/// the server is able to register callouts that get called before any
/// user-library callouts, and ones that get called after user-library callouts.
/// In other words, assuming the callouts on a hook are A1, A2, B1, B2, B3, C2,
/// C2 as before, and that the server registers S1 (to run before the
/// user-registered callouts) and S2 (to run after them), the callouts are
/// stored (and executed) in the order S1, A1, A2, B1, B2, B3, C2, C2, S2. In
/// summary, the recognised index values are:
///
/// - < 0: invalid.
/// - 0: used for server-registered callouts that are called before
/// user-registered callouts.
/// - 1 - n: callouts from user libraries.
/// - INT_MAX: used for server-registered callouts called after
/// user-registered callouts.
///
/// Note that the callout function do not access the
library m
anager: instead,
/// Note that the callout function
s
do not access the
CalloutM
anager: instead,
/// they use a LibraryHandle object. This contains an internal pointer to
/// the CalloutManager, but provides a restricted interface. In that way,
/// callouts are unable to affect callouts supplied by other libraries.
...
...
@@ -96,17 +134,16 @@ public:
///
/// @throw isc::BadValue if the number of libraries is less than or equal
/// to 0, or if the pointer to the server hooks object is empty.
CalloutManager
(
int
num_libraries
)
:
current_hook_
(
-
1
),
current_library_
(
-
1
),
hook_vector_
(),
library_handle_
(
this
),
num_libraries_
(
num_libraries
)
CalloutManager
(
int
num_libraries
=
0
)
:
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
)
{
if
(
num_libraries
<=
0
)
{
isc_throw
(
isc
::
BadValue
,
"number of libraries passed to the "
"CalloutManager must be >= 0"
);
}