ProFTPD Developer's Guide: Module Hash Tables

ProFTPD Version 1.2


Table of Contents

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.

Table of Contents



Author: $Author: castaglia $
Last Updated: $Date: 2003/01/02 17:39:34 $


© Copyright 2000-2003 TJ Saunders
All Rights Reserved