Module Hash Tables
When ProFTPD is compiled and the various modules read in, several different
hash tables are constructed: an authentication function hash, a configuration
directive hash, and a command hash. The keys to these hashes are the
the authentication function names, or the configuration directive names, or
the command names. So, whenever multiple modules declare an interest in
handling a key that is already in the relevant hash, there is a collision.
These collisions are handled simply, via a linked list of module "symbols"
that is created for these colliding keys. When a key is looked up, it is
then a simple matter of walking the list of symbols.
This is where module load order comes into play. First in, last out, right? This means that the last module loaded is inserted at the beginning of one of these collision lists, thus being first when called, and having the highest precedence.
Now, the mod_struc
structure defines an int priority
field, for "internal use" -- but nothing is at present using this
field. I suspect that it was being surreptitiously introduced into the code in
order to allow for the determination of module load order via configuration
directives or at run-time, rather than at compile or configure-time.
Well, that's not quite true. There appears to be only one function
that uses that priority
field -- and maybe it is the only key
function that matters:
src/modules.c
's
_compare_sym()
function.
static int _compare_sym(struct symbol_hash *s1, struct symbol_hash *s2) { int ret; ret = strcmp(s1->sym_name,s2->sym_name); /* higher priority modules must go BEFORE lower priority in * the hash tables. */ if(!ret) { if(s1->sym_module->priority > s2->sym_module->priority) ret = -1; else if(s1->sym_module->priority < s2->sym_module->priority) ret = 1; } return ret; }See symbol_hash for the contained fields.
However, this _compare_sym()
function is never called.
Interesting. Where would one call this function, and what would a
configuration directive to take advantage of this look like? Hmmm...
When starting up, one of the preparatory functions called is
src/modules.c
's
init_modules()
, excerpted here:
int init_modules() { int i,numconf = 0,numcmd = 0,numauth = 0; module *m; conftable *c,*wrk; cmdtable *cmd,*cmdwrk; authtable *auth,*authwrk; bzero(symtable,sizeof(symtable)); installed_modules = xaset_create(permanent_pool,NULL); for(i = 0; static_modules[i]; i++) { m = static_modules[i]; m->priority = i; ...
You can see here that this function sets the priority
member of
the module structure. Following the function calls from
init_modules()
is quite instructive. The list of modules is
iterated through, and the number of configuration directive handlers, command
handlers, and authentication handlers counted. An array is then allocated for
each of these types of handlers, and the function pointers hashed and inserted.
These arrays are static to src/modules.c
, which is fine, since the
dispatching code is also part of that file.
In the future 1.3.x releases, I expect that the priority
field
and the _compare_sym()
function will be hooked together so that
ProFTPD administrators can have a little finer control over the order in
which module handlers are called. But this is just pure speculation at this
point.