Add slab allocator; reduce delta with srvx-gs.
authorMichael Poole <mdpoole@troilus.org>
Mon, 31 Jan 2005 05:14:52 +0000 (05:14 +0000)
committerMichael Poole <mdpoole@troilus.org>
Mon, 31 Jan 2005 05:14:52 +0000 (05:14 +0000)
configure.in: Check for getpagesize().  Support --with-malloc=slab.

src/Makefile.am: Add alloc-slab.c as an extra source file.

src/alloc-srvx.c: Clean up srvx_free() slightly.  Check for previously
allocated blocks.

srvx.conf.example, src/chanserv.c, src/main.c, src/modcmd.c,
src/proto-p10.c: Apply patches to bring closer to srvx-gs branch.

src/log.c: Assert and _exit() on fatal log messages.

src/opserv.c: Clarify logic for modes to set on join floods.

src/proto-common.c: Accept off-channel commands in registered channels.
git-archimport-id: srvx@srvx.net--2005-srvx/srvx--devo--1.3--patch-10

17 files changed:
ChangeLog
configure.in
src/Makefile.am
src/alloc-slab.c [new file with mode: 0644]
src/alloc-srvx.c
src/chanserv.c
src/chanserv.h
src/common.h
src/hash.h
src/helpfile.c
src/log.c
src/main.c
src/modcmd.c
src/opserv.c
src/proto-common.c
src/proto-p10.c
srvx.conf.example

index 05846ca326f3a0de842d33302f2242161b298ac4..e309721dc7d5e79000e97f6d93aac3f9696c67b6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,39 @@
 # arch-tag: automatic-ChangeLog--srvx@srvx.net--2005-srvx/srvx--devo--1.3
 #
 
+2005-01-31 05:14:52 GMT        Michael Poole <mdpoole@troilus.org>     patch-10
+
+    Summary:
+      Add slab allocator; reduce delta with srvx-gs.
+    Revision:
+      srvx--devo--1.3--patch-10
+
+    configure.in: Check for getpagesize().  Support --with-malloc=slab.
+    
+    src/Makefile.am: Add alloc-slab.c as an extra source file.
+    
+    src/alloc-srvx.c: Clean up srvx_free() slightly.  Check for previously
+    allocated blocks.
+    
+    srvx.conf.example, src/chanserv.c, src/main.c, src/modcmd.c,
+    src/proto-p10.c: Apply patches to bring closer to srvx-gs branch.
+    
+    src/log.c: Assert and _exit() on fatal log messages.
+    
+    src/opserv.c: Clarify logic for modes to set on join floods.
+    
+    src/proto-common.c: Accept off-channel commands in registered channels.
+
+    new files:
+     src/.arch-ids/alloc-slab.c.id src/alloc-slab.c
+
+    modified files:
+     ChangeLog configure.in src/Makefile.am src/alloc-srvx.c
+     src/chanserv.c src/chanserv.h src/common.h src/hash.h
+     src/helpfile.c src/log.c src/main.c src/modcmd.c src/opserv.c
+     src/proto-common.c src/proto-p10.c srvx.conf.example
+
+
 2005-01-26 21:16:54 GMT        Michael Poole <mdpoole@troilus.org>     patch-9
 
     Summary:
index 81dd91dc3bff4a7836f14ae3062215a7c56ad981..3df600bf3404a8692c53e8e00860c888c3828b9f 100644 (file)
@@ -79,7 +79,7 @@ if test $ac_cv_func_gettimeofday = no; then
 fi
 
 dnl We have fallbacks in case these are missing, so just check for them.
-AC_CHECK_FUNCS(bcopy memcpy memset strdup strerror strsignal localtime_r setrlimit inet_ntoa getopt getopt_long regcomp regexec regfree sysconf,,)
+AC_CHECK_FUNCS(bcopy getpagesize memcpy memset strdup strerror strsignal localtime_r setrlimit inet_ntoa getopt getopt_long regcomp regexec regfree sysconf,,)
 
 dnl Check for absolutely required library functions.
 AC_CHECK_FUNCS(select socket strcspn strspn strtod strtoul,,AC_MSG_ERROR([a required function was not found.  srvx build will fail.]))
