#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 event_base *ev_base, 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 */