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