@@ -180,6 +180,10 @@ elif test "x$withval" = "xsrvx" ; then
   AC_MSG_RESULT(srvx)
   AC_DEFINE(WITH_MALLOC_SRVX, 1, [Define if using the srvx internal debug allocator])
   MODULE_OBJS="$MODULE_OBJS alloc-srvx.\$(OBJEXT)"
+elif test "x$withval" = "xslab" ; then
+  AC_MSG_RESULT(slab)
+  AC_DEFINE(WITH_MALLOC_SLAB, 1, [Define if using the slab internal debug allocator])
+  MODULE_OBJS="$MODULE_OBJS alloc-slab.\$(OBJEXT)"
 else
   AC_MSG_ERROR([Unknown malloc type $withval])
 fi
index 7fe7c1d12f8ecf40389242d41725d00eebec14f8..2ac28aad5190ecb42f14e4ec90689da836b8e704 100644 (file)
@@ -22,7 +22,7 @@ checkversion:
            mv $$TMPFILE arch-version.h ; \
        fi
 
-EXTRA_srvx_SOURCES = alloc-srvx.c proto-bahamut.c proto-common.c proto-p10.c mod-snoop.c mod-memoserv.c mod-helpserv.c mod-sockcheck.c
+EXTRA_srvx_SOURCES = alloc-slab.c alloc-srvx.c proto-bahamut.c proto-common.c proto-p10.c mod-snoop.c mod-memoserv.c mod-helpserv.c mod-sockcheck.c
 srvx_LDADD = @MODULE_OBJS@
 srvx_DEPENDENCIES = @MODULE_OBJS@
 srvx_SOURCES = \
