]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- code documentation on the module interface.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 6 Feb 2014 13:18:32 +0000 (13:18 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 6 Feb 2014 13:18:32 +0000 (13:18 +0000)
git-svn-id: file:///svn/unbound/trunk@3074 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
util/module.h

index 262efbb93ac01e2ab90666207757ed05a654bf12..53de7e61f3474a984fe7285fcd74f4b709947865 100644 (file)
@@ -1,5 +1,6 @@
 6 February 2014: Wouter
        - sldns has type HIP.
+       - code documentation on the module interface.
 
 5 February 2014: Wouter
        - Fix sldns parse tests on osx.
index 370eb972f155b4faf251ce432e415973246ecede..2b2c91a6044d1dc9ea648c1f44d8d104094afbc1 100644 (file)
  * \file
  *
  * This file contains the interface for DNS handling modules.
+ *
+ * The module interface uses the DNS modules as state machines.  The
+ * state machines are activated in sequence to operate on queries.  Once
+ * they are done, the reply is passed back.  In the usual setup the mesh
+ * is the caller of the state machines and once things are done sends replies
+ * and invokes result callbacks.
+ *
+ * The module provides a number of functions, listed in the module_func_block.
+ * The module is inited and destroyed and memory usage queries, for the
+ * module as a whole, for entire-module state (such as a cache).  And per-query
+ * functions are called, operate to move the state machine and cleanup of
+ * the per-query state.
+ *
+ * Most per-query state should simply be allocated in the query region.
+ * This is destroyed at the end of the query.
+ *
+ * The module environment contains services and information and caches
+ * shared by the modules and the rest of the system.  It also contains
+ * function pointers for module-specific tasks (like sending queries).
+ *
+ * *** Example module calls for a normal query
+ *
+ * In this example, the query does not need recursion, all the other data
+ * can be found in the cache.  This makes the example shorter.
+ *
+ * At the start of the program the iterator module is initialised.
+ * The iterator module sets up its global state, such as donotquery lists
+ * and private address trees.
+ *
+ * A query comes in, and a mesh entry is created for it.  The mesh
+ * starts the resolution process.  The validator module is the first
+ * in the list of modules, and it is started on this new query.  The
+ * operate() function is called.  The validator decides it needs not do
+ * anything yet until there is a result and returns wait_module, that
+ * causes the next module in the list to be started.
+ *
+ * The next module is the iterator.  It is started on the passed query and
+ * decides to perform a lookup.  For this simple example, the delegation
+ * point information is available, and all the iterator wants to do is
+ * send a UDP query.  The iterator uses env.send_query() to send the
+ * query.  Then the iterator suspends (returns from the operate call).
+ *
+ * When the UDP reply comes back (and on errors and timeouts), the
+ * operate function is called for the query, on the iterator module,
+ * with the event that there is a reply.  The iterator decides that this
+ * is enough, the work is done.  It returns the value finished from the
+ * operate call, which causes the previous module to be started.
+ *
+ * The previous module, the validator module, is started with the event
+ * that the iterator module is done.  The validator decides to validate
+ * the query.  Once it is done (which could take recursive lookups, but
+ * in this example no recursive lookups are needed), it returns from the
+ * operate function with finished.
+ *
+ * There is no previous module from the validator module, and the mesh
+ * takes this to mean that the query is finally done.  The mesh invokes
+ * callbacks and sends packets to queriers.
+ *
+ * If other modules had been waiting (recursively) on the answer to this
+ * query, then the mesh will tell them about it.  It calls the inform_super
+ * routine on all the waiting modules, and once that is done it calls all of
+ * them with the operate() call.  During inform_super the query that is done
+ * still exists and information can be copied from it (but the module should
+ * not really re-entry codepoints and services).  During the operate call
+ * the modules can use stored state to continue operation with the results.
+ * (network buffers are used to contain the answer packet during the
+ * inform_super phase, but after that the network buffers will be cleared
+ * of their contents so that other tasks can be performed).
+ *
+ * *** Example module calls for recursion
+ *
+ * A module is called in operate, and it decides that it wants to perform
+ * recursion.  That is, it wants the full state-machine-list to operate on
+ * a different query.  It calls env.attach_sub() to create a new query state.
+ * The routine returns the newly created state, and potentially the module
+ * can edit the module-states for the newly created query (i.e. pass along
+ * some information, like delegation points).  The module then suspends,
+ * returns from the operate routine.
+ *
+ * The mesh meanwhile will have the newly created query (or queries) on
+ * a waiting list, and will call operate() on this query (or queries).
+ * It starts again at the start of the module list for them.  The query
+ * (or queries) continue to operate their state machines, until they are
+ * done.  When they are done the mesh calls inform_super on the module that
+ * wanted the recursion.  After that the mesh calls operate() on the module
+ * that wanted to do the recursion, and during this phase the module could,
+ * for example, decide to create more recursions.
+ *
+ * If the module decides it no longer wants the recursive information
+ * it can call detach_subs.  Those queries will still run to completion,
+ * potentially filling the cache with information.  Inform_super is not
+ * called any more.
+ *
+ * The iterator module will fetch items from the cache, so a recursion
+ * attempt may complete very quickly if the item is in cache.  The calling
+ * module has to wait for completion or eventual timeout.  A recursive query
+ * that times out returns a servfail rcode (servfail is also returned for
+ * other errors during the lookup).
+ *
+ * Results are passed in the qstate, the rcode member is used to pass
+ * errors without requiring memory allocation, so that the code can continue
+ * in out-of-memory conditions.  If the rcode member is 0 (NOERROR) then
+ * the dns_msg entry contains a filled out message.  This message may
+ * also contain an rcode that is nonzero, but in this case additional
+ * information (query, additional) can be passed along.
+ *
+ * The rcode and dns_msg are used to pass the result from the the rightmost
+ * module towards the leftmost modules and then towards the user.
+ *
+ * If you want to avoid recursion-cycles where queries need other queries
+ * that need the first one, use detect_cycle() to see if that will happen.
+ *
  */
 
 #ifndef UTIL_MODULE_H