summary refs log tree commit diff
path: root/server.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-05-11 18:05:41 -0400
committerJune McEnroe <june@causal.agency>2020-05-11 18:16:19 -0400
commit548c4a3a86a37cf74aac5ef91f84b9a762dc1023 (patch)
tree810cdf6ea4d26421f4b2a36f3a35bda745fec628 /server.c
parentPass -1 as backlog to listen(2) (diff)
downloadpounce-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.c40
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;