diff options
author | June McEnroe <june@causal.agency> | 2020-05-11 18:05:41 -0400 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2020-05-11 18:16:19 -0400 |
commit | 548c4a3a86a37cf74aac5ef91f84b9a762dc1023 (patch) | |
tree | 810cdf6ea4d26421f4b2a36f3a35bda745fec628 /server.c | |
parent | Pass -1 as backlog to listen(2) (diff) | |
download | pounce-548c4a3a86a37cf74aac5ef91f84b9a762dc1023.tar.gz pounce-548c4a3a86a37cf74aac5ef91f84b9a762dc1023.zip |
Add server send queueing with time interval
This addresses pounce getting killed with "Excess flood" when it sends NAMES commands for too many channels when a client connects. These commands, as well as automatic AWAY commands, are by default throttled to 5 per second. Tested on freenode with 36 channels and 200ms interval.
Diffstat (limited to '')
-rw-r--r-- | server.c | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/server.c b/server.c index 20d94e3..1edeab5 100644 --- a/server.c +++ b/server.c @@ -148,6 +148,46 @@ void serverFormat(const char *format, ...) { serverSend(buf, len); } +enum { QueueCap = 256 }; +static struct { + size_t enq; + size_t deq; + char *msgs[QueueCap]; +} queue; + +void serverDequeue(void) { + if (queue.enq - queue.deq) { + char *msg = queue.msgs[queue.deq++ % QueueCap]; + serverSend(msg, strlen(msg)); + free(msg); + } else { + struct itimerval timer = { .it_value = {0} }; + int error = setitimer(ITIMER_REAL, &timer, NULL); + if (error) err(EX_OSERR, "setitimer"); + } +} + +struct timeval serverQueueInterval = { .tv_usec = 1000 * 200 }; + +void serverEnqueue(const char *format, ...) { + if (queue.enq - queue.deq == QueueCap) { + warnx("server send queue full"); + serverDequeue(); + } else if (queue.enq == queue.deq) { + struct itimerval timer = { + .it_interval = serverQueueInterval, + .it_value = { .tv_usec = 1 }, + }; + int error = setitimer(ITIMER_REAL, &timer, NULL); + if (error) err(EX_OSERR, "setitimer"); + } + va_list ap; + va_start(ap, format); + int len = vasprintf(&queue.msgs[queue.enq++ % QueueCap], format, ap); + va_end(ap); + if (len < 0) err(EX_OSERR, "vasprintf"); +} + void serverRecv(void) { static char buf[MessageCap]; static size_t len; |