diff --git a/src/alloc-slab.c b/src/alloc-slab.c
new file mode 100644 (file)
index 0000000..b44f6a0
--- /dev/null
@@ -0,0 +1,304 @@
+/* alloc-slab.c - Slab debugging allocator
+ * Copyright 2005 srvx Development Team
+ *
+ * This file is part of srvx.
+ *
+ * srvx is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "common.h"
+#include "log.h"
+
+#if defined(HAVE_SYS_MMAN_H)
+# include <sys/mman.h>
+#endif
+
+#if !defined(HAVE_MMAP)
+# error The slab allocator requires that your system have the mmap() system call.
+#endif
+
+struct slab {
+    struct slabset *parent;
+    struct slab *prev;
+    struct slab *next;
+    void *base;
+    void **free;
+    unsigned int used;
+};
+
+struct slabset {
+    struct slabset *next;
+    struct slab *child;
+    size_t size;
+    size_t items_per_slab;
+};
+
+#define SLAB_MIN     (2 * sizeof(void*))
+#define SLAB_GRAIN   sizeof(void*)
+#define SLAB_ALIGN   SLAB_GRAIN
+#define SMALL_CUTOFF 512
+/* Element size < SMALL_CUTOFF -> use small slabs.
+ * Larger elements are allocated directly using mmap().  The largest
+ * regularly allocated struct in srvx 1.x is smaller than
+ * SMALL_CUTOFF, so there is not much point in coding support for
+ * larger slabs.
+ */
+
+static struct slabset *little_slabs[SMALL_CUTOFF / SLAB_GRAIN];
+static struct slabset slabset_slabs;
+unsigned long alloc_count;
+unsigned long alloc_size;
+
+#if defined(MAP_ANON)
+#elif defined(MAP_ANONYMOUS)
+# define MAP_ANON MAP_ANONYMOUS
+#else
+# define MAP_ANON 0
+#endif
+
+static size_t
+slab_pagesize(void)
+{
+    static size_t pagesize;
+    if (pagesize
+#if defined(HAVE_GETPAGESIZE)
+        || (pagesize  = getpagesize())
+#endif
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+        || (pagesize = sysconf(_SC_PAGESIZE))
+#endif
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+        || (pagesize = sysconf(_SC_PAGE_SIZE))
+#endif
+        ) return pagesize;
+    assert(0 && "unable to find system page size");
+    return pagesize = 4096;
+}
+
+static size_t
+slab_round_up(size_t size)
+{
+    return (size + slab_pagesize() - 1) & ~(slab_pagesize() - 1);
+}
+
+static void *
+slab_map(size_t length)
+{
+    static int mmap_fd = -1;
+    void *res;
+
+#if ! MAP_ANON
+    if (mmap_fd < 0) {
+        mmap_fd = open("/dev/zero", 0);
+        if (mmap_fd < 0)
+            log_module(MAIN_LOG, LOG_FATAL, "Unable to open /dev/zero for mmap: %s", strerror(errno()));
+    }
+#endif
+    res = mmap(0, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, mmap_fd, 0);
+    if (res == MAP_FAILED)
+        log_module(MAIN_LOG, LOG_FATAL, "Unable to mmap %lu bytes (%s).", (unsigned long)length, strerror(errno));
+    return res;
+}
+
+static void *slab_alloc(struct slabset *sset);
+static void slab_unalloc(void *ptr, size_t size);
+
+static struct slabset *
+slabset_create(size_t size)
+{
+    unsigned int idx;
+
+    size = (size < SLAB_MIN) ? SLAB_MIN : (size + SLAB_GRAIN - 1) & ~(SLAB_GRAIN - 1);
+    idx = size / SLAB_GRAIN;
+    assert(idx < ArrayLength(little_slabs));
+    if (!little_slabs[idx]) {
+        if (!slabset_slabs.size) {
+            unsigned int idx2 = (sizeof(struct slabset) + SLAB_GRAIN - 1) / SLAB_GRAIN;
+            slabset_slabs.size = sizeof(struct slabset);
+            slabset_slabs.items_per_slab = (slab_pagesize() - sizeof(struct slab)) / ((sizeof(struct slabset) + SLAB_ALIGN - 1) & ~(SLAB_ALIGN - 1));
+            little_slabs[idx2] = &slabset_slabs;
+            if (idx == idx2)
+                return &slabset_slabs;
+        }
+        little_slabs[idx] = slab_alloc(&slabset_slabs);
+        little_slabs[idx]->size = size;
+        little_slabs[idx]->items_per_slab = (slab_pagesize() - sizeof(struct slab)) / ((size + SLAB_ALIGN - 1) & ~(SLAB_ALIGN - 1));
+    }
+    return little_slabs[idx];
+}
+
+static void *
+slab_alloc(struct slabset *sset)
+{
+    struct slab *slab;
+    void **item;
+
+    if (!sset->child || !sset->child->free) {
+        unsigned int ii, step;
+
+        /* Allocate new slab. */
+        item = slab_map(slab_pagesize());
+        slab = (struct slab*)((char*)item + slab_pagesize() - sizeof(*slab));
+        slab->base = item;
+
+        /* Populate free list. */
+        step = (sset->size + SLAB_ALIGN - 1) & ~(SLAB_ALIGN - 1);
+        for (ii = 1, item = slab->free = slab->base;
+             ii < sset->items_per_slab;
+             ++ii, item = (*item = (char*)item + step));
+
+        /* Link to parent slabset. */
+        slab->parent = sset;
+        if ((slab->prev = sset->child)) {
+            slab->next = slab->prev->next;
+            slab->prev->next = slab;
+            if (slab->next)
+                slab->next->prev = slab;
+        }
+        sset->child = slab;
+    }
+
+    slab = sset->child;
+    item = slab->free;
+    slab->free = *item;
+    if (slab->used++ == sset->items_per_slab) {
+        if (sset->child != slab) {
+            /* Unlink slab and reinsert before sset->child. */
+            if (slab->prev)
+                slab->prev->next = slab->next;
+            if (slab->next)
+                slab->next->prev = slab->prev;
+            if ((slab->prev = sset->child->prev))
+                slab->prev->next = slab;
+            if ((slab->next = sset->child))
+                slab->next->prev = slab;
+        } else if (slab->next) {
+            /* Advance sset->child to next pointer. */
+            sset->child = slab->next;
+        }
+    }
+    memset(item, 0, sset->size);
+    return item;
+}
+
+static void
+slab_unalloc(void *ptr, size_t size)
+{
+    void **item;
+    struct slab *slab, *new_next;
+
+    item = ptr;
+    assert(size < SMALL_CUTOFF);
+    slab = (struct slab*)((((unsigned long)ptr | (slab_pagesize() - 1)) + 1) - sizeof(*slab));
+    *item = slab->free;
+    slab->free = item;
+
+    if (slab->used-- == slab->parent->items_per_slab
+        && slab->parent->child != slab) {
+        new_next = slab->parent->child;
+        slab->parent->child = slab;
+    } else if (!slab->used) {
+        for (new_next = slab;
+             new_next->next && new_next->next->used;
+             new_next = new_next->next) ;
+        new_next = new_next->next;
+    } else
+        new_next = NULL;
+
+    if (new_next) {
+        if (slab->prev)
+            slab->prev->next = slab->next;
+        if (slab->next)
+            slab->next->prev = slab->prev;
+        if ((slab->prev = new_next->prev))
+            slab->prev->next = slab;
+        if ((slab->next = new_next->next))
+            slab->next->prev = slab;
+    }
+}
+
+void *
+slab_malloc(UNUSED_ARG(const char *file), UNUSED_ARG(unsigned int line), size_t size)
+{
+    size_t real, *res;
+
+    real = size + sizeof(size_t);
+    if (real < SMALL_CUTOFF)
+        res = slab_alloc(slabset_create(real));
+    else
+        res = slab_map(slab_round_up(real));
+    *res = size;
+    return res + 1;
+}
+
+void *
+slab_realloc(const char *file, unsigned int line, void *ptr, size_t size)
+{
+    size_t orig, *newblock;
+
+    if (!ptr)
+        return slab_malloc(file, line, size);
+
+    verify(ptr);
+    orig = ((size_t*)ptr)[-1];
+    if (orig >= size)
+        return ptr;
+    newblock = slab_malloc(file, line, size);
+    memcpy(newblock, ptr, orig);
+    return newblock;
+}
+
+char *
+slab_strdup(const char *file, unsigned int line, const char *src)
+{
+    char *target;
+    size_t len;
+
+    len = strlen(src) + 1;
+    target = slab_malloc(file, line, len);
+    memcpy(target, src, len);
+    return target;
+}
+
+void
+slab_free(UNUSED_ARG(const char *file), UNUSED_ARG(unsigned int line), void *ptr)
+{
+    size_t real, *size;
+
+    if (!ptr)
+        return;
+    verify(ptr);
+    size = (size_t*)ptr - 1;
+    real = *size + sizeof(size_t);
+    if (real < SMALL_CUTOFF)
+        slab_unalloc(size, real);
+    else
+        munmap(size, slab_round_up(real));
+}
+
+void
+verify(const void *ptr)
+{
+    size_t size;
+
+    if (!ptr)
+        return;
+    else if ((size = ((size_t*)ptr)[-1] + sizeof(size_t)) >= SMALL_CUTOFF)
+        assert(((unsigned long)ptr & (slab_pagesize() - 1)) == sizeof(size_t));
+    else {
+        struct slab *slab;
+        size_t expected;
+
+        expected = (size + SLAB_GRAIN - 1) & ~(SLAB_GRAIN - 1);
+        slab = (struct slab*)((((unsigned long)ptr | (slab_pagesize() - 1)) + 1) - sizeof(*slab));
+        assert(slab->parent->size == expected);
+    }
+}
index 72fca5a6e10947d9b8437d8936a05149e7a66014..45fd15de72cbde97e34a016b41e53240fbb561fd 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "common.h"
+#include "log.h"
 
 #undef malloc
 #undef free
