- Code cleanup
authorMatthew Mondor <mmondor@pulsar-zone.net>
Sat, 11 Oct 2003 11:20:23 +0000 (11:20 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Sat, 11 Oct 2003 11:20:23 +0000 (11:20 +0000)
- Now uses mmhash(3) for the command parser for speed improvement

mmsoftware/mmmail/ChangeLog
mmsoftware/mmmail/src/mmpop3d/mmpop3d.c
mmsoftware/mmmail/src/mmpop3d/mmpop3d.h
mmsoftware/mmmail/src/mmsmtpd/mmsmtpd.c
mmsoftware/mmmail/src/mmsmtpd/mmsmtpd.h

index cabf1cc..688cdbc 100644 (file)
@@ -1,4 +1,4 @@
-$Id: ChangeLog,v 1.30 2003/10/09 16:29:43 mmondor Exp $
+$Id: ChangeLog,v 1.31 2003/10/11 11:20:11 mmondor Exp $
 
 
 
@@ -22,6 +22,12 @@ By     : Matthew Mondor
     one of my first C programs many years ago :) The configuration files
     format is now more flexible as well, although the current files will
     parse properly without modifications still.
+  - mmhash(3) is now used by the command parser for more speed. Any such
+    speed improvement is always welcome when using userspace threads.
+* Bug fixes
+  - mmstatd(8) and the mmstat(3) library had a bugfix.
+* Other
+  - A minor code cleanup was done
 
 
 
index c87ca0e..a88bd9b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmpop3d.c,v 1.26 2003/10/09 16:29:46 mmondor Exp $ */
+/* $Id: mmpop3d.c,v 1.27 2003/10/11 11:20:16 mmondor Exp $ */
 
 /*
  * Copyright (C) 2000-2003, Matthew Mondor
@@ -63,6 +63,8 @@
 #include <mmreadcfg.h>
 #include <mmfd.h>
 #include <mmlist.h>
+#include <mmpool.h>
+#include <mmhash.h>
 #include <mmserver.h>
 #include <mmsql.h>
 #include <mmlog.h>
@@ -77,7 +79,7 @@
 
 MMCOPYRIGHT("@(#) Copyright (c) 2002-2003\n\
 \tMatthew Mondor. All rights reserved.\n");
-MMRCSID("$Id: mmpop3d.c,v 1.26 2003/10/09 16:29:46 mmondor Exp $");
+MMRCSID("$Id: mmpop3d.c,v 1.27 2003/10/11 11:20:16 mmondor Exp $");
 
 
 
@@ -87,21 +89,21 @@ static CONFIG CONF;
 
 /* Here consists of the commands we support */
 static command commands[] = {
-    /* Hash, LogLevel, Name */
-    {0, 3, "NOOP"},
-    {0, 3, "RSET"},
-    {0, 3, "QUIT"},
-    {0, 2, "USER"},
-    {0, 4, "PASS"},
-    {0, 3, "STAT"},
-    {0, 3, "LIST"},
-    {0, 3, "RETR"},
-    {0, 3, "DELE"},
-    {0, 3, "LAST"},
-    {0, 3, "TOP"},
-    {0, 3, "PAGE"},
-    {0, 5, "BEER"},
-    {0, 0, NULL}
+    /* LogLevel, Name */
+    {3, "NOOP"},
+    {3, "RSET"},
+    {3, "QUIT"},
+    {2, "USER"},
+    {4, "PASS"},
+    {3, "STAT"},
+    {3, "LIST"},
+    {3, "RETR"},
+    {3, "DELE"},
+    {3, "LAST"},
+    {3, "TOP"},
+    {3, "PAGE"},
+    {5, "BEER"},
+    {0, NULL}
 };
 
 /* Now here consists of our auth state functions */
