src/irc_queue.h
changeset 90 9d489b1039b2
child 155 c59d3eaff0fb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/irc_queue.h	Mon Mar 30 16:31:24 2009 +0300
@@ -0,0 +1,84 @@
+#ifndef IRC_QUEUE_H
+#define IRC_QUEUE_H
+
+/**
+ * @file
+ *
+ * Ratelimited queue of outgoing irc_line's for use with irc_conn.
+ *
+ * This implements the basic flood control algorithm as described in RFC1459 section 8.10.
+ */
+#include "irc_line.h"
+#include "line_proto.h"
+#include "error.h"
+
+#include <sys/queue.h>
+#include <event2/event.h>
+
+/**
+ * Number of seconds of penalty applied for each message
+ */
+#define IRC_QUEUE_PENALTY 2
+
+/**
+ * Maximum allowed burst, in seconds
+ */
+#define IRC_QUEUE_WINDOW 10
+
+/**
+ * An enqueued irc_line for later delivery
+ */
+struct irc_queue_entry {
+    /** The formatted irc_line data, including terminating CRLF */
+    char line_buf[IRC_LINE_MAX + 2];
+
+    /** Our entry in the irc_queue list */
+    TAILQ_ENTRY(irc_queue_entry) queue_list;
+};
+
+/**
+ * The queue state and timing algorithm, as described in the RFC:
+ *  * A line will be sent directly if the current timer is less than IRC_QUEUE_WINDOW seconds into the future, and
+ *    IRC_QUEUE_PENALTY seconds are added on to the timer.
+ *  * Otherwise, the line is stored as a irc_queue_entry and enqueued for later transmission, once the timer value
+ *    drops below IRC_QUEUE_WINDOW seconds into the future.
+ *  * The above is repeated for each dequeued line.
+ *
+ * Additionally, if sending a line fails due to the line_proto socket buffer being full, this also handles this case
+ * by queueing the line for later sending.
+ *
+ * Note that the timing behaviour of this is rather unexact - the socket layer may introduce its own delays/jitter which
+ * we can't measure or control here, but at least we make an effort. This should work OK as long as the outgoing lines
+ * don't accumulate in the socket's write buffer too much. XXX: maybe tweak socket params to try and "disable" 
+ * buffering on our end to improve accuracy?
+ */
+struct irc_queue {
+    /** The line_proto that we can send the messages out on */
+    struct line_proto *lp;
+
+    /** Our timeout used for delaying messages */
+    struct event *ev;
+
+    /** Current "message timer" value, may be up to IRC_QUEUE_WINDOW seconds in the future */
+    time_t timer;
+
+    /** The actual queue of messages */
+    TAILQ_HEAD(irc_queue_entry_list, irc_queue_entry) list;
+};
+
+/**
+ * Create a new irc_queue for use with the given line_proto
+ */
+err_t irc_queue_create (struct irc_queue **queue_ptr, struct line_proto *lp, struct error_info *err);
+
+/**
+ * Process a line, either sending it directly, or enqueueing it, based on the timer state.
+ */
+err_t irc_queue_process (struct irc_queue *queue, const struct irc_line *line);
+
+/**
+ * Destroy the irc_queue, releasing all queued lines
+ */
+void irc_queue_destroy (struct irc_queue *queue);
+
+#endif /* IRC_QUEUE_H */