From 48b08787286d7d777611c7b1658d42d424b7df59 Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Mon, 31 Jan 2005 05:14:52 +0000 Subject: [PATCH] Add slab allocator; reduce delta with srvx-gs. 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 --- ChangeLog | 33 +++++ configure.in | 6 +- src/Makefile.am | 2 +- src/alloc-slab.c | 304 +++++++++++++++++++++++++++++++++++++++++++++ src/alloc-srvx.c | 12 +- src/chanserv.c | 31 +++-- src/chanserv.h | 2 +- src/common.h | 18 +++ src/hash.h | 4 +- src/helpfile.c | 2 +- src/log.c | 7 +- src/main.c | 10 +- src/modcmd.c | 21 ++-- src/opserv.c | 3 +- src/proto-common.c | 7 +- src/proto-p10.c | 1 + srvx.conf.example | 2 +- 17 files changed, 425 insertions(+), 40 deletions(-) create mode 100644 src/alloc-slab.c diff --git a/ChangeLog b/ChangeLog index 05846ca..e309721 100644 --- 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 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 patch-9 Summary: diff --git a/configure.in b/configure.in index 81dd91d..3df600b 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index 7fe7c1d..2ac28aa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000..b44f6a0 --- /dev/null +++ b/src/alloc-slab.c @@ -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 +#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); + } +} diff --git a/src/alloc-srvx.c b/src/alloc-srvx.c index 72fca5a..45fd15d 100644 --- a/src/alloc-srvx.c +++ b/src/alloc-srvx.c @@ -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 diff --git a/src/chanserv.c b/src/chanserv.c index c1d6f91..9f6c141 100644 --- a/src/chanserv.c +++ b/src/chanserv.c @@ -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; diff --git a/src/chanserv.h b/src/chanserv.h index d094595..b01a944 100644 --- a/src/chanserv.h +++ b/src/chanserv.h @@ -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]; }; diff --git a/src/common.h b/src/common.h index 5982512..e2ee167 100644 --- a/src/common.h +++ b/src/common.h @@ -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 diff --git a/src/hash.h b/src/hash.h index d10c35e..443f9f4 100644 --- a/src/hash.h +++ b/src/hash.h @@ -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; diff --git a/src/helpfile.c b/src/helpfile.c index d214fe3..e5aca29 100644 --- a/src/helpfile.c +++ b/src/helpfile.c @@ -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 diff --git a/src/log.c b/src/log.c index aefadbb..8e2600a 100644 --- 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; diff --git a/src/main.c b/src/main.c index c16aafa..215edcf 100644 --- a/src/main.c +++ b/src/main.c @@ -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(); diff --git a/src/modcmd.c b/src/modcmd.c index 95feb17..2ae4db5 100644 --- a/src/modcmd.c +++ b/src/modcmd.c @@ -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; diff --git a/src/opserv.c b/src/opserv.c index 87845c5..b3d19ac 100644 --- a/src/opserv.c +++ b/src/opserv.c @@ -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"); diff --git a/src/proto-common.c b/src/proto-common.c index 2233402..7226977 100644 --- a/src/proto-common.c +++ b/src/proto-common.c @@ -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); } } diff --git a/src/proto-p10.c b/src/proto-p10.c index f602a98..96d3df6 100644 --- a/src/proto-p10.c +++ b/src/proto-p10.c @@ -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?) */ diff --git a/srvx.conf.example b/srvx.conf.example index fa446b2..6b89f32 100644 --- a/srvx.conf.example +++ b/srvx.conf.example @@ -220,7 +220,7 @@ // 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.", -- 2.20.1