@@ -148,12 +150,16 @@ static const struct state states[] = {
 static int LOGLEVEL;
 
 /* Pool used to allocate clientenv nodes */
-static pth_mutex_t cpool_lock;
-static pool_t cpool;
+static pth_mutex_t clenv_lock;
+static pool_t clenv_pool;
 
 /* Pool used to optimize creating/destroying mmfd mutexes */
 static pth_mutex_t mutexes_lock;
-static pool_t pmutexes;
+static pool_t mutexes_pool;
+
+/* Used for fast command lookup */
+static pool_t command_pool;
+static hashtable_t command_table;
 
 /* Global bandwidth shaping fdb context */
 static fdbcontext fdbc;
@@ -362,23 +368,23 @@ main(int argc, char **argv)
     async_init(afuncs, CONF.ASYNC_PROCESSES, uid, gids, ngids);
 
     /* Things which shouldn't be part of the async pool processes */
-    packcommands(commands, 3);
     pth_init();
     async_init_pth();
-    pth_mutex_init(&cpool_lock);
+    pth_mutex_init(&clenv_lock);
     pth_mutex_init(&mutexes_lock);
 
     /* Allocate necessary pools */
     /* Client nodes */
-    pool_init(&cpool, malloc, free, sizeof(clientenv),
+    pool_init(&clenv_pool, malloc, free, sizeof(clientenv),
            (65536 * CONF.ALLOC_BUFFERS) / sizeof(clientenv), 0, 0);
     /* Mutexes pool for mmfd */
-    pool_init(&pmutexes, malloc, free, sizeof(struct mutexnode),
+    pool_init(&mutexes_pool, malloc, free, sizeof(struct mutexnode),
            (16384 * CONF.ALLOC_BUFFERS) / sizeof(struct mutexnode), 0, 0);
     /* mmstr nodes */
     strlist = mmstrinit(malloc, free, 16384 * CONF.ALLOC_BUFFERS);
 
-    if (POOL_VALID(&cpool) && POOL_VALID(&pmutexes) && strlist) {
+    if (hash_commands(commands, 3) && POOL_VALID(&clenv_pool) &&
+           POOL_VALID(&mutexes_pool) && strlist) {
        fdbcinit(&gfdf, &fdbc, CONF.GBANDWIDTH_IN * 1024,
                CONF.GBANDWIDTH_OUT * 1024);
        mmsql_init(&mmsqlfuncs);
@@ -398,9 +404,16 @@ main(int argc, char **argv)
        syslog(LOG_NOTICE, "* Out of memory");
     }
 
-    if (strlist) mmstrexit();
-    if (POOL_VALID(&pmutexes)) pool_destroy(&pmutexes);
-    if (POOL_VALID(&cpool)) pool_destroy(&cpool);
+    if (strlist)
+       mmstrexit();
+    if (HASHTABLE_VALID(&command_table))
+       hashtable_destroy(&command_table, FALSE);
+    if (POOL_VALID(&command_pool))
+       pool_destroy(&command_pool);
+    if (POOL_VALID(&mutexes_pool))
+       pool_destroy(&mutexes_pool);
+    if (POOL_VALID(&clenv_pool))
+       pool_destroy(&clenv_pool);
 
     fdbcdestroy(&fdbc);
     kill(0, SIGTERM);
@@ -857,9 +870,9 @@ alloc_clientenv(void)
 {
     clientenv *clenv;
 
-    pth_mutex_acquire(&cpool_lock, FALSE, NULL);
-    clenv = (clientenv *)pool_alloc(&cpool, TRUE);
-    pth_mutex_release(&cpool_lock);
+    pth_mutex_acquire(&clenv_lock, FALSE, NULL);
+    clenv = (clientenv *)pool_alloc(&clenv_pool, TRUE);
+    pth_mutex_release(&clenv_lock);
 
     if (clenv) {
        mmstat_init(&clenv->pstat, TRUE, FALSE);
@@ -908,22 +921,67 @@ free_clientenv(clientenv *clenv)
     if (clenv->mailbox) mmstrfree(clenv->mailbox);
     if (clenv->index) free(clenv->index);
 
-    pth_mutex_acquire(&cpool_lock, FALSE, NULL);
+    pth_mutex_acquire(&clenv_lock, FALSE, NULL);
     pool_free((pnode_t *)clenv);
-    pth_mutex_release(&cpool_lock);
+    pth_mutex_release(&clenv_lock);
 
     return (NULL);
 }
 
 
-/* Used to initialize command table hashes */
-static void
-packcommands(struct command *cmd, size_t min)
-{
-    while (cmd->name) {
-       cmd->hash = mm_strpack32(cmd->name, min);
-       cmd++;
+/* Used to initialize command hash table */
+static bool
+hash_commands(struct command *cmd, size_t min)
+{   
+    int i;
+
+    /* We do not care for any unfreed resources, the program will free them
+     * and exit if we return FALSE.
+     */
+    if (!pool_init(&command_pool, malloc, free, sizeof(struct commandnode),
+               64, 1, 0) || !hashtable_init(&command_table, 64, 1, malloc,
+                   free, commandnode_keycmp, commandnode_keyhash, TRUE))
+       return FALSE;
+
+    for (i = 0; cmd->name != NULL; cmd++, i++) {
+       struct commandnode *nod;
+       if ((nod = (struct commandnode *)pool_alloc(&command_pool, FALSE))
+               == NULL)
+           return FALSE;
+       if ((nod->hash = mm_strpack32(cmd->name, min)) == 0)
+           return FALSE;
+       nod->command = cmd;
+       nod->index = i;
+       if (!hashtable_link(&command_table, (hashnode_t *)nod, &nod->hash,
+                   sizeof(u_int32_t))) {
+           DPRINTF("hash_commands", "hashtable_link(%s)", cmd->name);
+           return FALSE;
+       }
     }
+
+    return TRUE;
+}
+
+
+/* A quick hashtable_hash() replacement which already deals with unique
+ * 32-bit values
+ */
+/* ARGSUSED */
+static u_int32_t
+commandnode_keyhash(const void *data, size_t len)
+{   
+    return *((u_int32_t *)data);
+}
+
+
+/* A quick memcmp() replacement which only needs to compare two 32-bit values
+ */
+/* ARGSUSED */
+static int
+commandnode_keycmp(const void *src, const void *dst, size_t len)
+{
+    return *((u_int32_t *)src) - *((u_int32_t *)dst);
 }
 
 
@@ -1441,9 +1499,8 @@ handleclient(unsigned long id, int fd, clientlistnode *clientlnode,
 
            /* Main state switcher loop */
            for (;;) {
-               register int i = 0;
-               register int32_t chash;
-               register bool valid;
+               register struct commandnode *nod;
+               u_int32_t chash;
 
                fdbflushw(fdb);
                if ((len = fdbgets(fdb, buffer, 1000, FALSE)) > -1) {
@@ -1455,23 +1512,17 @@ handleclient(unsigned long id, int fd, clientlistnode *clientlnode,
                        break;
                    }
                    /* Verify if command matches an existing one */
-                   valid = FALSE;
-                   if ((chash = mm_strpack32(buffer, 3)) != -1) {
-                       for (i = 0; commands[i].name; i++) {
-                           if (commands[i].hash == chash) {
-                               valid = TRUE;
-                               break;
-                           }
-                       }
-                   }
-
-                   if (valid) {
+                   nod = NULL;
+                   if ((chash = mm_strpack32(buffer, 3)) != 0)
+                       nod = (struct commandnode *)hashtable_lookup(
+                               &command_table, &chash, sizeof(u_int32_t));
+                   if (nod != NULL) {
                        register int (*func)(clientenv *);
 
-                       mmsyslog(commands[i].loglevel, LOGLEVEL,
+                       mmsyslog(nod->command->loglevel, LOGLEVEL,
                                "%08X < %s", id, buffer);
 
-                       if ((func = states[state].functions[i])) {
+                       if ((func = states[state].functions[nod->index])) {
 
                            /* Valid command, process it in current state */
                            nstate = func(clenv);
@@ -1598,7 +1649,7 @@ _pth_mutex_create(void)
     struct mutexnode *mnod;
 
     pth_mutex_acquire(&mutexes_lock, FALSE, NULL);
-    mnod = (struct mutexnode *)pool_alloc(&pmutexes, FALSE);
+    mnod = (struct mutexnode *)pool_alloc(&mutexes_pool, FALSE);
     pth_mutex_release(&mutexes_lock);
 
     if (mnod)
index 133daca..8c94c92 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmpop3d.h,v 1.10 2003/08/13 11:20:39 mmondor Exp $ */
+/* $Id: mmpop3d.h,v 1.11 2003/10/11 11:20:16 mmondor Exp $ */
 
 /*
  * Copyright (C) 2000-2003, Matthew Mondor
@@ -47,6 +47,7 @@
 #include <pth.h>
 
 #include <mmtypes.h>
+#include <mmhash.h>
 #include <mmpool.h>
 #include <mmserver.h>
 #include <mmlist.h>
@@ -140,11 +141,18 @@ typedef struct state {
 
 /* A command of a state */
 typedef struct command {
-    int32_t hash;
     int loglevel;
     char *name;
 } command;
 
+/* Used for fast command lookup */
+struct commandnode {
+    hashnode_t node;
+    u_int32_t hash;
+    int index;
+    struct command *command;
+};
+
 /* Used by our asynchoneous functions */
 struct async_checkpw_msg {
     struct async_msg msg;
@@ -180,7 +188,9 @@ static int main_last(clientenv *);
 static int main_top(clientenv *);
 static int main_page(clientenv *);
 
-static void packcommands(struct command *, size_t);
+static bool hash_commands(struct command *, size_t);
+static u_int32_t commandnode_keyhash(const void *, size_t);
+static int commandnode_keycmp(const void *, const void *, size_t);
 static bool do_buildindex(clientenv *);
 static bool do_retreive(fdbuf *, msgnode *);
 static bool do_top(fdbuf *, msgnode *, long);
index 6b37aeb..5e76f79 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmsmtpd.c,v 1.36 2003/10/09 16:29:48 mmondor Exp $ */
+/* $Id: mmsmtpd.c,v 1.37 2003/10/11 11:20:23 mmondor Exp $ */
 
 /*
  * Copyright (C) 2001-2003, Matthew Mondor
@@ -77,7 +77,7 @@
 
 MMCOPYRIGHT("@(#) Copyright (c) 2002-2003\n\
 \tMatthew Mondor. All rights reserved.\n");
-MMRCSID("$Id: mmsmtpd.c,v 1.36 2003/10/09 16:29:48 mmondor Exp $");
+MMRCSID("$Id: mmsmtpd.c,v 1.37 2003/10/11 11:20:23 mmondor Exp $");
 
 
 
@@ -88,17 +88,17 @@ static CONFIG CONF;
 
 /* Here consists of the commands we support */
 static command commands[] = {
-    /* Hash, LogLevel, Cmd, Args, Description (NULL=unimplemented) */
-    {0, 3, "NOOP", "NOOP", "Does nothing"},
-    {0, 3, "RSET", "RSET", "Resets system to initial state"},
-    {0, 3, "QUIT", "QUIT", "Disconnects, exits"},
-    {0, 3, "HELP", "HELP [<topic>]", "Gives HELP information"},
-    {0, 2, "HELO", "HELO <hostname>", "Permits to authenticate"},
-    {0, 2, "MAIL", "MAIL FROM:<sender>", "Specifies sender of message"},
-    {0, 2, "RCPT", "RCPT TO:<recipient>", "Specifies a recipient"},
-    {0, 3, "DATA", "DATA", "Accepts the message ending with ."},
-    {0, 4, "BEER", NULL, NULL},
-    {0, 0, NULL, NULL, NULL}
+    /* LogLevel, Cmd, Args, Description (NULL=unimplemented) */
+    {3, "NOOP", "NOOP", "Does nothing"},
+    {3, "RSET", "RSET", "Resets system to initial state"},
+    {3, "QUIT", "QUIT", "Disconnects, exits"},
+    {3, "HELP", "HELP [<topic>]", "Gives HELP information"},
+    {2, "HELO", "HELO <hostname>", "Permits to authenticate"},
+    {2, "MAIL", "MAIL FROM:<sender>", "Specifies sender of message"},
+    {2, "RCPT", "RCPT TO:<recipient>", "Specifies a recipient"},
+    {3, "DATA", "DATA", "Accepts the message ending with ."},
+    {4, "BEER", NULL, NULL},
+    {0, NULL, NULL, NULL}
 };
 
 /* The system is simple enough that only one state is required, each command
@@ -125,21 +125,25 @@ static const struct state states[] = {
 static int LOGLEVEL;
 
 /* Used for clenv allocation buffering */
-static pool_t cpool;
-static pth_mutex_t cpool_lock;
+static pool_t clenv_pool;
+static pth_mutex_t clenv_lock;
 
 /* Used for the flood protection cache */
-static pool_t mpool;
-static hashtable_t mtable;
-static pth_mutex_t mtable_lock;
+static pool_t hosts_pool;
+static hashtable_t hosts_table;
+static pth_mutex_t hosts_lock;
 
 /* Used for rcpt allocation buffering */
-static pool_t rpool;
-static pth_mutex_t rpool_lock;
+static pool_t rcpt_pool;
+static pth_mutex_t rcpt_lock;
 
-/* Pool used to optimize creatiing/destroying mmfd mutexes */
+/* Pool used to optimize creating/destroying mmfd mutexes */
 static pth_mutex_t mutexes_lock;
-static pool_t pmutexes;
+static pool_t mutexes_pool;
+
+/* For fast command lookup */
+static pool_t command_pool;
+static hashtable_t command_table;
 
 /* Global bandwidth shaping fdb context */
 static fdbcontext fdbc;
@@ -278,7 +282,7 @@ main(int argc, char **argv)
        _pth_thread_yield
     };
     mmstat_t vstat;
-    pth_t mtable_thread = NULL;
+    pth_t hosts_table_thread = NULL;
     pth_attr_t threadattr;
 
     /* Set defaults */
@@ -404,39 +408,41 @@ main(int argc, char **argv)
     async_init(afuncs, CONF.ASYNC_PROCESSES, uid, gids, ngids);
 
     /* Things which shouldn't be part of the async pool processes */
-    packcommands(commands, 4);
     pth_init();
     async_init_pth();
-    pth_mutex_init(&cpool_lock);
-    pth_mutex_init(&mtable_lock);
-    pth_mutex_init(&rpool_lock);
+    pth_mutex_init(&clenv_lock);
+    pth_mutex_init(&hosts_lock);
+    pth_mutex_init(&rcpt_lock);
     pth_mutex_init(&mutexes_lock);
 
     /* Allocate necessary pools */
     /* Client nodes */
-    pool_init(&cpool, malloc, free, sizeof(clientenv),
+    pool_init(&clenv_pool, malloc, free, sizeof(clientenv),
            (65536 * CONF.ALLOC_BUFFERS) / sizeof(clientenv), 0, 0);
     /* RCPT nodes */
-    pool_init(&rpool, malloc, free, sizeof(rcptnode),
+    pool_init(&rcpt_pool, malloc, free, sizeof(rcptnode),
            (16384 * CONF.ALLOC_BUFFERS) / sizeof(rcptnode), 0, 0);
     /* Mutexes pool for mmfd */
-    pool_init(&pmutexes, malloc, free, sizeof(struct mutexnode),
+    pool_init(&mutexes_pool, malloc, free, sizeof(struct mutexnode),
            (16384 * CONF.ALLOC_BUFFERS) / sizeof(struct mutexnode), 0, 0);
     /* Rate nodes */
     if (CONF.FLOOD_PROTECTION) {
-       pool_init(&mpool, malloc, free, sizeof(mnode), CONF.FLOOD_CACHE, 1, 1);
-       hashtable_init(&mtable, CONF.FLOOD_CACHE, 1, malloc, free, mm_memcmp,
-               hashtable_hash, FALSE);
+       pool_init(&hosts_pool, malloc, free, sizeof(hostnode),
+               CONF.FLOOD_CACHE, 1, 1);
+       hashtable_init(&hosts_table, CONF.FLOOD_CACHE, 1, malloc, free,
+               mm_memcmp, hashtable_hash, FALSE);
        threadattr = pth_attr_new();
        pth_attr_set(threadattr, PTH_ATTR_JOINABLE, TRUE);
-       mtable_thread = pth_spawn(threadattr, mnode_expire_thread, NULL);
+       hosts_table_thread = pth_spawn(threadattr, hosts_expire_thread, NULL);
     }
     /* mmstr nodes */
     strlist = mmstrinit(malloc, free, 65536 * CONF.ALLOC_BUFFERS);
 
-    if (POOL_VALID(&cpool) && POOL_VALID(&rpool) && POOL_VALID(&pmutexes) &&
-           strlist && (!CONF.FLOOD_PROTECTION || (POOL_VALID(&mpool) &&
-                   HASHTABLE_VALID(&mtable) && mtable_thread != NULL))) {
+    if (hash_commands(commands, 4) && POOL_VALID(&clenv_pool) &&
+           POOL_VALID(&rcpt_pool) && POOL_VALID(&mutexes_pool) && strlist &&
+           (!CONF.FLOOD_PROTECTION || (POOL_VALID(&hosts_pool) &&
+                   HASHTABLE_VALID(&hosts_table) &&
+                   hosts_table_thread != NULL))) {
        fdbcinit(&gfdf, &fdbc, CONF.GBANDWIDTH_IN * 1024,
                CONF.GBANDWIDTH_OUT * 1024);
        mmsql_init(&mmsqlfuncs);
@@ -457,15 +463,24 @@ main(int argc, char **argv)
     }
 
     if (strlist) mmstrexit();
-    if (mtable_thread != NULL) {
-       pth_abort(mtable_thread);
-       pth_join(mtable_thread, NULL);
+    if (hosts_table_thread != NULL) {
+       pth_abort(hosts_table_thread);
+       pth_join(hosts_table_thread, NULL);
     }
-    if (HASHTABLE_VALID(&mtable)) hashtable_destroy(&mtable, FALSE);
-    if (POOL_VALID(&pmutexes)) pool_destroy(&pmutexes);
-    if (POOL_VALID(&mpool)) pool_destroy(&mpool);
-    if (POOL_VALID(&rpool)) pool_destroy(&rpool);
-    if (POOL_VALID(&cpool)) pool_destroy(&cpool);
+    if (HASHTABLE_VALID(&command_table))
+       hashtable_destroy(&command_table, FALSE);
+    if (POOL_VALID(&command_pool))
+       pool_destroy(&command_pool);
+    if (HASHTABLE_VALID(&hosts_table))
+       hashtable_destroy(&hosts_table, FALSE);
+    if (POOL_VALID(&mutexes_pool))
+       pool_destroy(&mutexes_pool);
+    if (POOL_VALID(&hosts_pool))
+       pool_destroy(&hosts_pool);
+    if (POOL_VALID(&rcpt_pool))
+       pool_destroy(&rcpt_pool);
+    if (POOL_VALID(&clenv_pool))
+       pool_destroy(&clenv_pool);
 
     fdbcdestroy(&fdbc);
     kill(0, SIGTERM);
@@ -524,25 +539,18 @@ all_help(clientenv *clenv)
 
     /* First check if a topic was specified */
     if ((col = mm_straspl(args, cmdline, 2)) == 2) {
-       register int i = 0;
-       register int32_t chash;
-       register bool valid;
+       u_int32_t chash;
+       struct commandnode *nod;
 
        /* Help requested on a topic */
-       valid = FALSE;
-       if ((chash = mm_strpack32(args[1], 4)) != -1) {
-           for (i = 0; commands[i].name; i++) {
-               if (commands[i].hash == chash) {
-                   valid = TRUE;
-                   break;
-               }
-           }
-       }
-
+       nod = NULL;
+       if ((chash = mm_strpack32(args[1], 4)) != 0)
+           nod = (struct commandnode *)hashtable_lookup(&command_table,
+                   &chash, sizeof(u_int32_t));
        col = 0;
-       if (valid) {
-           reply(fdb, 214, TRUE, commands[i].args);
-           reply(fdb, 214, TRUE, "   %s", commands[i].desc);
+       if (nod != NULL) {
+           reply(fdb, 214, TRUE, nod->command->args);
+           reply(fdb, 214, TRUE, "   %s", nod->command->desc);
            col = 2;
        }
 
@@ -758,7 +766,7 @@ all_rcpt(clientenv *clenv)
      * of CONF.FLOOD_MESSAGES within CONF.FLOOD_EXPIRES for this client.
      */
     if (valid && CONF.FLOOD_PROTECTION) {
-       register mnode *mnod;
+       register hostnode *hnod;
        register size_t len;
        register char *entry;
 
@@ -768,34 +776,35 @@ all_rcpt(clientenv *clenv)
            entry = clenv->c_ipaddr;
        len = mm_strlen(entry);
 
-       pth_mutex_acquire(&mtable_lock, FALSE, NULL);
-       /* First acquire our mnode, or create it if required */
-       if ((mnod = (mnode *)hashtable_lookup(&mtable, entry, len + 1))
+       pth_mutex_acquire(&hosts_lock, FALSE, NULL);
+       /* First acquire our hostnode, or create it if required */
+       if ((hnod = (hostnode *)hashtable_lookup(&hosts_table, entry, len + 1))
                != NULL) {
            /* Found, check and update limits */
-           mnod->posts++;
-           if (mnod->posts > CONF.FLOOD_MESSAGES) {
+           hnod->posts++;
+           if (hnod->posts > CONF.FLOOD_MESSAGES) {
                valid = FALSE;
                reason = RCPT_FLOOD;
                mmsyslog(0, LOGLEVEL,
                        "%08X Considered flood and rejected (%ld message(s) \
-within last %ld minute(s))", clenv->id, mnod->posts,
+within last %ld minute(s))", clenv->id, hnod->posts,
                        CONF.FLOOD_EXPIRES);
            }
        } else {
            /* Create a new entry */
-           if ((mnod = (mnode *)pool_alloc(&mpool, FALSE)) != NULL) {
-               mm_memcpy(mnod->host, entry, len + 1);
-               mnod->expires = time(NULL) + (CONF.FLOOD_EXPIRES * 60);
-               mnod->posts = 1;
-               hashtable_link(&mtable, (hashnode_t *)mnod, entry, len + 1);
+           if ((hnod = (hostnode *)pool_alloc(&hosts_pool, FALSE)) != NULL) {
+               mm_memcpy(hnod->host, entry, len + 1);
+               hnod->expires = time(NULL) + (CONF.FLOOD_EXPIRES * 60);
+               hnod->posts = 1;
+               hashtable_link(&hosts_table, (hashnode_t *)hnod, entry,
+                       len + 1);
            } else {
                valid = FALSE;
                reason = RCPT_FLOOD;
                mmsyslog(0, LOGLEVEL, "FLOOD_CACHE not large enough");
            }
        }
-       pth_mutex_release(&mtable_lock);
+       pth_mutex_release(&hosts_lock);
 
        if (!valid && CONF.STATFAIL_FLOOD)
            mmstat(&clenv->pstat, STAT_UPDATE, 1,
@@ -807,9 +816,9 @@ within last %ld minute(s))", clenv->id, mnod->posts,
        register rcptnode *rnode;
 
        reason = RCPT_ERROR;
-       pth_mutex_acquire(&rpool_lock, FALSE, NULL);
-       rnode = (rcptnode *)pool_alloc(&rpool, FALSE);
-       pth_mutex_release(&rpool_lock);
+       pth_mutex_acquire(&rcpt_lock, FALSE, NULL);
+       rnode = (rcptnode *)pool_alloc(&rcpt_pool, FALSE);
+       pth_mutex_release(&rcpt_lock);
        if (rnode) {
            mm_strcpy(rnode->address, addr);
            mm_strcpy(rnode->foraddress, foraddr);
@@ -818,7 +827,7 @@ within last %ld minute(s))", clenv->id, mnod->posts,
            reason = RCPT_OK;
            clenv->rcpts++;
        } else {
-           DPRINTF("all_rcpt", "pool_alloc(rpool)");
+           DPRINTF("all_rcpt", "pool_alloc(rcpt_pool)");
            nextstate = STATE_ERROR;
        }
     }
@@ -873,14 +882,59 @@ all_beer(clientenv *clenv)
 
 
 
-/* Used to initialize command table hashes */
-static void
-packcommands(struct command *cmd, size_t min)
-{
-    while (cmd->name) {
-       cmd->hash = mm_strpack32(cmd->name, min);
-       cmd++;
+/* Used to initialize command hash table */
+static bool     
+hash_commands(struct command *cmd, size_t min)
+{   
+    int i;
+
+    /* We do not care for any unfreed resources, the program will free them
+     * and exit if we return FALSE.
+     */ 
+    if (!pool_init(&command_pool, malloc, free, sizeof(struct commandnode),
+               64, 1, 0) || !hashtable_init(&command_table, 64, 1, malloc,
+                   free, commandnode_keycmp, commandnode_keyhash, TRUE))
+       return FALSE;
+
+    for (i = 0; cmd->name != NULL; cmd++, i++) {
+       struct commandnode *nod;
+       
+       if ((nod = (struct commandnode *)pool_alloc(&command_pool, FALSE))
+               == NULL)
+           return FALSE;
+       if ((nod->hash = mm_strpack32(cmd->name, min)) == 0)
+           return FALSE;
+       nod->command = cmd;
+       nod->index = i;
+       if (!hashtable_link(&command_table, (hashnode_t *)nod, &nod->hash,
+                   sizeof(u_int32_t))) {
+           DPRINTF("hash_commands", "hashtable_link(%s)", cmd->name);
+                                                                                   return FALSE;
+       }
     }
+
+    return TRUE;
+}               
+
+
+/* A quick hashtable_hash() replacement which already deals with unique
+ * 32-bit values                
+ */     
+/* ARGSUSED */  
+static u_int32_t
+commandnode_keyhash(const void *data, size_t len)
+{       
+    return *((u_int32_t *)data);
+}       
+
+
+/* A quick memcmp() replacement which only needs to compare two 32-bit values
+ */
+/* ARGSUSED */
+static int
+commandnode_keycmp(const void *src, const void *dst, size_t len)
+{
+    return *((u_int32_t *)src) - *((u_int32_t *)dst);
 }
 
 
@@ -919,9 +973,9 @@ alloc_clientenv(void)
 {
     clientenv *clenv;
 
-    pth_mutex_acquire(&cpool_lock, FALSE, NULL);
-    clenv = (clientenv *)pool_alloc(&cpool, TRUE);
-    pth_mutex_release(&cpool_lock);
+    pth_mutex_acquire(&clenv_lock, FALSE, NULL);
+    clenv = (clientenv *)pool_alloc(&clenv_pool, TRUE);
+    pth_mutex_release(&clenv_lock);
 
     if (clenv) {
        mmstat_init(&clenv->vstat, TRUE, TRUE);
@@ -954,9 +1008,9 @@ free_clientenv(clientenv *clenv)
     if (clenv->from) mmstrfree(clenv->from);
     empty_rcpts(&clenv->rcpt);
 
-    pth_mutex_acquire(&cpool_lock, FALSE, NULL);
+    pth_mutex_acquire(&clenv_lock, FALSE, NULL);
     pool_free((pnode_t *)clenv);
-    pth_mutex_release(&cpool_lock);
+    pth_mutex_release(&clenv_lock);
 
     return (NULL);
 }
@@ -970,12 +1024,12 @@ empty_rcpts(list_t *lst)
 {
     node_t *nod;
 
-    pth_mutex_acquire(&rpool_lock, FALSE, NULL);
+    pth_mutex_acquire(&rcpt_lock, FALSE, NULL);
     while ((nod = DLIST_TOP(lst)) != NULL) {
        DLIST_UNLINK(lst, nod);
        pool_free((pnode_t *)nod);
     }
-    pth_mutex_release(&rpool_lock);
+    pth_mutex_release(&rcpt_lock);
 }
 
 
@@ -1603,9 +1657,8 @@ handleclient(unsigned long id, int fd, clientlistnode *clientlnode,
 
            /* Main state switcher loop */
            for (;;) {
-               register int i = 0;
-               register int32_t chash;
-               register bool valid;
+               u_int32_t chash;
+               register struct commandnode *nod;
 
                fdbflushw(fdb);
                if ((len = fdbgets(fdb, buffer, 1000, FALSE)) > -1) {
@@ -1617,23 +1670,17 @@ handleclient(unsigned long id, int fd, clientlistnode *clientlnode,
                        break;
                    }
                    /* Verify if command matches an existing one */
-                   valid = FALSE;
-                   if ((chash = mm_strpack32(buffer, 4)) != -1) {
-                       for (i = 0; commands[i].name; i++) {
-                           if (commands[i].hash == chash) {
-                               valid = TRUE;
-                               break;
-                           }
-                       }
-                   }
-
-                   if (valid) {
+                   nod = NULL;
+                   if ((chash = mm_strpack32(buffer, 4)) != 0)
+                       nod = (struct commandnode *)hashtable_lookup(
+                               &command_table, &chash, sizeof(u_int32_t));
+                   if (nod != NULL) {
                        register int (*func)(clientenv *);
 
-                       mmsyslog(commands[i].loglevel, LOGLEVEL,
+                       mmsyslog(nod->command->loglevel, LOGLEVEL,
                                "%08X < %s", id, buffer);
 
-                       if ((func = states[state].functions[i])) {
+                       if ((func = states[state].functions[nod->index])) {
 
                            /* Valid command, process it in current state */
                            nstate = func(clenv);
@@ -1727,7 +1774,7 @@ _pth_mutex_create(void)
     struct mutexnode *mnod;
 
     pth_mutex_acquire(&mutexes_lock, FALSE, NULL);
-    mnod = (struct mutexnode *)pool_alloc(&pmutexes, FALSE);
+    mnod = (struct mutexnode *)pool_alloc(&mutexes_pool, FALSE);
     pth_mutex_release(&mutexes_lock);
 
     if (mnod)
@@ -1820,7 +1867,7 @@ a_res_query(clientenv *clenv, const char *dname, int class, int type,
 }
 
 
-/* Here consists of our mnode expiration thread. It asynchroneously and
+/* Here consists of our hostnode expiration thread. It asynchroneously and
  * occasionally iterating through all the nodes to reset and/or expunge the
  * expired ones. Doing this here prevents interfering with the normally more
  * frequent lookups which can be done with hashtable_lookup() in another
@@ -1829,9 +1876,9 @@ a_res_query(clientenv *clenv, const char *dname, int class, int type,
  */
 /* ARGSUSED */
 static void *
-mnode_expire_thread(void *args)
+hosts_expire_thread(void *args)
 {
-    struct mnode_expire_thread_iterator_udata data;
+    struct hosts_expire_thread_iterator_udata data;
 
     /* Set the initial timeout to the maximum allowed */
     data.soonest = time(NULL) + CONF.FLOOD_EXPIRES;
@@ -1844,13 +1891,14 @@ mnode_expire_thread(void *args)
         */
        data.current = time(NULL);
        data.soonest = data.current + CONF.FLOOD_EXPIRES;
-       /* Lock mtable, expunge expired nodes and set data.soonest to the
+       /* Lock hosts_table, expunge expired nodes and set data.soonest to the
         * time of the soonest next expireing node
         */
-       pth_mutex_acquire(&mtable_lock, FALSE, NULL);
-       if (HASHTABLE_NODES(&mtable) > 0)
-           hashtable_iterate(&mtable, mnode_expire_thread_iterator, &data);
-       pth_mutex_release(&mtable_lock);
+       pth_mutex_acquire(&hosts_lock, FALSE, NULL);
+       if (HASHTABLE_NODES(&hosts_table) > 0)
+           hashtable_iterate(&hosts_table, hosts_expire_thread_iterator,
+                   &data);
+       pth_mutex_release(&hosts_lock);
     }
 
     /* NOTREACHED */
@@ -1860,19 +1908,19 @@ mnode_expire_thread(void *args)
 
 
 static bool
-mnode_expire_thread_iterator(hashnode_t *hnod, void *udata)
+hosts_expire_thread_iterator(hashnode_t *hnod, void *udata)
 {
-    mnode *mnod = (mnode *)hnod;
-    struct mnode_expire_thread_iterator_udata *data = udata;
+    hostnode *nod = (hostnode *)hnod;
+    struct hosts_expire_thread_iterator_udata *data = udata;
 
-    if (mnod->expires <= data->current) {
+    if (nod->expires <= data->current) {
        /* This entry expired, expunge it */
-       hashtable_unlink(&mtable, (hashnode_t *)mnod);
-       pool_free((pnode_t *)mnod);
+       hashtable_unlink(&hosts_table, (hashnode_t *)nod);
+       pool_free((pnode_t *)nod);
     } else {
        /* We must find and record the soonest expireing node */
-       if (data->soonest > mnod->expires)
-           data->soonest = mnod->expires;
+       if (data->soonest > nod->expires)
+           data->soonest = nod->expires;
     }
     /* If the cache is big, prevent from interfering with other threads */
     if ((data->cnt++) == 64) {
index 4b19481..95c82e2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmsmtpd.h,v 1.17 2003/08/13 11:20:40 mmondor Exp $ */
+/* $Id: mmsmtpd.h,v 1.18 2003/10/11 11:20:23 mmondor Exp $ */
 
 /*
  * Copyright (C) 2000-2003, Matthew Mondor
@@ -162,14 +162,14 @@ typedef struct rcptnode {
  * received, along with information on it to determine if the rate of messages
  * is too high.
  */
-typedef struct mnode {
+typedef struct hostnode {
     hashnode_t node;
     char host[128];            /* Hostname */
     time_t expires;            /* Time entry will expire */
     long posts;                        /* How many posts since entry creation */
-} mnode;
+} hostnode;
 
-struct mnode_expire_thread_iterator_udata {
+struct hosts_expire_thread_iterator_udata {
     time_t current, soonest;
     int cnt;
 };
@@ -189,11 +189,18 @@ typedef struct state {
 
 /* A command of a state */
 typedef struct command {
-    int32_t hash;
     int loglevel;
     char *name, *args, *desc;
 } command;
 
+/* For fast command lookup */
+struct commandnode {
+    hashnode_t node;
+    u_int32_t hash;
+    struct command *command;
+    int index;
+};
+
 /* Used for fast index of result messages */
 struct reply_messages {
     int code;
@@ -238,7 +245,9 @@ static int all_rcpt(clientenv *);
 static int all_data(clientenv *);
 static int all_beer(clientenv *);
 
-static void packcommands(struct command *, size_t);
+static bool hash_commands(struct command *, size_t);
+static u_int32_t commandnode_keyhash(const void *, size_t);
+static int commandnode_keycmp(const void *, const void *, size_t);
 static bool reply(fdbuf *, int, bool, const char *, ...);
 
 static clientenv *alloc_clientenv(void);
@@ -270,8 +279,8 @@ static bool _pth_eintr(void);
 static void async_resquery(struct async_msg *);
 static int a_res_query(clientenv *, const char *, int, int, u_char *, int);
 
-static void *mnode_expire_thread(void *);
-static bool mnode_expire_thread_iterator(hashnode_t *, void *);
+static void *hosts_expire_thread(void *);
+static bool hosts_expire_thread_iterator(hashnode_t *, void *);