Browse Source

[2982] Updates to address review comments

Stephen Morris 11 years ago
parent
commit
cc508f6c28
2 changed files with 331 additions and 169 deletions
  1. 16 16
      doc/devel/mainpage.dox
  2. 315 153
      src/lib/hooks/hook_user.dox

+ 16 - 16
doc/devel/mainpage.dox

@@ -36,22 +36,22 @@
  * Regardless of your field of expertise, you are encouraged to visit
  * Regardless of your field of expertise, you are encouraged to visit
  * <a href="http://bind10.isc.org/">BIND10 webpage (http://bind10.isc.org)</a>
  * <a href="http://bind10.isc.org/">BIND10 webpage (http://bind10.isc.org)</a>
  *
  *
- * @section hookDevelopersGuide
+ * @section hooksdgDevelopersGuide
- * - @subpage hookIntroduction
+ * - @subpage hooksdgIntroduction
- *   - @subpage hookLanguages
+ *   - @subpage hooksdgLanguages
- *   - @subpage hookTerminology
+ *   - @subpage hooksdgTerminology
- * - @subpage hookTutorial
+ * - @subpage hooksdgTutorial
- *   - @subpage hookFrameworkFunctions
+ *   - @subpage hooksdgFrameworkFunctions
- *   - @subpage hookCallouts
+ *   - @subpage hooksdgCallouts
- *   - @subpage hookExampleCallouts
+ *   - @subpage hooksdgExampleCallouts
- *   - @subpage hookBuild
+ *   - @subpage hooksdgBuild
- *   - @subpage hookConfiguration
+ *   - @subpage hooksdgConfiguration
- * - @subpage hookAdvancedTopics
+ * - @subpage hooksdgAdvancedTopics
- *   - @subpage hookContextCreateDestroy
+ *   - @subpage hooksdgContextCreateDestroy
- *   - @subpage hookCalloutRegistration
+ *   - @subpage hooksdgCalloutRegistration
- *   - @subpage hookMultipleLibraries
+ *   - @subpage hooksdgMultipleLibraries
- *   - @subpage hookInterLibraryData
+ *   - @subpage hooksdgInterLibraryData
- *   - @subpage hookRegisterMultipleLibraries
+ *   - @subpage hooksdgRegisterMultipleLibraries
  *
  *
  * @section dnsMaintenanceGuide DNS Maintenance Guide
  * @section dnsMaintenanceGuide DNS Maintenance Guide
  * - Authoritative DNS (todo)
  * - Authoritative DNS (todo)

+ 315 - 153
src/lib/hooks/hook_user.dox

@@ -12,10 +12,14 @@
 // 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.
 
 
+// Note: the prefix "hooksdg" to all labels is an abbreviation for "Hooks
+// Developer's Guide" and is used to prevent a clash with symbols in any
+// other Doxygen file.
+
 /**
 /**
- @page hookDevelopersGuide Hook Developer's Guide
+ @page hooksdgDevelopersGuide Hook Developer's Guide
 
 
- @section hookIntroduction Introduction
+ @section hooksdgIntroduction Introduction
 
 
 Although the BIND 10 framework and its associated DNS and DHCP programs
 Although the BIND 10 framework and its associated DNS and DHCP programs
 provide comprehensive functionality, there will be times when it does
 provide comprehensive functionality, there will be times when it does
@@ -31,7 +35,7 @@ understanding how it works will take a significant amount of time. In
 addition, despite the fact that its object-oriented design keeps the
 addition, despite the fact that its object-oriented design keeps the
 coupling between modules to a minimum, an inappropriate change to one
 coupling between modules to a minimum, an inappropriate change to one
 part of the program during the extension could cause another to
 part of the program during the extension could cause another to
-behave oddly or to stop working altogether, adding to development time.
+behave oddly or to stop working altogether.
 
 
 - The change may need to be re-applied or re-written with every new
 - The change may need to be re-applied or re-written with every new
 version of BIND 10.  As new functionality is added or bugs are fixed,
 version of BIND 10.  As new functionality is added or bugs are fixed,
@@ -39,59 +43,59 @@ the code or algorithms in the core software may change - and may change
 significantly.
 significantly.
 
 
 To overcome these problems, BIND 10 provides the "Hooks" interface -
 To overcome these problems, BIND 10 provides the "Hooks" interface -
-a defined interface for third-party or user-written code (for ease of
+a defined interface for third-party or user-written code. (For ease of
-reference in the rest of this document, such code will be referred to
+reference in the rest of this document, all such code will be referred
-as "user-written code").  At specific points in its processing ("hook
+to as "user code".)  At specific points in its processing
-points") BIND 10 will make a call to this code.  The call passes data
+("hook points") BIND 10 will make a call to this code.  The call passes
-that the user can examine and, if required, modify.  BIND 10 used the
+data that the user code can examine and, if required, modify.
-modified code in the remainder of its processing.
+BIND 10 uses the modified data in the remainder of its processing.
-
+
-In order to minimise the interaction between BIND 10 and the 
+In order to minimise the interaction between BIND 10 and the user
 code, the latter is built independently of BIND 10 in the form of
 code, the latter is built independently of BIND 10 in the form of
 a shared library (or libraries).  These are made known to BIND 10
 a shared library (or libraries).  These are made known to BIND 10
 through its configuration mechanism, and BIND 10 loads the library at
 through its configuration mechanism, and BIND 10 loads the library at
 run time. Libraries can be unloaded and reloaded as needed while BIND
 run time. Libraries can be unloaded and reloaded as needed while BIND
 10 is running.
 10 is running.
 
 
-Use of a defined API and BIND 10 configuration mechanism means that as
+Use of a defined API and the BIND 10 configuration mechanism means that
-new versions of BIND 10 are released, there is no need to modify the
+as new versions of BIND 10 are released, there is no need to modify
-user-written code.  Unless there is a major change in an interface
+the user code.  Unless there is a major change in an interface
-(which will be clearly documented) all that will be required is a
+(which will be clearly documented), all that will be required is a rebuild
-rebuild of the libraries.
+of the libraries.
 
 
 @note Although the defined interface should not change, the internals
 @note Although the defined interface should not change, the internals
-of some of the classes and structures referenced by the user-written
+of some of the classes and structures referenced by the user code may
-code may alter.  These changes will need to be reflected in the compiled
+change between versions of BIND 10.  These changes have to be reflected
-version of the software, hence the need for a rebuild.
+in the compiled version of the software, hence the need for a rebuild.
 
 
-@subsection hookLanguages Languages
+@subsection hooksdgLanguages Languages
 
 
 The core of BIND 10 is written in C++.  While it is the intention to
 The core of BIND 10 is written in C++.  While it is the intention to
-provide interfaces into user code written into other languages, the
+provide interfaces into user code written in other languages, the initial
-initial versions of the Hooks system requires that user code be written
+versions of the Hooks system requires that user code be written in C++.
-in C++.  All examples in this guide are in that language.
+All examples in this guide are in that language.
 
 
-@subsection hookTerminology Terminology
+@subsection hooksdgTerminology Terminology
 
 
 In the remainder of this guide, the following terminology is used:
 In the remainder of this guide, the following terminology is used:
 
 
 - Hook/Hook Point - used interchageably, this is a point in the code at
 - Hook/Hook Point - used interchageably, this is a point in the code at
-which a call to user-written functions is made. Each hook has a name and
+which a call to user functions is made. Each hook has a name and
-each hook can have any number (including 0) of user-written functions
+each hook can have any number (including 0) of user functions
 attached to it.
 attached to it.
 
 
-- Callout - a user-written function called by the server at a hook
+- Callout - a user function called by the server at a hook
 point. This is so-named because the server "calls out" to the library
 point. This is so-named because the server "calls out" to the library
-to execute a user-written function.
+to execute a user function.
 
 
-- Framework function - the functions that a user-written library needs to
+- Framework function - the functions that a user library needs to
-supply in order for the hooks framework for load and unload the library.
+supply in order for the hooks framework to load and unload the library.
 
 
 - User code/user library - non-BIND 10 code that is compiled into a
 - User code/user library - non-BIND 10 code that is compiled into a
 shared library and loaded by BIND 10 into its address space.
 shared library and loaded by BIND 10 into its address space.
 
 
 
 
-@section hookTutorial Tutorial
+@section hooksdgTutorial Tutorial
 
 
 To illustrate how to write code that integrates with BIND 10, we will
 To illustrate how to write code that integrates with BIND 10, we will
 use the following (rather contrived) example:
 use the following (rather contrived) example:
@@ -103,14 +107,14 @@ IPv4 addresses according to their hardware address, and want to log both
 the hardware address and allocated IP address for the clients of interest.
 the hardware address and allocated IP address for the clients of interest.
 
 
 The following sections describe how to implement these requirements.
 The following sections describe how to implement these requirements.
-The code presented here is not efficient and there are better ways
+The code presented here is not efficient and there are better ways of
-of doing the task.  The aim is to illustrate the main features of
+doing the task.  The aim however, is to illustrate the main features of
-user-written hook code rather than provide an optimal solution.
+user hook code not to provide an optimal solution.
 
 
 
 
-@subsection hookFrameworkFunctions Framework Functions
+@subsection hooksdgFrameworkFunctions Framework Functions
 
 
-Loading an initializing a library holding user-written code makes use
+Loading and initializing a library holding user code makes use
 of three (user-supplied) functions:
 of three (user-supplied) functions:
 
 
 - version - defines the version of BIND 10 code with which the user-library
 - version - defines the version of BIND 10 code with which the user-library
@@ -118,10 +122,10 @@ is built
 - load - called when the library is loaded by the server.
 - load - called when the library is loaded by the server.
 - unload - called when the library is unloaded by the server.
 - unload - called when the library is unloaded by the server.
 
 
-Of these, only "version" is mandatory, although our in out example, all three
+Of these, only "version" is mandatory, although our in our example, all three
 are used.
 are used.
 
 
-@subsubsection hookVersionFunction The "version" Function
+@subsubsection hooksdgVersionFunction The "version" Function
 
 
 "version" is used by the hooks framework to check that the libraries
 "version" is used by the hooks framework to check that the libraries
 it is loading are compatible with the version of BIND 10 being run.
 it is loading are compatible with the version of BIND 10 being run.
@@ -129,14 +133,14 @@ Although the hooks system allows BIND 10 and user code to interface
 through a defined API, the relationship is somewhat tight in that the
 through a defined API, the relationship is somewhat tight in that the
 user code will depend on the internal structures of BIND 10.  If these
 user code will depend on the internal structures of BIND 10.  If these
 change - as they can between BIND 10 releases - and BIND 10 is run with
 change - as they can between BIND 10 releases - and BIND 10 is run with
-a version of user-written code built against an earlier version of BIND
+a version of user code built against an earlier version of BIND
 10, a program crash could result.
 10, a program crash could result.
 
 
-To guard against this, the "version" function must be provided in
+To guard against this, the "version" function must be provided in every
-every library.  It returns a constant defined in the version of header
+library.  It returns a constant defined in header files of the version
-files against which it was built.  The hooks framework checks this for
+of BIND 10 against which it was built.  The hooks framework checks this
-compatibility with the running version of BIND 10 before proceeding with
+for compatibility with the running version of BIND 10 before loading
-the library load.
+the library.
 
 
 In this tutorial, we'll put "version" in its own file, version.cc.  The
 In this tutorial, we'll put "version" in its own file, version.cc.  The
 contents are:
 contents are:
@@ -155,10 +159,11 @@ int version() {
 };
 };
 @endcode
 @endcode
 
 
-The file "hooks/hooks.h" is specified relative to the BIND 10 libraries source
+The file "hooks/hooks.h" is specified relative to the BIND 10 libraries
-directory - this is covered later in the section @ref hookBuild.  It defines the
+source directory - this is covered later in the section @ref hooksdgBuild.
-symbol BIND10_HOOKS_VERSION, which has a value that changes on every release
+It defines the symbol BIND10_HOOKS_VERSION, which has a value that changes
-of BIND 10: this is the value that needs to be returned to the hooks framework.
+on every release of BIND 10: this is the value that needs to be returned
+to the hooks framework.
 
 
 A final point to note is that the definition of "version" is enclosed
 A final point to note is that the definition of "version" is enclosed
 within 'extern "C"' braces.  All functions accessed by the hooks
 within 'extern "C"' braces.  All functions accessed by the hooks
@@ -166,31 +171,36 @@ framework use C linkage, mainly to avoid the name mangling that
 accompanies use of the C++ compiler, but also to avoid issues related
 accompanies use of the C++ compiler, but also to avoid issues related
 to namespaces.
 to namespaces.
 
 
-@subsubsection hookLoadUnloadFunctions The "load" and "unload" Functions
+@subsubsection hooksdgLoadUnloadFunctions The "load" and "unload" Functions
 
 
 As the names suggest, "load" is called when a library is loaded and
 As the names suggest, "load" is called when a library is loaded and
-"unload" called when it is unloaded.  (It is always guaranteed that "load"
+"unload" called when it is unloaded.  (It is always guaranteed that
-is called: "unload" may not be called in some circumstances, e.g. if the
+"load" is called: "unload" may not be called in some circumstances,
-system shuts down abnormally.)  These functions are the places where any
+e.g. if the system shuts down abnormally.)  These functions are the
-library-wide resources are allocated and deallocated.  "load" is also
+places where any library-wide resources are allocated and deallocated.
-the place where any callouts with non-standard names can be registered:
+"load" is also the place where any callouts with non-standard names
-this is covered further in the section @ref hookCalloutRegistration.
+(names that are not hook point names) can be registered:
+this is covered further in the section @ref hooksdgCalloutRegistration.
 
 
 The example does not make any use callouts with non-standard names.  However,
 The example does not make any use callouts with non-standard names.  However,
 as our design requires that the log file be open while BIND 10 is active
 as our design requires that the log file be open while BIND 10 is active
 and the library loaded, we'll open the file in the "load" function and close
 and the library loaded, we'll open the file in the "load" function and close
-it in "unload".  We create two files, one for the file handle declaration:
+it in "unload".
+
+We create two files, one for the file handle declaration:
 
 
 @code
 @code
 // library_common.h
 // library_common.h
 
 
 #ifndef LIBRARY_COMMON_H
 #ifndef LIBRARY_COMMON_H
 #define LIBRARY_COMMON_H
 #define LIBRARY_COMMON_H
+
 #include <fstream>
 #include <fstream>
 
 
 // "Interesting clients" log file handle declaration.
 // "Interesting clients" log file handle declaration.
 extern std::fstream interesting;
 extern std::fstream interesting;
-#endif
+
+#endif // LIBRARY_COMMON_H
 @endcode
 @endcode
 
 
 ... and one to hold the "load" and "unload" functions:
 ... and one to hold the "load" and "unload" functions:
@@ -227,37 +237,40 @@ Notes:
 outside of any function.  This means it can be accessed by any function
 outside of any function.  This means it can be accessed by any function
 within the user library.  For convenience, the definition is in the
 within the user library.  For convenience, the definition is in the
 load_unload.cc file.
 load_unload.cc file.
-- "load" is called with a LibraryHandle argument, used in the registration
+- "load" is called with a LibraryHandle argument, this being used in
-of functions.  As no functions are being called in this example,
+the registration of functions.  As no functions are being registered
-the argument specification omits the variable name (whilst retaining the type)
+in this example, the argument specification omits the variable name
-to avoid an "unused variable" compiler warning. (The LibraryHandle is
+(whilst retaining the type) to avoid an "unused variable" compiler
-discussed in the section @ref hookLibraryHandle.)
+warning. (The LibraryHandle and its use is discussed in the section
+@ref hooksdgLibraryHandle.)
 - In the current version of the hooks framework, it is not possible to pass
 - In the current version of the hooks framework, it is not possible to pass
 any configuration information to the "load" function.  The name of the log
 any configuration information to the "load" function.  The name of the log
-file must therefore be hard-coded as an absolute path name, or communicated
+file must therefore be hard-coded as an absolute path name or communicated
-to the user-written code by some other means.
+to the user code by some other means.
-- "load" returns 0 on success and non-zero on error.  The hooks framework
+- "load" must 0 on success and non-zero on error.  The hooks framework
 will abandon the loading of the library if "load" returns an error status.
 will abandon the loading of the library if "load" returns an error status.
 (In this example, "interesting" can be tested as a boolean value,
 (In this example, "interesting" can be tested as a boolean value,
 returning "true" if the file opened successfully.)
 returning "true" if the file opened successfully.)
 - "unload" closes the log file if it is open and is a no-op otherwise. As
 - "unload" closes the log file if it is open and is a no-op otherwise. As
-with "load", a zero value is returned on success and a non-zero value
+with "load", a zero value must be returned on success and a non-zero value
 on an error.  The hooks framework will record a non-zero status return
 on an error.  The hooks framework will record a non-zero status return
 as an error in the current BIND 10 log but otherwise ignore it.
 as an error in the current BIND 10 log but otherwise ignore it.
 - As before, the function definitions are enclosed in 'extern "C"' braces.
 - As before, the function definitions are enclosed in 'extern "C"' braces.
 
 
-@subsection hookCallouts Callouts
+@subsection hooksdgCallouts Callouts
 
 
 Having sorted out the framework, we now come to the functions that
 Having sorted out the framework, we now come to the functions that
 actually do something.  These functions are known as "callouts" because
 actually do something.  These functions are known as "callouts" because
-the BIND 10 code "calls out" to them.  Each BIND 10 server has a number
+the BIND 10 code "calls out" to them.  Each BIND 10 server has a number of
-of hooks to which callouts can be attached: the purpose of the hooks
+hooks to which callouts can be attached: server-specific documentation
-and the data passed to callouts is documented elsewhere.
+describes in detail the points in the server at which the hooks are
+present together with the data passed to callouts attached to them.
 
 
 Before we continue with the example, we'll discuss how arguments are
 Before we continue with the example, we'll discuss how arguments are
-passed to callouts and how information can be moved between them.
+passed to callouts and information is returned to the server.  We will
+also discuss how information can be moved between callouts.
 
 
-@subsubsection hookCalloutSignature The Callout Signature
+@subsubsection hooksdgCalloutSignature The Callout Signature
 
 
 All callouts are declared with the signature:
 All callouts are declared with the signature:
 @code
 @code
@@ -279,7 +292,7 @@ log an error, specifying both the library and hook that generated it.
 Effectively the return status provides a quick way for a callout to log
 Effectively the return status provides a quick way for a callout to log
 error information to the BIND 10 logging system.
 error information to the BIND 10 logging system.
 
 
-@subsubsection hookArguments Callout Arguments
+@subsubsection hooksdgArguments Callout Arguments
 
 
 The CalloutHandle object provides two methods to get and set the
 The CalloutHandle object provides two methods to get and set the
 arguments passed to the callout.  These methods are called (naturally
 arguments passed to the callout.  These methods are called (naturally
@@ -296,7 +309,7 @@ following code snippets.
     handle.setArgument("data_count", count);
     handle.setArgument("data_count", count);
     handle.setArgument("inpacket", pktptr);
     handle.setArgument("inpacket", pktptr);
 
 
-    // Call the hook code...
+    // Call the callouts attached to the hook
     ...
     ...
 
 
     // Retrieve the modified values
     // Retrieve the modified values
@@ -342,15 +355,13 @@ be thrown if an attempt is made to retrieve it into a variable of type
 "const char*".  (However, if an argument is set as a "const int", it can
 "const char*".  (However, if an argument is set as a "const int", it can
 be retrieved into an "int".)  The documentation of each hook point will
 be retrieved into an "int".)  The documentation of each hook point will
 detail the data type of each argument.
 detail the data type of each argument.
-
 - Although all arguments can be modified, some altered values may not
 - Although all arguments can be modified, some altered values may not
 be read by the server. (These would be ones that the server considers
 be read by the server. (These would be ones that the server considers
 "read-only".) Consult the documentation of each hook to see whether an
 "read-only".) Consult the documentation of each hook to see whether an
 argument can be used to transfer data back to the server.
 argument can be used to transfer data back to the server.
-
 - If a pointer to an object is passed to a callout (either a "raw"
 - If a pointer to an object is passed to a callout (either a "raw"
 pointer, or a boost smart pointer (as in the example above), and the
 pointer, or a boost smart pointer (as in the example above), and the
-underlying object altered through that pointer, the change will be
+underlying object is altered through that pointer, the change will be
 reflected in the server even if no call is made to setArgument.
 reflected in the server even if no call is made to setArgument.
 
 
 In all cases, consult the documentation for the particular hook to see whether
 In all cases, consult the documentation for the particular hook to see whether
@@ -361,10 +372,54 @@ the server.
 - If you alter an argument, call CalloutHandle::setArgument to update the
 - If you alter an argument, call CalloutHandle::setArgument to update the
 value in the CalloutHandle object.
 value in the CalloutHandle object.
 
 
-@subsubsection hookCalloutContext Per-Request Context
+@subsubsection hooksdgSkipFlag The "Skip" Flag
+
+When a to callouts attached to a hook returns, the server will usually continue
+its processing.  However, a callout might have done something that means that
+the server should follow another path.  Possible actions a server could take
+include:
+
+- Skip the next stage of processing because the callout has already
+done it.  For example, a hook is located just before the DHCP server
+allocates an address to the client.  A callout may decide to allocate
+special addresses for certain clients, in which case it needs to tell
+the server not to allocate an address in this case.
+- Drop the packet and continue with the next request. A possible scenario
+is a DNS server where a callout inspects the source address of an incoming
+packet and compares it against a black list; if the address is on it,
+the callout notifies the server to drop the packet.
+
+To handle these common cases, the CalloutHandle has a "skip" flag.
+This is set by a callout when it wishes the server to skip normal
+processing.  It is set false by the hooks framework before callouts on a
+hook are called.  If the flag is set on return, the server will take the
+"skip" action relevant for the hook.
+
+The methods to get and set the "skip" flag are getSkip and setSkip. Their
+usage is intuitive:
+
+@code
+    // Get the current setting of the skip flag.
+    bool skip = handle.getSkip();
+
+    // Do some processing...
+        :
+    if (lease_allocated) {
+        // Flag the server to skip the next step of the processing as we
+        // already have an address.
+        handle.setSkip(true);
+    }
+    return;
+    
+@endcode
+
+Like arguments, the "skip" flag is passed to all callouts on a hook.  Callouts
+later in the list are able to examine (and modify) the settings of earlier ones.
+
+@subsubsection hooksdgCalloutContext Per-Request Context
 
 
 Although many of the BIND 10 modules can be characterised as handling
 Although many of the BIND 10 modules can be characterised as handling
-a single packet - e.g. the DHCPv4 server receives a DISCOVER packet,
+singles packet - e.g. the DHCPv4 server receives a DISCOVER packet,
 processes it and responds with an OFFER, this is not true in all cases.
 processes it and responds with an OFFER, this is not true in all cases.
 The principal exception is the recursive DNS resolver: this receives a
 The principal exception is the recursive DNS resolver: this receives a
 packet from a client but that packet may itself generate multiple packets
 packet from a client but that packet may itself generate multiple packets
@@ -381,9 +436,8 @@ per-request basis.
 Context only exists only for the duration of the request: when a request
 Context only exists only for the duration of the request: when a request
 is completed, the context is destroyed.  A new request starts with no
 is completed, the context is destroyed.  A new request starts with no
 context information.  Context is particularly useful in servers that may
 context information.  Context is particularly useful in servers that may
-be processing multiple requests simultaneously: callouts are effectively
+be processing multiple requests simultaneously: callouts can effectively
-attaching data to a request and that data follows the request around the
+attach data to a request that follows the request around the system.
-system.
 
 
 Context information is held as name/value pairs in the same way
 Context information is held as name/value pairs in the same way
 as arguments, being accessed by the pair of methods setContext and
 as arguments, being accessed by the pair of methods setContext and
@@ -391,11 +445,9 @@ getContext.  They have the same restrictions as the setArgument and
 getArgument methods - the type of data retrieved from context must
 getArgument methods - the type of data retrieved from context must
 <B>exactly</B> match the type of the data set.
 <B>exactly</B> match the type of the data set.
 
 
-As the example in the tutorial uses per-request context, no separate
+The example in the next section illustrates their use.
-example is given here.
 
 
-
+@subsection hooksdgExampleCallouts Example Callouts
-@subsection hookExampleCallouts Example Callouts
 
 
 Continuing with the tutorial, the requirements need us to retrieve the
 Continuing with the tutorial, the requirements need us to retrieve the
 hardware address of the incoming packet, classify it, and write it,
 hardware address of the incoming packet, classify it, and write it,
@@ -409,14 +461,14 @@ We will do the classification here.
 
 
 - v4_lease_write_post - called when the lease (an assignment of an IPv4
 - 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
 address to a client for a fixed period of time) has been written to the
-database. It is passed two (constant) arguments, the query ("query")
+database. It is passed two arguments, the query ("query")
 and the response (called "reply").  This is the point at which the
 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.
 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
 by the Hooks system (this is discussed further in section @ref
 by the Hooks system (this is discussed further in section @ref
-hookCalloutRegistration).  For our example, we will assume this is the
+hooksdgCalloutRegistration).  For our example, we will assume this is the
 case, so the code for the first callout (used to classify the client's
 case, so the code for the first callout (used to classify the client's
 hardware address) is:
 hardware address) is:
 
 
@@ -435,7 +487,6 @@ using namespace std;
 extern "C" {
 extern "C" {
 
 
 // This callout is called at the "pkt_rcvd" hook.
 // This callout is called at the "pkt_rcvd" hook.
-
 int pkt_rcvd(CalloutHandle& handle) {
 int pkt_rcvd(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
@@ -485,7 +536,6 @@ using namespace std;
 extern "C" {
 extern "C" {
 
 
 // This callout is called at the "v4_lease_write_post" hook.
 // This callout is called at the "v4_lease_write_post" hook.
-
 int v4_lease_write_post(CalloutHandle& handle) {
 int v4_lease_write_post(CalloutHandle& handle) {
 
 
     // Obtain the hardware address of the "interesting" client.  We have to
     // Obtain the hardware address of the "interesting" client.  We have to
@@ -495,10 +545,10 @@ int v4_lease_write_post(CalloutHandle& handle) {
     try (handle.getArgument("hwaddr", hwaddr) {
     try (handle.getArgument("hwaddr", hwaddr) {
 
 
         // getArgument didn't throw so the client is interesting.  Get a pointer
         // getArgument didn't throw so the client is interesting.  Get a pointer
-        // to the reply.  This is read-only so is passed through a smart pointer
+        // to the reply.  Note that the argument list for this hook also
-        // const Pkt4 object.  Note that the argument list also contains a
+        // contains a pointer to the query: we don't need to access that in this
-        // pointer to the query: we don't need to access that in this example.
+        // example.
-        ConstPkt4Ptr reply;
+        Pkt4Ptr reply;
         handle.getArgument("reply", reply);
         handle.getArgument("reply", reply);
 
 
         // Get the string form of the IP address.
         // Get the string form of the IP address.
@@ -523,13 +573,13 @@ int v4_lease_write_post(CalloutHandle& handle) {
 };
 };
 @endcode
 @endcode
 
 
-@subsection hookBuild Building the Library
+@subsection hooksdgBuild Building the Library
 
 
 Building the code requires building a shareable library.  This requires
 Building the code requires building a shareable library.  This requires
 the the code be compiled as positition-independent code (using the
 the the code be compiled as positition-independent code (using the
-compiler's -fpic switch) and linked as a shared library (with the linker's
+compiler's "-fpic" switch) and linked as a shared library (with the
--shared switch).  The build command also needs to point to the BIND 10 include
+linker's "-shared" switch).  The build command also needs to point to
-directory and link in the appropriate libraries.
+the BIND 10 include directory and link in the appropriate libraries.
 
 
 Assuming that BIND 10 has been installed in the default location, the
 Assuming that BIND 10 has been installed in the default location, the
 command line needed to create the library using the Gnu C++ compiler on a
 command line needed to create the library using the Gnu C++ compiler on a
@@ -542,20 +592,18 @@ g++ -I /usr/include/bind10 -L /usr/lib/bind10 -fpic -shared -o example.so \
 @endcode
 @endcode
 
 
 Notes:
 Notes:
-- the compilation command and switches required may vary depending on
+- The compilation command and switches required may vary depending on
 your operating system and compiler - consult the relevant documentation
 your operating system and compiler - consult the relevant documentation
 for details.
 for details.
-- the values for the -I and -L switches depend on where you have installed
+- The values for the "-I" and "-L" switches depend on where you have
-BIND 10.
+installed BIND 10.
-- the list of libraries that need to be included in the command line
+- The list of libraries that need to be included in the command line
 depends on the functionality used by the hook code and the module to
 depends on the functionality used by the hook code and the module to
 which they are attached (e.g. hook code for DNS will need to link against
 which they are attached (e.g. hook code for DNS will need to link against
 the libb10-dns++ library).  Depending on operating system, you may also need
 the libb10-dns++ library).  Depending on operating system, you may also need
-to explicitly list libraries on which the BIND 10 libraries depend, e.g.
+to explicitly list libraries on which the BIND 10 libraries depend.
-in the command line above, libb10-exceptions depends on log4cplus, so it
-is possible that "-llog4cplus" may need to be appended to the command line.
 
 
-@subsection hookConfiguration Configuring the Hook Library
+@subsection hooksdgConfiguration Configuring the Hook Library
 
 
 The final step is to make the library known to BIND 10.  All BIND 10 modules to
 The final step is to make the library known to BIND 10.  All BIND 10 modules to
 which hooks can be added contain the "hook_library" element, and user
 which hooks can be added contain the "hook_library" element, and user
@@ -565,17 +613,17 @@ To add the example library (assumed to be in /usr/local/lib) to the DHCPv4
 module, the following bindctl commands must be executed:
 module, the following bindctl commands must be executed:
 
 
 @code
 @code
-> config add Dhcp4/hook_library
+> config add Dhcp4/hook_libraries
-> config set Dhcp4/hook_library[0]/name "/usr/local/lib/example.so"
+> config set Dhcp4/hook_libraries[0] "/usr/local/lib/example.so"
 > config commit
 > config commit
 @endcode
 @endcode
 
 
 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.
 
 
-@section hookAdvancedTopics Advanced Topics
+@section hooksdgAdvancedTopics Advanced Topics
 
 
-@subsection hookContextCreateDestroy Context Creation and Destruction
+@subsection hooksdgContextCreateDestroy Context Creation and Destruction
 
 
 As well as the hooks defined by the server, the hooks framework defines
 As well as the hooks defined by the server, the hooks framework defines
 two hooks of its own, "context_create" and "context_destroy".  The first
 two hooks of its own, "context_create" and "context_destroy".  The first
@@ -585,14 +633,14 @@ 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
+As an example, the v4_lease_write example above required that the code
-example above required that the code check for an exception being
+check for an exception being thrown when accessing the "hwaddr" context
-thrown when accessing the "hwaddr" context item in case it was not set.
+item in case it was not set.  An alternative strategy would have been to
-An alternative strategy would have been to provide a callout for the
+provide a callout for the "context_create" hook and set the context item
-"context_create" hook and set the context item "hwaddr" to an empty
+"hwaddr" to an empty string. Instead of needing to handle an exception,
-string. Instead of needing to handle an exception, v4_lease_write would
+v4_lease_write would be guaranteed to get something when looking for
-be guaranteed to get something when looking for the hwaddr item and so
+the hwaddr item and so could write or not write the output depending on
-could write or not write the output depending on the value.
+the value.
 
 
 In most cases, "context_destroy" is not needed as the Hooks system
 In most cases, "context_destroy" is not needed as the Hooks system
 automatically deletes context. An example where it could be required
 automatically deletes context. An example where it could be required
@@ -600,32 +648,143 @@ is where memory has been allocated by a callout during the processing
 of a request and a raw pointer to it stored in the context object. On
 of a request and a raw pointer to it stored in the context object. On
 destruction of the context, that memory will not be automatically
 destruction of the context, that memory will not be automatically
 released. Freeing in the memory in the "context_destroy callout will solve
 released. Freeing in the memory in the "context_destroy callout will solve
-that problem. (Actually, when the context is destroyed, the destructor
+that problem.
+
+Actually, when the context is destroyed, the destructor
 associated with any objects stored in it are run. Rather than point to
 associated with any objects stored in it are run. Rather than point to
 allocated memory with a raw pointer, a better idea would be to point to
 allocated memory with a raw pointer, a better idea would be to point to
 it with a boost "smart" pointer and store that pointer in the context.
 it with a boost "smart" pointer and store that pointer in the context.
 When the context is destroyed, the smart pointer's destructor is run,
 When the context is destroyed, the smart pointer's destructor is run,
-which will automatically delete the pointed-to object.)
+which will automatically delete the pointed-to object.
 
 
+These approaches are illustrated in the following examples.
+Here it is assumed that the hooks library is performing some form of
+security checking on the packet and needs to maintain information in
+a user-specified "SecurityInformation" object. (The details of this
+fictitious object are of no concern here.) The object is created in
+the context_create callout and used in both the pkt4_rcvd and the
+v4_lease_write_post callouts.
 
 
-@subsection hookCalloutRegistration Registering Callouts
+@code
+// Storing information in a "raw" pointer.  Assume that the
 
 
-As briefly mentioned in @ref hookExampleCallouts, the standard is for 
+#include <hooks/hooks.h>
-callouts in the user library to have the same name as the name of the hook
+   :
-to which they are being attached.  This was followed in the tutorial, e.g.
+
-the callout that needed to be attached to the "pkt_rcvd" hook was named
+extern "C" {
-pkt_rcvd.
 
 
-The reason for this standard is that when the library is loaded, the
+// context_create callout - called when the request is created.
-hook framework automatically searches the library for functions with the
+int context_create(CalloutHandle& handle) {
-same names as the server hooks.  When it finds one, it attaches it to
+    // Create the security information and store it in the context
-that hook point.  This simplifies the loading process and bookkeeping
+    // for this packet.
-required to create a library of callouts.
+    SecurityInformation* si = new SecurityInformation();
+    handle.setContext("security_information", si);
+}
+
+// Callouts that use the context
+int pktv_rcvd(CalloutHandle& handle) {
+    // Retrieve the pointer to the SecurityInformation object
+    SecurityInformation si;
+    handle.getContext("security_information", si);
+        :
+        :
+    // Set the security information
+    si->setSomething(...);
+
+    // The pointed-to information has been updated but the pointer has not been
+    // altered, so there is no need to call setContext() again.
+}
+
+int v4_lease_write_post(CalloutHandle& handle) {
+    // Retrieve the pointer to the SecurityInformation object
+    SecurityInformation si;
+    handle.getContext("security_information", si);
+        :
+        :
+    // Retrieve security information
+    bool active = si->getSomething(...);
+        :
+}
+
+// Context destruction.  We need to delete the pointed-to SecurityInformation
+// object because we will lose the pointer to it when the CalloutHandle is
+// destroyed.
+int context_destroy(CalloutHandle& handle) {
+    // Retrieve the pointer to the SecurityInformation object
+    SecurityInformation si;
+    handle.getContext("security_information", si);
+
+    // Delete the pointed-to memory.
+    delete si;
+}
+@endcode
+
+The requirement for the context_destroy callout can be eliminated if
+a Boost shared ptr is used to point to the allocated memory:
+
+@code
+// Storing information in a "raw" pointer.  Assume that the
+
+#include <hooks/hooks.h>
+#include <boost/shared_ptr.hpp>
+   :
+
+extern "C" {
+
+// context_create callout - called when the request is created.
+
+int context_create(CalloutHandle& handle) {
+    // Create the security information and store it in the context for this
+    // packet.
+    boost::shared_ptr<SecurityInformation> si(new SecurityInformation());
+    handle.setContext("security_information", si);
+}
+
+// Other than the data type, a shared pointer has similar semantics to a "raw"
+// pointer.  Only the code from pkt_rcvd is shown here.
+
+int pktv_rcvd(CalloutHandle& handle) {
+    // Retrieve the pointer to the SecurityInformation object
+    boost::shared_ptr<SecurityInformation> si;
+    handle.setContext("security_information", si);
+        :
+        :
+    // Modify the security information
+    si->setSomething(...);
+
+    // The pointed-to information has been updated but the pointer has not
+    // altered, so theree is no need to reset the context.
+}
+
+// No context_destroy callout is needed to delete the allocated
+// SecurityInformation object.  When the CalloutHandle is destroyed, the shared
+// pointer object will be destroyed.  If that is the last shared pointer to the
+// allocated memory, then it too will be deleted.
+@endcode
+
+(Note that a Boost shared pointer - rather than any other Boost smart pointer -
+should be used, as the pointer objects are copied within the hooks framework and
+only shared pointers have the correct behavior for the copy operation.)
+
+
+@subsection hooksdgCalloutRegistration Registering Callouts
+
+As briefly mentioned in @ref hooksdgExampleCallouts, the standard is for
+callouts in the user library to have the same name as the name of the
+hook to which they are being attached.  This convention was followed
+in the tutorial, e.g.  the callout that needed to be attached to the
+"pkt_rcvd" hook was named pkt_rcvd.
+
+The reason for this convention is that when the library is loaded, the
+hook framework automatically searches the library for functions with
+the same names as the server hooks.  When it finds one, it attaches it
+to the appropriate hook point.  This simplifies the loading process and
+bookkeeping required to create a library of callouts.
 
 
 However, the hooks system is flexible in this area: callouts can have
 However, the hooks system is flexible in this area: callouts can have
 non-standard names, and multiple callouts can be registered on a hook.
 non-standard names, and multiple callouts can be registered on a hook.
 
 
-@subsubsection hookLibraryHandle The LibraryHandle Object
+@subsubsection hooksdgLibraryHandle The LibraryHandle Object
 
 
 The way into the part of the hooks framework that allows callout
 The way into the part of the hooks framework that allows callout
 registration is through the LibraryHandle object.  This was briefly
 registration is through the LibraryHandle object.  This was briefly
@@ -642,11 +801,11 @@ The LibraryHandle provides three methods to manipulate callouts:
 
 
 The following sections cover some of the ways in which these can be used.
 The following sections cover some of the ways in which these can be used.
 
 
-@subsubsection hookNonstandardCalloutNames Non-Standard Callout Names
+@subsubsection hooksdgNonstandardCalloutNames Non-Standard Callout Names
 
 
 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 out callouts
+callout names "pkt_rcvd" and "v4_lease_write", 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
@@ -670,7 +829,7 @@ It is possible for a library to contain callouts with both standard and
 non-standard names: ones with standard names will be registered automatically,
 non-standard names: ones with standard names will be registered automatically,
 ones with non-standard names need to be registered manually.
 ones with non-standard names need to be registered manually.
 
 
-@subsubsection hookMultipleCallouts Multiple Callouts on a Hook
+@subsubsection hooksdgMultipleCallouts Multiple Callouts on a Hook
 
 
 The BIND 10 hooks framework allows multiple callouts to be attached to 
 The BIND 10 hooks framework allows multiple callouts to be attached to 
 a hook point.  Although it is likely to be rare for user code to need to
 a hook point.  Although it is likely to be rare for user code to need to
@@ -684,16 +843,16 @@ LibraryHandle::registerCallout multiple times on the same hook, e.g.
     libhandle.registerCallout("pkt_rcvd", write_data);
     libhandle.registerCallout("pkt_rcvd", write_data);
 @endcode
 @endcode
 
 
-The hooks framework will call the callouts in the order they are registered.
+The hooks framework will call the callouts in the order they are
-The same CalloutHandle is passed between them, so any change made to the
+registered.  The same CalloutHandle is passed between them, so any
-CalloutHandle's arguments or per-request context by the first is visible
+change made to the CalloutHandle's arguments, "skip" flag, or per-request
-to the second.
+context by the first is visible to the second.
 
 
-@subsubsection hookDynamicRegistration Dynamic Registration and Reregistration of Callouts
+@subsubsection hooksdgDynamicRegistration Dynamic Registration and Reregistration of Callouts
 
 
 The previous sections have dealt with callouts being registered during
 The previous sections have dealt with callouts being registered during
 the call to "load".  The hooks framework is more flexible than that
 the call to "load".  The hooks framework is more flexible than that
-in that callouts and be registered and deregistered within a callout.
+in that callouts can be registered and deregistered within a callout.
 In fact, a callout is able to register or deregister itself, and a callout
 In fact, a callout is able to register or deregister itself, and a callout
 is able to be registered on a hook multiple times.
 is able to be registered on a hook multiple times.
 
 
@@ -716,7 +875,11 @@ int pkt_rcvd(CalloutHandle& handle) {
 
 
     // Classify it.
     // Classify it.
     if (sum % 4 == 0) {
     if (sum % 4 == 0) {
-        // Interesting, register the callback to log the data.
+        // Store the text form of the hardware address in the context to pass
+        // to the next callout.
+        handle.setContext("hwaddr", hwaddr_ptr->hwaddr_.toText());
+
+        // Register the callback to log the data.
         handle.getLibraryHandle().registerCallout("v4_lease_write", write_data);
         handle.getLibraryHandle().registerCallout("v4_lease_write", write_data);
     }
     }
 
 
@@ -758,7 +921,7 @@ int write_data(CalloutHandle& handle) {
 @endcode
 @endcode
 
 
 Note that the above example used a non-standard name for the callout
 Note that the above example used a non-standard name for the callout
-that wronte the data.  Had the name been a standard one, it would have been
+that wrote the data.  Had the name been a standard one, it would have been
 registered when the library was loaded and called for the first request,
 registered when the library was loaded and called for the first request,
 regardless of whether that was defined as "interesting".  (Although as
 regardless of whether that was defined as "interesting".  (Although as
 callouts with standard names are always registered before "load" gets called,
 callouts with standard names are always registered before "load" gets called,
@@ -768,15 +931,14 @@ callout in the "load" function.)
 
 
 @note Deregistration of a callout on the hook that is currently
 @note Deregistration of a callout on the hook that is currently
 being called only takes effect when the server next calls the hook.
 being called only takes effect when the server next calls the hook.
-To illustrate this, suppose the callouts attached to a hook are A,
+To illustrate this, suppose the callouts attached to a hook are A, B and C
-B and C (in that order), and during execution, A deregisters B and C
+(in that order), and during execution, A deregisters B and C and adds D.
-and adds D.  When callout A returns, B and C will still run.  The next
+When callout A returns, B and C will still run.  The next time the server
-time the server calls the callouts attached to the hook, callouts
+calls the hook's callouts, A and D will run (in that order).
-A and D will run (in that order).
 
 
-@subsection hookMultipleLibraries Multiple User Libraries
+@subsection hooksdgMultipleLibraries Multiple User Libraries
 
 
-As alluded to in the section @ref hookConfiguration, BIND 10 can load
+As alluded to in the section @ref hooksdgConfiguration, BIND 10 can load
 multiple libraries.  The libraries are loaded in the order specified in
 multiple libraries.  The libraries are loaded in the order specified in
 the configuration, and the callouts attached to the hooks in the order
 the configuration, and the callouts attached to the hooks in the order
 presented by the libraries.
 presented by the libraries.
@@ -818,7 +980,7 @@ It is stressed that the context for callouts associated with different
 libraries is entirely separate.  For example, suppose "authorize" sets
 libraries is entirely separate.  For example, suppose "authorize" sets
 the CalloutHandle's context item "foo" to 2 and "logpkt" sets an item of
 the CalloutHandle's context item "foo" to 2 and "logpkt" sets an item of
 the same name to the string "bar".  When "check" accesses the context
 the same name to the string "bar".  When "check" accesses the context
-item "foo", it gets a value of 2: when "validate" accesses an item of
+item "foo", it gets a value of 2; when "validate" accesses an item of
 the same name, it gets the value "bar".
 the same name, it gets the value "bar".
 
 
 It is also stressed that all this context exists only for the life of the
 It is also stressed that all this context exists only for the life of the
@@ -831,7 +993,7 @@ without worrying about the presence of other libraries.  Other libraries
 may be present, but will not affect the context values set by a library's
 may be present, but will not affect the context values set by a library's
 callouts.
 callouts.
 
 
-@subsection hookInterLibraryData Passing Data Between Libraries
+@subsection hooksdgInterLibraryData Passing Data Between Libraries
 
 
 In rare cases, it is possible that one library may want to pass
 In rare cases, it is possible that one library may want to pass
 data to another.  This can be done in a limited way by means of the
 data to another.  This can be done in a limited way by means of the
@@ -850,7 +1012,7 @@ the dollar symbol or percent sign.  In this way there is no danger that
 a name will conflict with any existing or future BIND 10 argument names.
 a name will conflict with any existing or future BIND 10 argument names.
 
 
 
 
-@subsection hookRegisterMultipleLibraries Dynamic Callout Registration and Multiple Libraries
+@subsection hooksdgRegisterMultipleLibraries Dynamic Callout Registration and Multiple Libraries
 
 
 On a particular hook, callouts are called in the order the libraries appear
 On a particular hook, callouts are called in the order the libraries appear
 in the configuration and, within a library, in the order the callouts
 in the configuration and, within a library, in the order the callouts