@@ -60,6 +61,11 @@ srvx_malloc(const char *file, unsigned int line, size_t size)
 
     block = malloc(sizeof(*block) + size + sizeof(redzone));
     assert(block != NULL);
+    if (block->magic == ALLOC_MAGIC && block->file_id < file_ids_used) {
+        /* Only report the error, due to possible false positives. */
+        log_module(MAIN_LOG, LOG_WARNING, "Detected possible reallocation: %p (called by %s:%u/%u; allocated by %u:%u/%u).",
+                   block, file, line, size, block->file_id, block->line, block->size);
+    }
     memset(block, 0, sizeof(*block) + size);
     memcpy((char*)(block + 1) + size, redzone, sizeof(redzone));
     block->file_id = get_file_id(file);
@@ -116,23 +122,21 @@ srvx_strdup(const char *file, unsigned int line, const char *src)
 }
 
 void
-srvx_free(const char *file, unsigned int line, void *ptr)
+srvx_free(UNUSED_ARG(const char *file), UNUSED_ARG(unsigned int line), void *ptr)
 {
     struct alloc_header *block;
     size_t size;
 
     if (!ptr)
         return;
+    verify(ptr);
     block = (struct alloc_header *)ptr - 1;
-    assert(block->magic == ALLOC_MAGIC);
-    assert(0 == memcmp((char*)(block + 1) + block->size, redzone, sizeof(redzone)));
     size = block->size;
     memset(block + 1, 0xde, size);
     block->magic = FREE_MAGIC;
     free(block);
     alloc_count--;
     alloc_size -= size;
-    (void)file; (void)line;
 }
 
 void
