mirror of
https://github.com/NishiOwO/ircservices5.git
synced 2025-04-21 16:54:38 +00:00
1045 lines
52 KiB
HTML
1045 lines
52 KiB
HTML
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11-strict.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
|
<head>
|
|
<meta http-equiv="Content-Style-Type" content="text/css"/>
|
|
<style type="text/css">@import "style.css";</style>
|
|
<title>IRC Services Technical Reference Manual - 4. Module system</title>
|
|
</head>
|
|
|
|
<body>
|
|
<h1 class="title" id="top">IRC Services Technical Reference Manual</h1>
|
|
|
|
<h2 class="section-title">4. The module system</h2>
|
|
|
|
<p class="section-toc">
|
|
4-1. <a href="#s1">The module concept</a>
|
|
<br/>4-2. <a href="#s2">Structure of a module</a>
|
|
<br/> 4-2-1. <a href="#s2-1">Required symbols</a>
|
|
<br/> 4-2-2. <a href="#s2-2">Utility macros and functions</a>
|
|
<br/> 4-2-3. <a href="#s2-3">Dynamic versus static modules</a>
|
|
<br/>4-3. <a href="#s3">Module management</a>
|
|
<br/> 4-3-1. <a href="#s3-1">Module loading</a>
|
|
<br/> 4-3-2. <a href="#s3-2">Module configuration</a>
|
|
<br/> 4-3-3. <a href="#s3-3">Module unloading</a>
|
|
<br/> 4-3-4. <a href="#s3-4">Searching for a module</a>
|
|
<br/> 4-3-5. <a href="#s3-5">Locking a module in memory</a>
|
|
<br/> 4-3-6. <a href="#s3-6">Global initialization and cleanup</a>
|
|
<br/>4-4. <a href="#s4">External symbols</a>
|
|
<br/> 4-4-1. <a href="#s4-1">Exporting symbols</a>
|
|
<br/> 4-4-2. <a href="#s4-2">Importing symbols</a>
|
|
<br/>4-5. <a href="#s5">Callbacks</a>
|
|
<br/> 4-5-1. <a href="#s5-1">Registering callbacks</a>
|
|
<br/> 4-5-2. <a href="#s5-2">Hooking into callbacks</a>
|
|
<br/> 4-5-3. <a href="#s5-3">Calling callbacks</a>
|
|
<br/>4-6. <a href="#s6">Adding a module to Services</a>
|
|
</p>
|
|
|
|
<p class="backlink"><a href="3.html">Previous section: Communication (socket) handling</a> |
|
|
<a href="index.html">Table of Contents</a> |
|
|
<a href="5.html">Next section: IRC server interface</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s1">4-1. The module concept</h3>
|
|
|
|
<p>The module system was introduced in Services 5.0, partly to allow
|
|
greater flexibility in configuring Services, partly to simplify the process
|
|
of extending Services, and partly to help clarify the boundaries between
|
|
distinct sets of functionality. Rather than merge every conceivable
|
|
function into a single monolithic program, Services was divided into a
|
|
comparatively small core and a number of modules which each implemented
|
|
distinct sets of features. These modules could then be developed
|
|
separately from the core and from each other, without concern for the
|
|
effects of changes in other parts of the program.</p>
|
|
|
|
<p>Aside from providing a cleaner program structure, modules make it
|
|
simpler to implement different variations on a particular feature. A good
|
|
example of this is the protocol modules (discussed in
|
|
<a href="5.html">section 5</a>); rather than a complex set of <tt>#if</tt>
|
|
and <tt>#else</tt> directives to handle differences between IRC server
|
|
types, a separate protocol module can be written for each type of IRC
|
|
server; this results in a certain amount of code duplication for similar
|
|
protocols, but makes the code for each protocol much more maintainable, and
|
|
allows the code for a single protocol to be changed easily without worrying
|
|
that it will break processing for other protocols.</p>
|
|
|
|
<p>Modules also make it easier to add new features to Services, whether as
|
|
part of the Services package or as third-party additions. By connecting to
|
|
the Services core and standard modules through a set of well-defined
|
|
callbacks, no changes need to be made to the main source code when the
|
|
module is updated, and vice versa. The compilation system (see
|
|
<a href="10.html#s3-2">section 10-3-2</a>) also makes it easy for users to
|
|
add modules on their own, by simply "dropping in" the source code for the
|
|
new module; Services will automatically find the module and compile it.</p>
|
|
|
|
<p>Below, <a href="#s2">section 4-2</a> discusses the basic structure of a
|
|
module, along with other background issues; <a href="#s3">section 4-3</a>
|
|
discusses how modules are managed, including the details of module loading,
|
|
configuration, and unloading; <a href="#s4">section 4-4</a> discusses how
|
|
to make symbols available to other modules and use symbols from other
|
|
modules; and <a href="#s5">section 4-5</a> covers callbacks.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s2">4-2. Structure of a module</h3>
|
|
|
|
<p>From the viewpoint of the Services core, a module is a single unit of
|
|
functionality with a known interface. The only direct accesses made to
|
|
module data are to a limited number of functions and variables (as
|
|
described in <a href="#s2-1">section 4-2-1</a> below); all other module
|
|
interactions occur through callbacks, which it is the module's
|
|
responsibility to install as necessary.</p>
|
|
|
|
<p>A typical module, therefore, will use its initialization routine (one of
|
|
the directly-accessed functions) to install callback functions, enabling it
|
|
to respond to events such as messages from the IRC server or connections on
|
|
a socket. After performing any other necessary setup actions, the
|
|
initialization routine returns control to the Services core, which will
|
|
then call the module's callback functions as appropriate. The bulk of a
|
|
module is thus usually contained in these callback functions or their
|
|
helper routines.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s2-1">4-2-1. Required and optional symbols</h4>
|
|
|
|
<p>Modules are required to define two variables, used by the module loader:
|
|
<b><tt>int32 module_version</tt></b>, initialized to the value
|
|
of the macro <tt>MODULE_VERSION_CODE</tt>, and
|
|
<b><tt>Module **_this_module_ptr</tt></b>, a pointer to a variable
|
|
which will receive the module's handle (see <a href="#s3">section 4-3</a>
|
|
for information on module handles). However, both of these variables are
|
|
normally defined by <tt>modules.h</tt> when compiling the module's main
|
|
file (the source file with the same base name as the module object file),
|
|
so ordinarily there is no need to be concerned about these variables.</p>
|
|
|
|
<p>Modules may optionally define two functions, which the module loader
|
|
will call when the module is loaded and unloaded, respectively:</p>
|
|
|
|
<dl>
|
|
<dt><tt>int <b>init_module</b>()</tt></dt>
|
|
<dd>Performs any initialization operations necessary for the module,
|
|
returning nonzero on success, zero on failure. This function is
|
|
called during the module loading process (see
|
|
<a href="#s3-1">section 4-3-1</a>); if it returns failure, the
|
|
module load is aborted.</dd>
|
|
|
|
<dt><tt>int <b>exit_module</b>(int <i>shutdown</i>)</tt></dt>
|
|
<dd>Performs any cleanup operations necessary for the module. If
|
|
<tt><i>shutdown</i></tt> is zero, then the function is being called
|
|
for an unload operation during normal program processing; if
|
|
<tt>exit_module()</tt> returns zero, then the unload is aborted (a
|
|
nonzero return value indicates permission to unload the module).
|
|
If <tt><i>shutdown</i></tt> is nonzero, then the function is being
|
|
called because the program is shutting down; in this case, the
|
|
function must perform all necessary shutdown operations (returning
|
|
zero to cancel the unload is not permitted). <i>Implementation
|
|
note: The <tt><i>shutdown</i></tt> parameter was included primarily
|
|
for the protocol modules, due to some shortcuts taken on the
|
|
assumption that only one protocol module would be used during any
|
|
given execution.</i></dd>
|
|
</dl>
|
|
|
|
<p>Modules may also optionally define
|
|
<b><tt>ConfigDirective module_config[]</tt></b> (this must be an
|
|
array, not a pointer), containing configuration information for the module
|
|
which will be processed by the module loader. The use of this array is
|
|
described in <a href="#s3-2">section 4-3-2</a>.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s2-2">4-2-2. Utility macros and functions</h4>
|
|
|
|
<p>The header file <tt>modules.h</tt>, which must be included by all module
|
|
source files, includes a few macros for convenience in writing modules:</p>
|
|
|
|
<dl>
|
|
<dt><tt><b>THIS_MODULE</b></tt></dt>
|
|
<dd>Evaluates to the module handle for this module. This can be used,
|
|
for example, if a module wants to pass its handle explicitly to
|
|
another module, but it is more commonly used by other macros in
|
|
<tt>modules.h</tt> to automatically pass the module's handle to
|
|
various module-related routines (see below).</dd>
|
|
|
|
<dt><tt><b>MODULE_NAME</b></tt></dt>
|
|
<dd>Evaluates to a string containing the module's name; the value
|
|
should be treated as constant but not literal. (Internally, it is
|
|
simply the result of <tt>get_module_name(THIS_MODULE)</tt>.)</dd>
|
|
|
|
<dt><tt><b>MODULE_VERSION_CODE</b></tt></dt>
|
|
<dd>Evaluates to a numeric code indicating the Services version number.
|
|
The version number consists of four parts: major version number,
|
|
minor version number, release status (alpha, beta/prerelease, or
|
|
final), and release number. These are passed to the macro to
|
|
produce a number indicating the version, where greater values
|
|
indicate later versions. For example:
|
|
<div class="code"> MODULE_VERSION_CODE(5,0,MODULE_VERSION_FINAL,4)
|
|
< MODULE_VERSION_CODE(5,1,MODULE_VERSION_ALPHA,3)
|
|
< MODULE_VERSION_CODE(5,1,MODULE_VERSION_BETA,2)
|
|
< MODULE_VERSION_CODE(5,1,MODULE_VERSION_FINAL,1)</div>
|
|
because version 5.0 is earlier than version 5.1, alpha releases
|
|
are earlier than beta releases, and beta releases are earlier than
|
|
final releases. (These values correspond to the versions 5.0.4,
|
|
5.1a3, 5.1pre2, and 5.1.1 respectively.) While this value is
|
|
primarily used to set the <tt>module_version</tt> required
|
|
variable, as described above, it can also be used in conditional
|
|
compilation when compatibility with multiple versions of Services
|
|
is desired.</dd>
|
|
</dl>
|
|
|
|
<p>In addition, many of the routines described in this section take a
|
|
<tt><i>module</i></tt> or <tt><i>caller</i></tt> parameter, so that the
|
|
module subsystem knows which module is making the call; however, macros are
|
|
used to hide this parameter from the module source code, both to improve
|
|
readability of the code and to avoid potential errors from passing the
|
|
wrong parameter. These functions are:</p>
|
|
<ul>
|
|
<li><tt>add_callback()</tt> (and <tt>add_callback_pri()</tt>)</li>
|
|
<li><tt>call_callback()</tt> (and variations)</li>
|
|
<li><tt>module_log()</tt> (and variations; declared in <tt>log.h</tt>)</li>
|
|
<li><tt>register_callback()</tt></li>
|
|
<li><tt>remove_callback()</tt></li>
|
|
<li><tt>unregister_callback()</tt></li>
|
|
<li><tt>unuse_module()</tt></li>
|
|
<li><tt>use_module()</tt></li>
|
|
</ul>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s2-3">4-2-3. Dynamic versus static modules</h4>
|
|
|
|
<p>It is possible for modules to be compiled either <i>dynamically</i>, so
|
|
that the module is loaded into memory only when used, or <i>statically</i>,
|
|
building all modules into the main executable file. The decision of which
|
|
to use is made by the user via the <tt>configure</tt> script, and cannot be
|
|
controlled by individual modules. In general, modules will behave exactly
|
|
the same whether compiled dynamically or statically; however, it is
|
|
important to be aware of particular behaviors with each method, to avoid
|
|
problems that cause the module to fail when using one method or the other.</p>
|
|
|
|
<p><i>Dynamic linking</i> involves compiling each module into an
|
|
independent loadable object file, which is then loaded into memory as
|
|
needed using the system's <tt>dlopen()</tt> family of functions. (If
|
|
these functions are not available, dynamic modules cannot be used; the
|
|
<tt>configure</tt> script will detect this and select static modules
|
|
automatically.) Any direct references to symbols not defined in the
|
|
module, such as core Services routines, will be marked as unresolved
|
|
references in the object file. As a result, it is possible to compile a
|
|
module that references a nonexistent symbol—for example, accidentally
|
|
typing <tt>str<b>mc</b>p</tt> instead of <tt>str<b>cm</b>p</tt>—and
|
|
the error will not be detected until an attempt is made to load the module.</p>
|
|
|
|
<p><i>Static linking</i>, on the other hand, results in every module being
|
|
linked together with the core code to produce a single executable file.
|
|
This means that every symbol in the Services core—and in other
|
|
modules—will be available for use. Static linking can detect
|
|
references to nonexistent symbols at compile time, unlike dynamic linking,
|
|
but will not generate an error if one module references a symbol from
|
|
another. For example, if a protocol module erroneously references a symbol
|
|
from one of the pseudoclients directly (rather than using the symbol lookup
|
|
method described in <a href="#s4-2">section 4-4-2</a>), the protocol module
|
|
will fail to load when using dynamic linking unless the appropriate
|
|
pseudoclient module is loaded first. (Since the current design of Services
|
|
requires that a protocol module be loaded first, this would result in
|
|
Services not being able to run at all.)</p>
|
|
|
|
<p>When using modules composed of two or more source files that share
|
|
internal-use symbols, static linking can cause spurious errors at link
|
|
time. This is because, even though the symbols are only used internally,
|
|
they are still included in the final object file for the module; thus, if
|
|
two separate modules happen to use the same name for a function or
|
|
variable, the final link will report a "duplicate symbol" error. This is
|
|
an actual problem with the NickServ and ChanServ modules, both of which
|
|
include various internal utility routines in a separate source file, and as
|
|
a result some ChanServ routines have to be renamed (see
|
|
<a href="7.html#s4-1-1-rename">the relevant part of section 7-4-1-1</a>).</p>
|
|
|
|
<p>Additionally, when using static linking, module-global variables will
|
|
always retain their values between a module unload and a subsequent module
|
|
load; when using dynamic linking, it is system-dependent whether the values
|
|
will be retained or reset to their initial values. Thus it is important
|
|
that a module's cleanup routine not only free all resources used by the
|
|
module, but also reset all variables to appropriate values for the next
|
|
call to the initialization routine.</p>
|
|
|
|
<p>For these reasons, it is best to test modules using both dynamic and
|
|
static linking, to ensure that unintended errors are not introduced.</p>
|
|
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s3">4-3. Module management</h3>
|
|
|
|
<p>The module subsystem uses the routines described in this section to
|
|
manage modules, performing loading, configuration and unloading as well as
|
|
checking whether a module is loaded or locking modules into memory.</p>
|
|
|
|
<p>Most module subsystem routines take or return a <i>module handle</i>, a
|
|
value of type <tt>Module *</tt>, to identify a particular module. The
|
|
<tt>Module</tt> type is declared as simply <tt>struct Module_</tt> in
|
|
<tt>modules.h</tt>, rendering the type opaque to callers. Internally,
|
|
<tt>struct Module_</tt> is used to hold information about each loaded
|
|
module, and has the following fields:</p>
|
|
|
|
<dl>
|
|
<dt><tt>Module *<b>next</b>, *<b>prev</b></tt></dt>
|
|
<dd>Used to maintain the linked list of loaded modules.</dd>
|
|
|
|
<dt><tt>char *<b>name</b></tt></dt>
|
|
<dd>The module's name, set to the pathname used to load the module (for
|
|
example, "<tt>nickserv/main</tt>").</dd>
|
|
|
|
<dt><tt>ConfigDirective *<b>modconfig</b></tt></dt>
|
|
<dd>The value of the symbol <tt>module_config</tt> in this module, or
|
|
<tt>NULL</tt> if the <tt>module_config</tt> symbol does not exist.</dd>
|
|
|
|
<dt><tt>Module ***<b>this_module_pptr</b></tt></dt>
|
|
<dd>The value of the symbol <tt>_this_module_ptr</tt> in this module.
|
|
(This is the <i>address</i> of the <tt>_this_module_ptr</tt>
|
|
variable, which itself is a pointer to a variable of type
|
|
<tt>Module *</tt>, so the type of this field is
|
|
<tt>Module ***</tt>.)</dd>
|
|
|
|
<dt><tt>const int32 *<b>module_version_ptr</b></tt></dt>
|
|
<dd>The value of the symbol <tt>module_version</tt> in this module
|
|
(again, the address of the variable, not its value).</dd>
|
|
|
|
<dt><tt>void *<b>dllhandle</b></tt></dt>
|
|
<dd>The handle returned by the system <tt>dlopen()</tt> function. For
|
|
static linking, this instead points to an internal structure with
|
|
the module data.</dd>
|
|
|
|
<dt><tt>CallbackList *<b>callbacks</b></tt>
|
|
<br/><tt>int <b>callbacks_count</b></tt></dt>
|
|
<dd>A variable-length array containing the callbacks registered by this
|
|
module.</dd>
|
|
|
|
<dt><tt>const Module **<b>users</b></tt>
|
|
<br/><tt>int <b>users_count</b></tt></dt>
|
|
<dd>A variable-length array containing handles of modules which have
|
|
called <tt>use_module()</tt> for this module.</dd>
|
|
</dl>
|
|
|
|
<p>Loaded modules are kept as a doubly-linked list, with the list head in
|
|
the file-scope variable <tt>modulelist</tt>. This list always contains at
|
|
least one entry: a dummy entry for the Services core, defined in the
|
|
variable <tt>coremodule</tt>.</p>
|
|
|
|
<p>The module management routines are:</p>
|
|
|
|
<dl>
|
|
<dt><tt>Module *<b>load_module</b>(const char *<i>modulename</i>)</tt></dt>
|
|
<dd>Loads the given module and returns a pointer to its module handle,
|
|
or <tt>NULL</tt> on failure. Described in <a href="#s3-1">section
|
|
4-3-1</a>.</dd>
|
|
|
|
<dt><tt>int <b>unload_module</b>(Module *<i>module</i>)</tt></dt>
|
|
<dd>Unloads the given module. Returns nonzero if the module was
|
|
successfully unloaded, zero if not. Described in
|
|
<a href="#s3-3">section 4-3-3</a>.</dd>
|
|
|
|
<dt><tt>Module *<b>find_module</b>(const char *<i>modulename</i>)</tt></dt>
|
|
<dd>Returns a handle for the module whose name is given by
|
|
<tt><i>modulename</i></tt>. If no such module has been loaded,
|
|
returns <tt>NULL</tt>. Described in <a href="#s3-4">section
|
|
4-3-4</a>.</dd>
|
|
|
|
<dt><tt>void <b>use_module</b>(Module *<i>module</i>)</tt></dt>
|
|
<dd>Marks the given module as "in use", preventing it from being
|
|
unloaded. Described in <a href="#s3-5">section 4-3-5</a>.</dd>
|
|
|
|
<dt><tt>void <b>unuse_module</b>(Module *<i>module</i>)</tt></dt>
|
|
<dd>Releases the lock on a module set by <tt>use_module()</tt>.
|
|
Described in <a href="#s3-5">section 4-3-5</a>.</dd>
|
|
|
|
<dt><tt>void <b>modules_init</b>()</tt></dt>
|
|
<dd>Initializes the module subsystem. Described in
|
|
<a href="#s3-6">section 4-3-6</a>.</dd>
|
|
|
|
<dt><tt>void <b>modules_cleanup</b>()</tt></dt>
|
|
<dd>Shuts down the module subsystem. Described in
|
|
<a href="#s3-6">section 4-3-6</a>.</dd>
|
|
</dl>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s3-1">4-3-1. Module loading</h4>
|
|
|
|
<p>A module can be loaded by calling the <tt>load_module()</tt> routine.
|
|
This routine takes a single parameter, a string giving the name of the
|
|
module to load (such as "nickserv/main"), and returns the handle for the
|
|
newly-loaded module or <tt>NULL</tt> on failure. The routine:</p>
|
|
|
|
<ul>
|
|
<li class="spaced">Calls <tt>internal_load_module()</tt> to load the module
|
|
into memory. This helper routine takes care of performing the
|
|
actual module load (or lookup, when modules are linked statically)
|
|
and filling in the <tt>Module</tt> structure; see below for
|
|
details.</li>
|
|
|
|
<li class="spaced">Links the new <tt>Module</tt> structure into the loaded
|
|
module list.</li>
|
|
|
|
<li class="spaced">Calls the core's <tt>configure()</tt> routine to
|
|
configure module settings; see <a href="#s3-2">section 4-3-2</a>
|
|
for details.</li>
|
|
|
|
<li class="spaced">Calls <tt>internal_init_module()</tt> to perform module
|
|
initialization. This returns nonzero (success) if the module's
|
|
initialization function, <tt>module_init()</tt>, returns success
|
|
(or does not exist).</li>
|
|
|
|
<li class="spaced">Calls the "<tt>load module</tt>" callback, a module
|
|
callback (see <a href="#s5">section 4-5</a>) used to signal that a
|
|
new module has been loaded.</li>
|
|
|
|
<li class="spaced">Finally, performs a check to ensure that a valid
|
|
protocol module is loaded. This is a kludge to ensure that a
|
|
protocol module is loaded before any other modules, since some
|
|
modules alter their initialization behavior depending on the
|
|
protocol in use. See also <a href="5.html#s1">section 5-1</a>.</li>
|
|
</ul>
|
|
|
|
<p>The actual low-level work of loading the module and initializing the
|
|
<tt>Module</tt> structure is handled by the <tt>internal_load_module()</tt>
|
|
helper routine mentioned above. This routine:</p>
|
|
|
|
<ul>
|
|
<li class="spaced">Ensures that the name given (which, when using dynamic
|
|
linking, becomes part of the file pathname) does not contain
|
|
<tt>../</tt>", to avoid attempts by malicious code to access files
|
|
outside the Services data directory.</li>
|
|
|
|
<li class="spaced">Checks whether the module has already been loaded,
|
|
returning an error if so.</li>
|
|
|
|
<li class="spaced">Calls <tt>my_dlopen()</tt> (see below) to actually load
|
|
the module into memory.</li>
|
|
|
|
<li class="spaced">Allocates a new <tt>Module</tt> structure, filling in
|
|
the system module handle and module name.</li>
|
|
|
|
<li class="spaced">Looks up the <tt>_this_module_ptr</tt> symbol in the
|
|
module, returning an error if the symbol is not found, and stores
|
|
the symbol's value in the <tt>this_module_pptr</tt> field of the
|
|
<tt>Module</tt> structure. The variable pointed to by
|
|
<tt>_this_module_ptr</tt> is then set to the module handle,
|
|
allowing the <tt>THIS_MODULE</tt> macro to work.
|
|
|
|
<p>To perform the lookup, <tt>internal_load_module()</tt> first
|
|
calls <tt>check_module_symbol()</tt> to get the symbol value.
|
|
Then, if dynamic linking is in use, the returned value is checked
|
|
the <tt>this_module_pptr</tt> field of each module in the loaded
|
|
module list to see whether the same address has been used for a
|
|
different module. This latter check is required because of a
|
|
problem (on some systems) with the system function
|
|
<tt>dlsym()</tt>, used for looking up symbols when dynamic linking
|
|
is in use: if the requested symbol is not present in the requested
|
|
module but is present in another module, <tt>dlsym()</tt> may
|
|
return the symbol from the other module (see <a href="#s4-2">section
|
|
4-4-2</a> for details).</p>
|
|
|
|
<p>Note that the implementation used with static linking does not
|
|
have this problem, rendering the check unnecessary. In fact,
|
|
attempting to perform the check with static linking can actually
|
|
cause problems on some systems. This is due to constant merging
|
|
performed by linkers, which results in distinct modules
|
|
legitimately having the same value for such a symbol. This has
|
|
been observed with the <tt>module_version</tt> symbol (see below),
|
|
so the check is disabled when static linking is in use.</p></li>
|
|
|
|
<li class="spaced">Looks up the <tt>module_version</tt> symbol in the
|
|
module, returning an error if the symbol is not found or the 32-bit
|
|
value that it points to does not match the value of the
|
|
<tt>MODULE_VERSION_CODE</tt> macro, and stores the symbol value
|
|
(variable address) in the <tt>module_version_ptr</tt> field of the
|
|
<tt>Module</tt> structure.</li>
|
|
|
|
<li class="spaced">Looks up the <tt>module_config</tt> symbol in the
|
|
module, setting the <tt>modconfig</tt> field of the <tt>Module</tt>
|
|
structure to the symbol's value (or <tt>NULL</tt> if the symbol is
|
|
not found).</li>
|
|
|
|
<li class="spaced">Returns the new <tt>Module</tt> structure.</li>
|
|
</ul>
|
|
|
|
<p>The <tt>my_dlopen()</tt> function referred to above is one of four
|
|
wrappers for the system dynamic linking functions: <tt>dlopen()</tt>,
|
|
<tt>dlclose()</tt>, <tt>dlsym()</tt>, and <tt>dlerror()</tt>. When using
|
|
dynamic linking, the wrapper functions essentially just call their system
|
|
counterparts, although <tt>my_dlopen()</tt> generates the actual pathname
|
|
from the module name (prepending the module directory pathname and
|
|
appending the shared object extension "<tt>.so</tt>"), and
|
|
<tt>my_dlsym()</tt> includes workarounds for systems that prepend symbol
|
|
names with underscores and that do not handle <tt>dlsym(NULL,...)</tt>.
|
|
When static linking is in use, the wrapper functions instead search through
|
|
the pregenerated module and symbol lists for the requested module or symbol
|
|
(<tt>dlclose()</tt> does nothing, and <tt>dlerror()</tt> uses a static
|
|
error message variable to hold the value to return). See
|
|
<a href="10.html#s3-2">section 10-3-2</a>) for details on the generation of
|
|
these lists.</p>
|
|
|
|
<p>Note that <tt>load_module()</tt> (and its counterpart,
|
|
<tt>unload_module()</tt>) are only intended to be called by the Services
|
|
core to load modules specified by <tt>LoadModule</tt> directives in
|
|
<tt>ircservices.conf</tt>. Modules should never attempt to load other
|
|
modules on their own, since the user may have intentionally chosen not to
|
|
load certain modules; instead, an error should be generated if a required
|
|
module is not available.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s3-2">4-3-2. Module configuration</h4>
|
|
|
|
<p>Configuration of modules is performed through the same routine,
|
|
<tt>configure()</tt>, that handles the Services core configuration;
|
|
however, a different file is used, <tt>modules.conf</tt> rather than
|
|
<tt>ircservices.conf</tt>, and each module's configuration directives must
|
|
be enclosed by the <tt>Module</tt> and <tt>EndModule</tt> meta-directives.
|
|
(Configuration files and the <tt>configure()</tt> routine are described in
|
|
detail in <a href="2.html#s3-2">section 2-3-2</a>.)</p>
|
|
|
|
<p>Each module can define configuration directives to be parsed by the
|
|
configuration file reader by creating an array of <tt>ConfigDirective</tt>
|
|
entries named <tt>module_config</tt>. <tt>load_module()</tt> will check
|
|
for this symbol and, if found, pass it to <tt>configure()</tt>, as
|
|
described above; thus, the variables corresponding to the configuration
|
|
directives will have already been set when the module's
|
|
<tt>init_module()</tt> function is called. The directives will likewise be
|
|
reprocessed automatically during reconfiguration; however, it may be
|
|
necessary for the module to detect changes in configuration variables (such
|
|
as the nickname of a pseudoclient). For this purpose, the module can hook
|
|
into the "<tt>reconfigure</tt>" callback, which is called once before
|
|
reconfiguration takes place and once after (see
|
|
<a href="c.html#s2">appendix C</a> for details on the callback).</p>
|
|
|
|
<p>All configuration variables will be reset to their initial values when
|
|
the module is unloaded, so the module's <tt>exit_module()</tt> routine does
|
|
not need to take any particular actions with respect to such variables.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s3-3">4-3-3. Module unloading</h4>
|
|
|
|
<p>Loaded modules are unloaded from memory with the <tt>unload_module()</tt>
|
|
routine. This routine, which is implemented in a separate
|
|
<tt>internal_unload_module()</tt> routine to allow passing a
|
|
<tt><i>shutdown</i></tt> parameter to the module's cleanup function,
|
|
performs the reverse of <tt>load_module()</tt>'s operations, returning
|
|
nonzero if the module is successfully unloaded, zero if not. The routine:</p>
|
|
|
|
<ul>
|
|
<li class="spaced">Checks whether the module is in use (locked) by another
|
|
module (see <a href="#s3-5">section 4-3-5</a>), returning failure
|
|
if so.</li>
|
|
|
|
<li class="spaced">Calls the module's <tt>exit_module()</tt> function (if
|
|
it exists) with a parameter of zero, indicating that the unload
|
|
request is explicit rather than part of the program shutdown
|
|
process. The unload fails if the function returns zero
|
|
(failure).</li>
|
|
|
|
<li class="spaced">Removes the module from the global module list, ensuring
|
|
that other modules cannot access it during the unload procedure
|
|
(particularly when the "<tt>unload module</tt>" callback is
|
|
called).</li>
|
|
|
|
<li class="spaced">Checks that the module has not left any other modules in
|
|
a locked state, by calling <tt>use_module()</tt> without a
|
|
corresponding <tt>unuse_module()</tt> (see <a href="#s3-5">section
|
|
4-3-5</a>). If it has, a warning message is logged and the
|
|
offending locks are removed.</li>
|
|
|
|
<li class="spaced">Checks that the module has not left any callback
|
|
functions hooked into other modules' (or the core's) callbacks. If
|
|
it has, a warning message is logged and the offending functions are
|
|
removed.</li>
|
|
|
|
<li class="spaced">Checks that the module has not left any callbacks of its
|
|
own registered. If it has, a warning message is logged and the
|
|
offending callbacks are removed.</li>
|
|
|
|
<li class="spaced">Calls the "<tt>unload module</tt>" callback, passing the
|
|
handle for the module that is being unloaded.</li>
|
|
|
|
<li class="spaced">Calls <tt>deconfigure()</tt> for the module's
|
|
configuration directives (if any), restoring configuration
|
|
variables to their original values.</li>
|
|
|
|
<li class="spaced">Frees resources used by the <tt>Module</tt> structure,
|
|
and calls <tt>my_dlclose()</tt> to unload the module at the system
|
|
level.</li>
|
|
</ul>
|
|
|
|
<p>Aside from <tt>unload_module()</tt>, modules are also unloaded during
|
|
the shutdown process (see <a href="#s3-6">section 4-3-6</a>).</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s3-4">4-3-4. Searching for a module</h4>
|
|
|
|
<p>If one module needs to access another, it can do so with the
|
|
<tt>find_module()</tt> routine. This routine takes a module name as
|
|
parameter, searches through the loaded module list for a module whose name
|
|
exactly matches the given name (case-sensitively), and returns the handle
|
|
for that module (<tt>NULL</tt> if no matching module is found).</p>
|
|
|
|
<p><tt>find_module()</tt> is used most commonly when one module wants to
|
|
use functionality provided by another; for example, the module implementing
|
|
the ChanServ pseudoclient (<tt>chanserv/main</tt>) uses it to retrieve the
|
|
handle for the NickServ module (<tt>nickserv/main</tt>). Note, however,
|
|
that in cases where the module being searched for is not required, it may
|
|
not be present at initialization time; in this case, it is better to hook
|
|
into the core's "<tt>load module</tt>" and "<tt>unload module</tt>"
|
|
callbacks, and only use <tt>find_module()</tt> to check whether the desired
|
|
module has already been loaded when <tt>init_module()</tt> is called. For
|
|
example, the MemoServ module, <tt>memoserv/main</tt>, takes this approach
|
|
with respect to the <tt>chanserv/main</tt> module when deciding whether to
|
|
enable channel memos.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s3-5">4-3-5. Locking a module in memory</h4>
|
|
|
|
<p>If one module requires another in order to function properly, the
|
|
"user" module can request that the "used" module not be unloaded. This is
|
|
accomplished by calling the <tt>use_module()</tt> routine, passing the
|
|
"used" module as the <tt><i>module</i></tt> parameter; this causes the
|
|
specified module to be locked in memory. When the module is no longer
|
|
needed (for example, when the "user" module's <tt>exit_module()</tt>
|
|
routine is being called for unloading), <tt>unuse_module()</tt> unlocks the
|
|
module, allowing it to be unloaded normally.</p>
|
|
|
|
<p>One problem that can arise when locking resources is the case of a
|
|
circular lock dependency: if module A has locked module B, but module B has
|
|
also locked module A, then neither of them can be unloaded until one or the
|
|
other module releases its lock; if the modules only release their locks at
|
|
cleanup time, there would be no way to unload them. In order to prevent
|
|
situations like this, <tt>use_module()</tt> checks for such circular
|
|
dependencies and issues a warning if one is detected (in the form of a
|
|
"BUG" message written to the log file). Naturally, it is also not
|
|
permitted for a module to attempt to lock itself.</p>
|
|
|
|
<p>Note that both of these routines are internally named with a preceding
|
|
underscore (<tt>_use_module()</tt>, <tt>_unuse_module()</tt>) and take a
|
|
second parameter, <tt>const Module *<i>caller</i></tt>, which is used to
|
|
ensure that modules do not leave stale locks around when they are unloaded
|
|
(as described in <a href="#s3-3">section 4-3-3</a>). However, these are
|
|
hidden by macros which automatically pass <tt>THIS_MODULE</tt> as the
|
|
<tt><i>caller</i></tt> parameter.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s3-6">4-3-6. Global initialization and cleanup</h4>
|
|
|
|
<p>Before calling any module-related routines, the module subsystem must be
|
|
initialized by calling <tt>modules_init()</tt>, which obtains the system
|
|
handle for the program itself (when using dynamic linking) and sets up the
|
|
three module subsystem callbacks: "<tt>load module</tt>",
|
|
"<tt>reconfigure</tt>", and "<tt>unload module</tt>".</p>
|
|
|
|
<p>Likewise, the <tt>modules_cleanup()</tt> routine must be called when the
|
|
program shuts down. Aside from removing the callbacks mentioned above,
|
|
<tt>modules_cleanup()</tt> checks that other parts of the Services core
|
|
have removed any callbacks they registered, and calls the internal routine
|
|
<tt>unload_all_modules()</tt> to walk the loaded module list and unload
|
|
each module. In this case, each module's <tt>exit_module()</tt> function
|
|
is called with a nonzero <tt><i>shutdown</i></tt> value, indicating that
|
|
the program is shutting down and the module must clean up after itself.
|
|
(The module will be unloaded regardless of the return value of
|
|
<tt>exit_module()</tt>.)</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s4">4-4. External symbols</h3>
|
|
|
|
<p>While some modules only require Services core functions to operate, most
|
|
interact with other modules. This necessitates a way of accessing
|
|
functions and data provided by outside modules.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s4-1">4-4-1. Exporting symbols</h4>
|
|
|
|
<p>A module can designate certain symbols (functions or variables) to be
|
|
exported, so that other modules can access them as described in the next
|
|
section. This is done using one of three macros, depending on what is
|
|
being exported:</p>
|
|
|
|
<ul>
|
|
<li><b><tt>EXPORT_FUNC(<i>symbol</i>)</tt></b> (for functions)</li>
|
|
<li><b><tt>EXPORT_VAR(<i>type</i>,<i>symbol</i>)</tt></b> (for ordinary
|
|
variables)</li>
|
|
<li><b><tt>EXPORT_ARRAY(<i>eltype</i>,<i>symbol</i>)</tt></b> (for arrays;
|
|
<tt><i>eltype</i></tt> is the type of an element of the array)</li>
|
|
</ul>
|
|
|
|
<p>These macros do not expand to anything themselves, but are used by the
|
|
compilation process (see <a href="10.html#s3-2">section 10-3-2</a>) to
|
|
generate lists of exported symbols when using static linking. Even without
|
|
these macros, the symbols will still (if not declared <tt>static</tt>) be
|
|
recorded in the object file, but since there is no way to access the
|
|
program's symbols when using static linking—and in fact, the symbols
|
|
may have been stripped from the executable file by the user—the
|
|
macros must be used in order for <tt>get_module_symbol()</tt> (see
|
|
<a href="#s4-2">section 4-4-2</a> below) to be able to retrieve the
|
|
symbol's value.</p>
|
|
|
|
<p>Note that the symbols used by the module subsystem
|
|
(<tt>module_version</tt> and so on, as described in <a href="#s2-1">section
|
|
4-2-1</a>) are automatically made available to the module subsystem, and
|
|
need not be explicitly exported. This is done by the <tt>Makefile</tt>
|
|
controlling module compilation, as described in
|
|
<a href="10.html#s3-2">section 10-3-2</a>.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s4-2">4-4-2. Importing symbols</h4>
|
|
|
|
<p>There are two methods of accessing symbols located in other modules: by
|
|
calling <tt>get_module_symbol()</tt> or <tt>check_module_symbol()</tt>, or
|
|
by referencing the symbol directly. Each has its benefits and
|
|
disadvantages.</p>
|
|
|
|
<p><tt>get_module_symbol()</tt> and <tt>check_module_symbol()</tt> allow a
|
|
caller to retrieve the value of a given symbol in a specified (or any)
|
|
module. The functions are declared as follows (note that
|
|
<tt>get_module_symbol()</tt> is declared internally as
|
|
<tt>_get_module_symbol()</tt> and takes a hidden <tt><i>caller</i></tt>
|
|
parameter, but these are hidden by a macro in <tt>modules.h</tt>):</p>
|
|
|
|
<div class="code">void *<b>get_module_symbol</b>(Module *<i>module</i>,
|
|
const char *<i>symname</i>)
|
|
int <b>check_module_symbol</b>(Module *<i>module</i>,
|
|
const char *<i>symname</i>,
|
|
void **<i>resultptr</i>,
|
|
const char **<i>errorptr</i>)</div>
|
|
|
|
<p>Both of these functions retrieve the value of the symbol
|
|
<tt><i>symname</i></tt> in the module <tt><i>module</i></tt>; if
|
|
<tt><i>module</i></tt> is <tt>NULL</tt>, the symbol is searched for in all
|
|
loaded modules (if defined in more than one module, then an arbitrary
|
|
module is used for the lookup). If the symbol is not defined in
|
|
<tt><i>module</i></tt> but is defined in another module, then the result of
|
|
the lookup is defined to be either <tt>NULL</tt> or the value of the symbol
|
|
in the module in which it is defined. This undesirable behavior
|
|
unfortunately cannot be avoided due to identical behavior by (at least) the
|
|
glibc library used on Linux. When using static linking, the functions
|
|
always return <tt>NULL</tt> for this case.</p>
|
|
|
|
<p>The difference between their two functions is how they deal with the
|
|
case of a nonexistent symbol. <tt>get_module_symbol()</tt> is intended for
|
|
use when the symbol is assumed to exist; it returns the symbol's value
|
|
directly if it exist, and logs a warning and returns <tt>NULL</tt>
|
|
otherwise. The danger of using this for symbols that may legitimately not
|
|
exist (other than generating spurious log messages) is that it is possible
|
|
for a symbol to have the value zero (<tt>NULL</tt>), which would be
|
|
indistinguishable from a symbol lookup failure.
|
|
<tt>check_module_symbol()</tt>, on the other hands, takes two extra
|
|
parameters, a pointer to a variable in which the result is to be stored
|
|
on success and a pointer to a variable in which the relevant error message
|
|
is to be stored on failure (either or both of which may be <tt>NULL</tt>),
|
|
and returns nonzero on success, zero on failure. On success, the variable
|
|
pointed to by <tt><i>resultptr</i></tt> is set to the value of the pointer,
|
|
and the variable pointed to by <tt><i>errorptr</i></tt> is left unchanged;
|
|
on failure, the variable pointed to by <tt><i>errorptr</i></tt> is set to a
|
|
human-readable error string, and the variable pointed to by
|
|
<tt><i>resultptr</i></tt> is left unchanged.</p>
|
|
|
|
<p>Note that the "value of the symbol" here is the value in linker terms;
|
|
in other words, when using these functions to access a variable, the value
|
|
of the symbol is the <i>address</i> of the variable, not its value. To
|
|
access the value of the <tt>s_NickServ</tt> string variable in an
|
|
unspecified module, for example, one would write code like:</p>
|
|
|
|
<div class="code">char **p_s_NickServ = get_module_symbol(NULL, "s_NickServ");
|
|
if (p_s_NickServ) {
|
|
notice(*p_s_NickServ, user->nick, "message");
|
|
} else {
|
|
/* Unable to resolve s_NickServ */
|
|
}</div>
|
|
|
|
<p>It is also important to keep in mind that the value of such variables
|
|
may change, or the module containing the variable may be unloaded, at any
|
|
time. Accesses should therefore always be done by looking up the symbol,
|
|
ensuring that the symbol exists, and referencing it through the returned
|
|
pointer. Since this can incur significant overhead, however, another
|
|
option (when the module name is known) is to use the "<tt>load module</tt>"
|
|
and "<tt>unload module</tt>" callbacks to watch for the module to be loaded
|
|
or unloaded; a single <tt>get_module_symbol()</tt> or
|
|
<tt>check_module_symbol()</tt> will then suffice, and the returned variable
|
|
pointer can be saved locally until the module is later unloaded. Many of
|
|
the modules distributed with Services take this approach.</p>
|
|
|
|
<p>The other method of accessing symbols in other modules is to simply
|
|
reference the symbol as if it was an ordinary external variable or
|
|
function. Doing this avoids the overhead of looking up the symbol every
|
|
time it is to be used, or monitoring the relevant module for loads and
|
|
unloads. However, it also requires the module containing the symbol to be
|
|
loaded before the module that uses it; if the modules are not loaded in the
|
|
correct order, <tt>load_module()</tt> will report an "unresolved symbol"
|
|
error. For example, if module A exports a symbol <tt>symA</tt> which
|
|
module B accesses directly, attempting to load module B before module A
|
|
will cause an "unresolved symbol" error for <tt>symA</tt>, without giving
|
|
module B a chance to manually resolve the symbol. As a general rule,
|
|
therefore, it is recommended to avoid direct references to symbols from
|
|
other modules, unless the other module can be reasonably expected to be
|
|
loaded first (for example, many of the pseudoclients' sub-modules access
|
|
symbols from their respective core modules in this fashion).</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s5">4-5. Callbacks</h3>
|
|
|
|
<p><i>Callbacks</i> are a method of allowing modules to signal other
|
|
modules when certain events occur. A module first establishes a callback
|
|
by registering it, giving it a name unique among all callbacks for that
|
|
module (two callbacks in different modules can share the same name). Other
|
|
modules can use that name to refer to the callback, and add functions to be
|
|
called when the callback's event occurs (also referred to as <i>hooking
|
|
into</i> the callback). The module which added the callback can then
|
|
instruct the module subsystem to call each of those functions in turn when
|
|
the requisite event occurs.</p>
|
|
|
|
<p>The Services core also sets up a number of callbacks which can be hooked
|
|
into by modules as necessary. A full list of callbacks available in the
|
|
Services core and standard modules can be found in <a href="c.html">Appendix
|
|
C</a>.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s5-1">4-5-1. Registering callbacks</h4>
|
|
|
|
<p>A module that wishes to register a new callback can do so with the
|
|
<tt>register_callback()</tt> routine (internally
|
|
<tt>_register_callback()</tt>):</p>
|
|
|
|
<div class="code">int <b>register_callback</b>([Module *<i>module</i>,] const char *<i>name</i>)</div>
|
|
|
|
<p>This routine checks to ensure that the given module has not already
|
|
registered a callback of the same name (by calling <tt>find_callback()</tt>,
|
|
an internal helper function that looks for a callback by name in a given
|
|
module), then adds the callback to the module's callback table with an
|
|
empty callback function list. The return value is the ID value assigned to
|
|
the callback (a value used when calling or removing the callback, both for
|
|
efficiency and to eliminate the possibility of mistyping the callback name
|
|
string when referring to it internally); a return value of -1 signals an
|
|
error. Note that the module's <tt>THIS_MODULE</tt> macro (which evaluates
|
|
to <tt>NULL</tt> when called by the core) is automatically passed to the
|
|
function by the <tt>register_callback()</tt> macro in <tt>modules.h</tt>,
|
|
like the <tt><i>caller</i></tt> parameter to <tt>use_module()</tt> and
|
|
<tt>unuse_module()</tt>.</p>
|
|
|
|
<p>When the callback is no longer needed, it can be unregistered by
|
|
calling <tt>unregister_callback()</tt> (internally
|
|
<tt>_unregister_callback()</tt>):</p>
|
|
|
|
<div class="code">int <b>unregister_callback</b>([Module *<i>module</i>,] int <i>id</i>)</div>
|
|
|
|
<p>The routine returns 1 if the callback was found and freed, 0 if the ID
|
|
value given was invalid.</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s5-2">4-5-2. Hooking into callbacks</h4>
|
|
|
|
<p>Once a callback has been registered, other modules can add functions to
|
|
or remove functions from the callback with the <tt>add_callback()</tt>,
|
|
<tt>add_callback_pri()</tt>, and <tt>remove_callback()</tt> functions
|
|
(internally <tt>_add_callback_pri()</tt> and
|
|
<tt>_remove_callback</tt>—<tt>add_callback()</tt> is defined in terms
|
|
of <tt>add_callback_pri()</tt>):</p>
|
|
|
|
<div class="code">int <b>add_callback</b>(Module *<i>module</i>,
|
|
const char *<i>name</i>,
|
|
callback_t <i>callback</i>,
|
|
[const Module *<i>caller</i>])
|
|
int <b>add_callback_pri</b>(Module *<i>module</i>,
|
|
const char *<i>name</i>,
|
|
callback_t <i>callback</i>,
|
|
int <i>priority</i>,
|
|
[const Module *<i>caller</i>])
|
|
int <b>remove_callback</b>(Module *<i>module</i>,
|
|
const char *<i>name</i>,
|
|
callback_t <i>callback</i>,
|
|
[const Module *<i>caller</i>])</div>
|
|
|
|
<p>The type of a callback function is defined as <tt>callback_t</tt>:</p>
|
|
|
|
<div class="code">typedef int (*callback_t)()</div>
|
|
|
|
<p>The number and type of parameters passed to the function depends on the
|
|
particular callback, and thus the <tt>callback_t</tt> type is not a true
|
|
prototype. The <tt>int</tt> return value is used both to return a result
|
|
from the callback function itself and to control execution of the list of
|
|
callback functions, with a nonzero value terminating execution, as
|
|
described in <a href="#s5-3">section 4-5-3</a> below.</p>
|
|
|
|
<p><tt>add_callback()</tt> and <tt>add_callback_pri()</tt> add the given
|
|
function to the selected callback, returning nonzero on success, zero on
|
|
error. In the case of <tt>add_callback_pri()</tt>, the callback function
|
|
can be given a numeric priority; callback functions with higher priority
|
|
values are called before those with lower values, and callback functions
|
|
with the same priority value are called in the same order they were added.
|
|
<tt>add_callback()</tt> is equivalent to <tt>add_callback_pri()</tt> with a
|
|
priority of zero, and in fact is implemented as a macro that does exactly
|
|
that. <i>Implementation note: Priorities were added to allow the
|
|
<tt>operserv/sessions</tt> module to have its "<tt>user check</tt>"
|
|
callback function, which increments the user count for a session if the
|
|
user passes the session check, called last. This is arguably a bad design
|
|
decision, as it would be better (if less efficient) to move the session
|
|
count incrementing to the "<tt>user create</tt>" callback, and the current
|
|
method cannot stop another module from adding a callback function at an
|
|
even lower priority and causing the session count to "leak" if the
|
|
lower-priority function rejects the user.</i></p>
|
|
|
|
<p><tt>remove_callback()</tt> removes the given function from the selected
|
|
callback, returning nonzero if the function was found and successfully
|
|
removed, else zero. <tt>remove_callback()</tt> deliberately does not
|
|
generate a log warning when used with a callback function that has not been
|
|
added, in order to simplify modules' cleanup routines (so that they can
|
|
call <tt>remove_callback()</tt> for all callbacks that may have potentially
|
|
been added without having to keep track of which ones were in fact
|
|
added).</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
|
|
<h4 class="subsubsection-title" id="s5-3">4-5-3. Calling callbacks</h4>
|
|
|
|
<p>A module can instruct the module subsystem to call all callback
|
|
functions for a particular callback with the <tt>call_callback()</tt> set
|
|
of functions (actually macros, with the implementing function internally
|
|
named <tt>_call_callback_5()</tt>):</p>
|
|
|
|
<div class="code">int <b>call_callback</b>([Module *<i>module</i>,] int <i>id</i>)
|
|
int <b>call_callback_1</b>([Module *<i>module</i>,] int <i>id</i>,
|
|
void *<i>arg1</i>)
|
|
int <b>call_callback_2</b>([Module *<i>module</i>,] int <i>id</i>,
|
|
void *<i>arg1</i>, void *<i>arg2</i>)
|
|
int <b>call_callback_3</b>([Module *<i>module</i>,] int <i>id</i>,
|
|
void *<i>arg1</i>, void *<i>arg2</i>, void *<i>arg3</i>)
|
|
int <b>call_callback_4</b>([Module *<i>module</i>,] int <i>id</i>,
|
|
void *<i>arg1</i>, void *<i>arg2</i>, void *<i>arg3</i>,
|
|
void *<i>arg4</i>)
|
|
int <b>call_callback_5</b>([Module *<i>module</i>,] int <i>id</i>,
|
|
void *<i>arg1</i>, void *<i>arg2</i>, void *<i>arg3</i>,
|
|
void *<i>arg4</i>, void *<i>arg5</i>)</div>
|
|
|
|
<p>As with <tt>register_module()</tt> and <tt>unregister_module()</tt>,
|
|
the module handle of the calling module is automatically passed in the
|
|
hidden <tt><i>module</i></tt> parameter.</p>
|
|
|
|
<p>These functions all call the selected callback (specified by callback
|
|
ID value, as returned from <tt>register_callback()</tt>), and differ only
|
|
in the number of parameters passed to the callback. The parameters
|
|
<tt><i>arg1</i></tt> through <tt><i>arg5</i></tt> are passed to the
|
|
callback functions unchanged; the parameters are declared as the (more or
|
|
less) generic type <tt>void *</tt>, but may be of any type, as the
|
|
<tt>call_callback()</tt> macros take care of converting the parameters to
|
|
<tt>void *</tt> to avoid type conversion warnings (but see
|
|
<a href="11.html#s1">section 11-1</a> for problems with this method of
|
|
passing parameters). It is the callback function's responsibility to
|
|
ensure that it is declared with the correct parameter list.</p>
|
|
|
|
<p>After checking the validity of the module and callback ID parameters,
|
|
<tt>call_callback()</tt> calls each callback function that has been added
|
|
to the callback, in priority and time order (see <a href="#s5-2">section
|
|
4-5-2</a> about calling order). If any callback function returns a nonzero
|
|
value, <tt>call_callback()</tt> stops immediately and returns that value,
|
|
skipping the rest of the callback functions; if all callback functions
|
|
return zero (or if there are no callback functions for the given callback),
|
|
zero is returned. (-1 is returned if the callback ID is invalid.) Thus,
|
|
callbacks should be designed so that a return value of zero from a callback
|
|
function means "continue processing" and a nonzero value means "stop
|
|
processing or take some other action".</p>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<h3 class="subsection-title" id="s6">4-6. Adding a module to Services</h3>
|
|
|
|
<p>Adding a new module to Services consists generally of the following
|
|
steps:</p>
|
|
|
|
<ul>
|
|
<li>Create a subdirectory for the module under the <tt>modules</tt>
|
|
directory.</li>
|
|
<li>Write the module itself.</li>
|
|
<li>Create a Makefile for the module (see <a href="10.html#s3-2">section
|
|
10-3-2</a>).</li>
|
|
</ul>
|
|
|
|
<p>For submodules of pre-existing modules, like new NickServ or ChanServ
|
|
features, the module can naturally go in the appropriate pre-existing
|
|
directory instead, with the corresponding Makefile modified to compile the
|
|
new module.</p>
|
|
|
|
<p>For modules intended to be distributed separately from Services itself,
|
|
it is sufficient to distribute the subdirectory containing the module
|
|
source code and Makefile; by copying that directory into the <tt>modules</tt>
|
|
directory of a fresh Services distribution, the module Makefile will
|
|
automatically detect it and compile the module without any further
|
|
intervention on the part of the user. (See also
|
|
<a href="../3.html#10">section 3-10 of th user's manual</a>.)</p>
|
|
|
|
<p>In addition to this section, sections <a href="2.html#s2">2-2</a>
|
|
(concerning utility functions) and <a href="2.html#s4">2-4</a> (concerning
|
|
logging), along with <a href="c.html">Appendix C</a> (containing a list of
|
|
core and standard module callbacks), provide useful information for module
|
|
development. Additionally, the following sections of this manual can be
|
|
helpful in writing different types of modules:</p>
|
|
|
|
<ul>
|
|
<li><b>Protocol modules:</b> sections <a href="5.html">5</a> and
|
|
<a href="2.html#s5">2-5</a>, and particularly section
|
|
<a href="5.html#s6-14">5-6-14</a>, which discusses the Unreal
|
|
protocol module in detail.</li>
|
|
<li><b>Database modules:</b> sections <a href="6.html">6</a> and
|
|
<a href="2.html#s9-2">2-9-2</a>.</li>
|
|
<li><b>Pseudoclient modules:</b> sections <a href="7.html">7</a>,
|
|
<a href="2.html#s6">2-6</a>, <a href="2.html#s8">2-8</a>,
|
|
<a href="2.html#s10">2-10</a>, and <a href="6.html#s2">6-2</a>.</li>
|
|
</ul>
|
|
|
|
<p class="backlink"><a href="#top">Back to top</a></p>
|
|
|
|
<!------------------------------------------------------------------------>
|
|
<hr/>
|
|
|
|
<p class="backlink"><a href="3.html">Previous section: Communication (socket) handling</a> |
|
|
<a href="index.html">Table of Contents</a> |
|
|
<a href="5.html">Next section: IRC server interface</a></p>
|
|
|
|
</body>
|
|
</html>
|