From 0e91325e164b609f78e5454c85ec93860448ed1a Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Sat, 9 Jan 2010 11:41:41 +0000 Subject: dont send more than one line per second to any channel We want avoid getting kicked out for flooding channels, so we read from he FIFO and store data in a queue. We then flush the queue, line by line each second. --- sircbot.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/sircbot.c b/sircbot.c index f2d9d76..7341cc2 100644 --- a/sircbot.c +++ b/sircbot.c @@ -7,6 +7,7 @@ Intended usage is git hook that sends commits, etc. #define _GNU_SOURCE #include +#include #include #include @@ -26,12 +27,22 @@ Intended usage is git hook that sends commits, etc. #define DEFAULT_PIDFILE "/var/run/" PROGNAME "/" PROGNAME ".pid" #endif +struct tq_string { + char *value; + TAILQ_ENTRY(tq_string) entries; +}; + +typedef TAILQ_HEAD(tq_stringlist, tq_string) TQ_STRINGLIST; + struct sircbot_channel { char *name; char *fifo; int fd; + time_t last_data_sent; + TQ_STRINGLIST queue_head; /* queue of in-data */ }; + static int foreground = 0; static int sigterm = 0; @@ -90,6 +101,21 @@ static void log_err(const char *msg) syslog(LOG_ERR, "%s: %s", msg, strerror(errno)); } +struct tq_string *tq_stringlist_add(TQ_STRINGLIST *list, const char *data) +{ + struct tq_string *item = malloc(sizeof(struct tq_string)); + if (item == NULL) { + log_err("malloc"); + return NULL; + } + if ((item->value = strdup(data)) == NULL) { + log_err("strdup"); + return NULL; + } + TAILQ_INSERT_TAIL(list, item, entries); + return item; +} + int init_fifo(struct sircbot_channel *chan) { unlink(chan->fifo); @@ -211,6 +237,38 @@ int parse_irc_data(char *buf, struct sircbot_channel *chan, int numchan, return 0; } +/* init pollfd strucs */ +static void irc_reset_pollfds(struct irc_session *sess, struct pollfd *fds, + struct sircbot_channel *chan, int numchan) +{ + int i; + /* first pollfd struc is the irc session */ + fds[0].fd = sess->fd; + fds[0].events = POLLIN; + fds[0].revents = 0; + /* rest is channel fifos */ + for (i = 1; i < numchan + 1; i++) { + fds[i].fd = chan[i-1].fd; + fds[i].events = POLLIN; + fds[i].revents = 0; + } +} + +static int send_fifo_queue(struct irc_session *sess, + struct sircbot_channel *chan, time_t now) +{ + int r; + struct tq_string *item = TAILQ_FIRST(&chan->queue_head); + if (item == NULL || chan->last_data_sent == now) + return 0; /* nothing in queue, or too early to send */ + + r = irc_send_chan(sess, chan->name, item->value); + /* remove from FIFO queue */ + TAILQ_REMOVE(&chan->queue_head, item, entries); + free(item->value); + free(item); + return r; +} static int irc_loop(struct irc_session *sess, struct sircbot_channel *chan, int numchan) { @@ -219,38 +277,41 @@ static int irc_loop(struct irc_session *sess, struct sircbot_channel *chan, struct pollfd fds[numchan + 1]; sigset_t sigmask; struct timespec tv; + time_t now, last_ping; for (i = 0; i < numchan; i++) irc_send(sess, "JOIN", chan[i].name); sigemptyset(&sigmask); sigaddset(&sigmask, SIGTERM); - tv.tv_sec = 120; + tv.tv_sec = 1; tv.tv_nsec = 0; while (!sigterm) { - /* init pollfd strucs */ - fds[0].fd = sess->fd; - fds[0].events = POLLIN; - fds[0].revents = 0; - for (i = 1; i < numchan + 1; i++) { - fds[i].fd = chan[i-1].fd; - fds[i].events = POLLIN; - fds[i].revents = 0; - } - //r = ppoll(fds, numchan+1, &tv, &sigmask); - r = poll(fds, numchan+1, 120000); + irc_reset_pollfds(sess, fds, chan, numchan); + r = ppoll(fds, numchan+1, &tv, &sigmask); +// r = poll(fds, numchan+1, 120000); if (r < 0) { - log_err("poll"); + log_err("ppoll"); return -1; - } else if (r == 0) { - /* timeout */ + } + now = time(NULL); + + /* send a ping every 2 min */ + if ((now - last_ping) > 120) { irc_send_ping(sess); - continue; + last_ping = now; } + for (i = 0; i < numchan + 1; i++) { int j; + + /* send data in queue for this fifo */ + if (i != 0 && + send_fifo_queue(sess, &chan[i-1], now) < 0) + goto ret_err; + if (!(fds[i].revents & POLLIN)) - continue; + continue; /* no data available for read */ printf("DEBUG: data available from fds[%i]\n", i); r = read(fds[i].fd, buf, sizeof(buf)-1); @@ -269,9 +330,7 @@ static int irc_loop(struct irc_session *sess, struct sircbot_channel *chan, /* data was from fifos */ printf("DEBUG: data from fifo %s: %s\n", chan[i-1].name, buf); - r = irc_send_chan(sess, chan[i-1].name, buf); - if (r < 0) - goto ret_err; + tq_stringlist_add(&chan[i-1].queue_head, buf); } } return 0; @@ -343,6 +402,7 @@ int main(int argc, char *argv[]) chan[i].name = strdup(argv[i]); asprintf(&chan[i].fifo, "/var/run/sircbot/%s", argv[i]); unlink(chan[i].fifo); + TAILQ_INIT(&chan[i].queue_head); } /* daemonize */ -- cgit v1.2.3