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 /bounce.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-- | bounce.c | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/bounce.c b/bounce.c index dd5d723..6ddc023 100644 --- a/bounce.c +++ b/bounce.c @@ -31,6 +31,7 @@ #include <sys/file.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/time.h> #include <sysexits.h> #include <tls.h> #include <unistd.h> @@ -111,6 +112,16 @@ static size_t parseSize(const char *str) { return size; } +static struct timeval parseInterval(const char *str) { + char *rest; + long ms = strtol(str, &rest, 0); + if (*rest) errx(EX_USAGE, "invalid interval: %s", str); + return (struct timeval) { + .tv_sec = ms / 1000, + .tv_usec = 1000 * (ms % 1000), + }; +} + static FILE *saveFile; static void saveSave(void) { @@ -280,6 +291,7 @@ int main(int argc, char *argv[]) { { .val = 'K', .name = "local-priv", required_argument }, { .val = 'N', .name = "no-names", no_argument }, { .val = 'P', .name = "local-port", required_argument }, + { .val = 'Q', .name = "queue-interval", required_argument }, { .val = 'S', .name = "bind", required_argument }, { .val = 'T', .name = "no-sts", no_argument }, { .val = 'U', .name = "local-path", required_argument }, @@ -329,6 +341,7 @@ int main(int argc, char *argv[]) { break; case 'K': strlcpy(privPath, optarg, sizeof(privPath)); break; case 'N': stateNoNames = true; break; case 'P': bindPort = optarg; + break; case 'Q': serverQueueInterval = parseInterval(optarg); break; case 'S': serverBindHost = optarg; break; case 'T': clientSTS = false; break; case 'U': strlcpy(bindPath, optarg, sizeof(bindPath)); @@ -447,6 +460,7 @@ int main(int argc, char *argv[]) { signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); signal(SIGPIPE, SIG_IGN); + signal(SIGALRM, signalHandler); signal(SIGINFO, signalHandler); signal(SIGUSR1, signalHandler); @@ -509,18 +523,23 @@ int main(int argc, char *argv[]) { if (signals[SIGINT] || signals[SIGTERM]) break; + if (signals[SIGALRM]) { + signals[SIGALRM] = 0; + serverDequeue(); + } + if (signals[SIGINFO]) { - ringInfo(); signals[SIGINFO] = 0; + ringInfo(); } if (signals[SIGUSR1]) { + signals[SIGUSR1] = 0; cert = splitOpen(certSplit); priv = splitOpen(privSplit); localConfig(cert, priv, localCA, !clientPass); fclose(cert); fclose(priv); - signals[SIGUSR1] = 0; } } |