aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2010-01-09 11:41:41 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2010-01-09 11:41:41 +0000
commit0e91325e164b609f78e5454c85ec93860448ed1a (patch)
treeff2a72450e7f1738fdad5fa0f891cc95899fcf08
parent6feda46dcc18c1acb9483196351b0ebf23949cd8 (diff)
downloadsircbot-0e91325e164b609f78e5454c85ec93860448ed1a.tar.bz2
sircbot-0e91325e164b609f78e5454c85ec93860448ed1a.tar.xz
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.
-rw-r--r--sircbot.c100
1 files 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 <sys/poll.h>
+#include <sys/queue.h>
#include <errno.h>
#include <fcntl.h>
@@ -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 */