index c1d6f9124ec950e86630a91afe20fcb1a2d49883..9f6c1412a802f85710c65aa69cb3606efa8709c6 100644 (file)
@@ -1684,7 +1684,8 @@ static CHANSERV_FUNC(cmd_register)
             return 0;
         }
 
-        if(!IsHelping(user) && (!(mn = GetUserMode(channel, user)) || !(mn->modes & MODE_CHANOP)))
+        if(!IsHelping(user)
+           && (!(mn = GetUserMode(channel, user)) || !(mn->modes & MODE_CHANOP)))
         {
             reply("CSMSG_MUST_BE_OPPED", channel->name);
             return 0;
@@ -4456,18 +4457,21 @@ chanserv_expire_suspension(void *data)
 {
     struct suspended *suspended = data;
     struct chanNode *channel;
-    struct mod_chanmode change;
 
     if(!suspended->expires || (now < suspended->expires))
         suspended->revoked = now;
     channel = suspended->cData->channel;
     suspended->cData->channel = channel;
     suspended->cData->flags &= ~CHANNEL_SUSPENDED;
-    mod_chanmode_init(&change);
-    change.argc = 1;
-    change.args[0].mode = MODE_CHANOP;
-    change.args[0].u.member = AddChannelUser(chanserv, channel);
-    mod_chanmode_announce(chanserv, channel, &change);
+    if(!IsOffChannel(suspended->cData))
+    {
+        struct mod_chanmode change;
+        mod_chanmode_init(&change);
+        change.argc = 1;
+        change.args[0].mode = MODE_CHANOP;
+        change.args[0].u.member = AddChannelUser(chanserv, channel);
+        mod_chanmode_announce(chanserv, channel, &change);
+    }
 }
 
 static CHANSERV_FUNC(cmd_csuspend)
@@ -5494,8 +5498,15 @@ static CHANSERV_FUNC(cmd_giveownership)
     new_owner = GetChannelAccess(cData, new_owner_hi);
     if(!new_owner)
     {
-        reply("CSMSG_NO_CHAN_USER", new_owner_hi->handle, channel->name);
-        return 0;
+        if(force)
+        {
+            new_owner = add_channel_user(cData, new_owner_hi, UL_COOWNER, 0, NULL);
+        }
+        else
+        {
+            reply("CSMSG_NO_CHAN_USER", new_owner_hi->handle, channel->name);
+            return 0;
+        }
     }
     if((chanserv_get_owned_count(new_owner_hi) >= chanserv_conf.max_owned) && !force)
     {
@@ -6598,6 +6609,8 @@ ban_read_helper(const char *key, struct record_data *rd, struct chanData *chan)
     s_expires = database_get_data(rd->d.object, KEY_EXPIRES, RECDB_QSTRING);
     owner = database_get_data(rd->d.object, KEY_OWNER, RECDB_QSTRING);
     reason = database_get_data(rd->d.object, KEY_REASON, RECDB_QSTRING);
+    if (!reason || !owner)
+        return;
 
     set_time = set ? (time_t)strtoul(set, NULL, 0) : now;
     triggered_time = triggered ? (time_t)strtoul(triggered, NULL, 0) : 0;
index d094595fbe6b50b7128b66516ecbd3be31478828..b01a944617221e503278f766f2472b76a83e390f 100644 (file)
@@ -163,7 +163,7 @@ struct do_not_register
 {
     char   chan_name[CHANNELLEN+1];
     char   setter[NICKSERV_HANDLE_LEN+1];
-    time_t set; 
+    time_t set;
     char   reason[1];
 };
 
index 5982512fe3670eda84f87721e133e8193342ed56..e2ee1675e422257a2ef60c6fb6ac20d76949cd4b 100644 (file)
@@ -102,6 +102,24 @@ extern void srvx_free(const char *, unsigned int, void *);
 extern void verify(const void *ptr);
 #  define verify(x) verify(x)
 # endif
+#elif defined(WITH_MALLOC_SLAB)
+# define malloc(n) slab_malloc(__FILE__, __LINE__, (n))
+# undef calloc
+# define calloc(m,n) slab_malloc(__FILE__, __LINE__, (m)*(n))
+# undef realloc
+# define realloc(p,n) slab_realloc(__FILE__, __LINE__, (p), (n))
+# undef free
+# define free(p) slab_free(__FILE__, __LINE__, (p))
+# undef strdup
+# define strdup(s) slab_strdup(__FILE__, __LINE__, (s))
+extern void *slab_malloc(const char *, unsigned int, size_t);
+extern void *slab_realloc(const char *, unsigned int, void *, size_t);
+extern char *slab_strdup(const char *, unsigned int, const char *);
+extern void slab_free(const char *, unsigned int, void *);
+# if !defined(NDEBUG)
+extern void verify(const void *ptr);
+#  define verify(x) verify(x)
+# endif
 #endif
 
 #ifndef verify
index d10c35ea9467b3fc794213d9298e93843d01fed7..443f9f4ddd5a41af8d1ddbd1d878f5abb6ce0f6f 100644 (file)
@@ -58,7 +58,7 @@
 #define FLAGS_STAMPED           0x1000 /* for users who have been stamped */
 #define FLAGS_HIDDEN_HOST       0x2000 /* user's host is masked by their account */
 #define FLAGS_REGNICK           0x4000 /* user owns their current nick */
-#define FLAGS_REGISTERING      0x8000 /* user has issued account register command, is waiting for email cookie */
+#define FLAGS_REGISTERING       0x8000 /* user has issued account register command, is waiting for email cookie */
 
 #define IsOper(x)               ((x)->modes & FLAGS_OPER)
 #define IsService(x)            ((x)->modes & FLAGS_SERVICE)
@@ -126,7 +126,7 @@ struct chanNode {
     unsigned int limit, locks;
     char key[KEYLEN + 1];
     time_t timestamp; /* creation time */
-  
+
     char topic[TOPICLEN + 1];
     char topic_nick[NICKLEN + 1];
     time_t topic_time;
index d214fe345e95b45d1514d991ae2d134239d65fad..e5aca29edec0b07b6df8cdc464f4a0c2002e0bd1 100644 (file)
@@ -84,7 +84,7 @@ static struct language *language_alloc(const char *name)
  * lang is a two-letter code according to ISO-639-1 (or three-letter
  * code according to ISO-639-2 for languages not in ISO-639-1), and
  * COUNTRY is the ISO 3166 country code in all upper case.
- * 
+ *
  * See also:
  * http://www.loc.gov/standards/iso639-2/
  * http://www.loc.gov/standards/iso639-2/langhome.html
index aefadbb86496e05931bcc60b8400415ceaa7fbdd..8e2600ac0b3fd2a04bf44cc18538c9a2a4eb41c3 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -587,6 +587,10 @@ log_module(struct log_type *type, enum log_severity sev, const char *format, ...
         /* Special behavior before we start full operation */
         fprintf(stderr, "%s: %s\n", log_severity_names[sev], msgbuf);
     }
+    if (sev == LOG_FATAL) {
+        assert(0 && "fatal message logged");
+        _exit(1);
+    }
 }
 
 /* audit log searching */
@@ -719,7 +723,8 @@ log_entry_search(struct logSearch *discrim, entry_search_func esf, void *data)
     unsigned int matched = 0;
 
     if (discrim->type) {
-        struct logEntry *entry, *last;
+        volatile struct logEntry *last;
+        struct logEntry *entry;
 
         for (entry = discrim->type->log_oldest, last = NULL;
              entry;
index c16aafac1b41950a99a5b779442e5bd8d6005ca7..215edcf646cb0043e4541e734a838163b2da1014 100644 (file)
@@ -691,6 +691,12 @@ int main(int argc, char *argv[])
     FILE *file_out;
     struct sigaction sv;
 
+#if WITH_MALLOC_BOEHM_GC
+    GC_find_leak = 1;
+    GC_set_warn_proc(gc_warn_proc);
+    GC_enable_incremental();
+#endif
+
     daemon = 1;
     debug = 0;
     tools_init();
@@ -816,10 +822,6 @@ int main(int argc, char *argv[])
     MAIN_LOG = log_register_type("srvx", "file:main.log");
     if (debug)
         log_debug();
-#if WITH_MALLOC_BOEHM_GC
-    GC_set_warn_proc(gc_warn_proc);
-    GC_enable_incremental();
-#endif
     timeq_init();
     init_structs();
     init_parse();
index 95feb17f3bc411bff5cbcaf7f4f810b64c0fb069..2ae4db59e59005b6c8149b079ffed66ce3aa8802 100644 (file)
@@ -145,18 +145,18 @@ static struct modcmd_flag {
     { "channel", MODCMD_REQUIRE_CHANNEL },
     { "chanuser", MODCMD_REQUIRE_CHANUSER },
     { "disabled", MODCMD_DISABLED },
+    { "helping", MODCMD_REQUIRE_HELPING },
     { "ignore_csuspend", MODCMD_IGNORE_CSUSPEND },
     { "joinable", MODCMD_REQUIRE_JOINABLE },
     { "keepbound", MODCMD_KEEP_BOUND },
     { "loghostmask", MODCMD_LOG_HOSTMASK },
-    { "nolog", MODCMD_NO_LOG },
     { "networkhelper", MODCMD_REQUIRE_NETWORK_HELPER },
     { "never_csuspend", MODCMD_NEVER_CSUSPEND },
+    { "nolog", MODCMD_NO_LOG },
     { "oper", MODCMD_REQUIRE_OPER },
     { "qualified", MODCMD_REQUIRE_QUALIFIED },
     { "regchan", MODCMD_REQUIRE_REGCHAN },
     { "supporthelper", MODCMD_REQUIRE_SUPPORT_HELPER },
-    { "helping", MODCMD_REQUIRE_HELPING },
     { "toy", MODCMD_TOY },
     { NULL, 0 }
 };
@@ -545,7 +545,8 @@ svccmd_can_invoke(struct userNode *user, struct userNode *bot, struct svccmd *cm
         rflags |= ACTION_STAFF;
     }
     if (cmd->min_opserv_level > 0) {
-        if (!oper_has_access(user, bot, cmd->min_opserv_level, !(options & SVCCMD_NOISY))) return 0;
+        if (!oper_has_access(user, bot, cmd->min_opserv_level, !(options & SVCCMD_NOISY)))
+            return 0;
         rflags |= ACTION_STAFF;
     }
     if (cmd->req_account_flags || cmd->deny_account_flags) {
@@ -566,7 +567,7 @@ svccmd_can_invoke(struct userNode *user, struct userNode *bot, struct svccmd *cm
     /* If it's an override, return a special value. */
     if ((flags & MODCMD_REQUIRE_CHANUSER)
         && (options & SVCCMD_NOISY)
-        && (uData->access > 500)
+        && (!uData || (uData->access > 500))
         && (!(uData = _GetChannelUser(channel->channel_info, user->handle_info, 0, 0))
             || uData->access < cmd->min_channel_access)
         && !(flags & (MODCMD_REQUIRE_STAFF|MODCMD_REQUIRE_HELPING))) {
@@ -1670,12 +1671,12 @@ static MODCMD_FUNC(cmd_showcommands) {
             if (flags & MODCMD_REQUIRE_HELPING)
                 access = "helping";
             else if (flags & MODCMD_REQUIRE_STAFF) {
-                switch (flags & MODCMD_REQUIRE_STAFF) {
-                case MODCMD_REQUIRE_OPER: access = "oper"; break;
-                case MODCMD_REQUIRE_OPER | MODCMD_REQUIRE_NETWORK_HELPER:
-                case MODCMD_REQUIRE_NETWORK_HELPER: access = "net.helper"; break;
-                default: access = "staff"; break;
-                }
+                if (flags & MODCMD_REQUIRE_OPER)
+                    access = "oper";
+                else if (flags & MODCMD_REQUIRE_NETWORK_HELPER)
+                    access = "net.helper";
+                else
+                    access = "staff";
             } else
                 access = strtab(svccmd->min_channel_access);
             tbl.contents[ii+1][1+show_opserv_level] = access;
index 87845c512b9e543f9858ef95c9c06f1345e0689b..b3d19ac8032886d960cc308fb45338d08d95c8d3 100644 (file)
@@ -1896,8 +1896,7 @@ opserv_join_check(struct modeNode *mNode)
                 change.args[0].u.member = AddChannelUser(opserv, channel);
                 change.argc++;
             }
-            if (!(channel->modes & MODE_MODERATED))
-                change.modes_set |= MODE_MODERATED;
+            change.modes_set = (MODE_MODERATED | MODE_DELAYJOINS) & ~channel->modes;
             if (change.modes_set || change.argc)
                 mod_chanmode_announce(opserv, channel, &change);
             send_target_message(0, channel->name, opserv, "OSMSG_FLOOD_MODERATE");
index 22334026c9e412cebe6b658ef78dbcb7d942f95d..7226977f7a01cf4871212f0b99987d6d1819d096 100644 (file)
@@ -440,16 +440,17 @@ privmsg_chan_helper(struct chanNode *cn, void *data)
         mn->idle_since = now;
 
     /* Never send a NOTICE to a channel to one of the services */
-    if (!pd->is_notice && cf->func && GetUserMode(cn, cf->service))
+    if (!pd->is_notice && cf->func
+        && ((cn->modes & MODE_REGISTERED) || GetUserMode(cn, cf->service)))
         cf->func(pd->user, cn, pd->text+1, cf->service);
 
     /* This catches *all* text sent to the channel that the services server sees */
     for (x = 0; x < ALLCHANMSG_FUNCS_MAX; x++) {
        cf = (struct chanmsg_func *)&allchanmsg_funcs[x];
        if (!cf->func)
-         break; /* end of list */
+           break; /* end of list */
        else
-       cf->func(pd->user, cn, pd->text, cf->service);
+           cf->func(pd->user, cn, pd->text, cf->service);
     }
 }
 
index f602a98a958cc99c9c6ee4b4a77ff1a7b6de2209..96d3df60122b5d635441eda741e8dc18f54cd5a8 100644 (file)
@@ -1579,6 +1579,7 @@ init_parse(void)
     dict_insert(irc_func_dict, "401", cmd_dummy); /* target left network */
     dict_insert(irc_func_dict, "403", cmd_dummy); /* no such channel */
     dict_insert(irc_func_dict, "404", cmd_dummy); /* cannot send to channel */
+    dict_insert(irc_func_dict, "439", cmd_dummy); /* target change too fast */
     dict_insert(irc_func_dict, "441", cmd_dummy); /* target isn't on that channel */
     dict_insert(irc_func_dict, "442", cmd_dummy); /* you aren't on that channel */
     dict_insert(irc_func_dict, "443", cmd_dummy); /* is already on channel (after invite?) */
index fa446b212473853b969a1bd1fd56d7e77c4d7227..6b89f32f8d9192343c54fb24072ea5dd97145563 100644 (file)
         // How long is a channel unvisited (by masters or above) before it can be expired?
         "chan_expire_delay" "30d";
         // what !set options should we show when user calls "!set" with no arguments?
-        "set_shows" ("DefaultTopic", "TopicMask", "Greeting", "UserGreeting", "Modes", "PubCmd", "InviteMe", "UserInfo", "GiveVoice", "GiveOps", "EnfOps", "EnfModes", "EnfTopic", "TopicSnarf", "Setters", "CtcpUser", "CtcpReaction", "Protect", "Toys", "DynLimit", "NoDelete");
+        "set_shows" ("DefaultTopic", "TopicMask", "Greeting", "UserGreeting", "Modes", "PubCmd", "InviteMe", "StrictOp", "AutoOp", "EnfModes", "EnfTopic", "TopicSnarf", "UserInfo", "GiveVoice", "GiveOps", "EnfOps", "Setters", "CtcpUser", "CtcpReaction", "Protect", "Toys", "DynLimit", "NoDelete");
 
         // A list of !8ball responses
         "8ball" ("Not a chance.",