diff --git a/include/class.h b/include/class.h index c076c185a..33b99e73f 100644 --- a/include/class.h +++ b/include/class.h @@ -40,6 +40,7 @@ struct Class int max_global; int max_ident; int max_sendq; + int max_sendq_hard; int con_freq; int ping_freq; int total; @@ -61,6 +62,7 @@ extern struct Class *default_class; #define MaxUsers(x) ((x)->max_total) #define PingFreq(x) ((x)->ping_freq) #define MaxSendq(x) ((x)->max_sendq) +#define MaxSendqHard(x) ((x)->max_sendq_hard) #define CurrUsers(x) ((x)->total) #define IpLimits(x) ((x)->ip_limits) #define CidrIpv4Bitlen(x) ((x)->cidr_ipv4_bitlen) @@ -81,12 +83,14 @@ extern struct Class *default_class; #define ConfCidrAmount(x) (ClassPtr(x)->cidr_amount) #define ConfCidrIpv4Bitlen(x) (ClassPtr(x)->cidr_ipv4_bitlen) #define ConfCidrIpv6Bitlen(x) (ClassPtr(x)->cidr_ipv6_bitlen) +#define ConfMaxSendqHard(x) (ClassPtr(x)->max_sendq_hard) void add_class(struct Class *); struct Class *make_class(void); extern long get_sendq(struct Client *); +extern long get_sendq_hard(struct Client *); extern int get_con_freq(struct Class *); extern struct Class *find_class(const char *); extern const char *get_client_class(struct Client *); diff --git a/ircd/class.c b/ircd/class.c index a7eb528ac..25a7f53f9 100644 --- a/ircd/class.c +++ b/ircd/class.c @@ -55,6 +55,7 @@ make_class(void) PingFreq(tmp) = DEFAULT_PINGFREQUENCY; MaxUsers(tmp) = 1; MaxSendq(tmp) = DEFAULT_SENDQ; + MaxSendqHard(tmp) = DEFAULT_SENDQ * 4; tmp->ip_limits = rb_new_patricia(PATRICIA_BITS); return tmp; @@ -198,6 +199,7 @@ add_class(struct Class *classptr) MaxIdent(tmpptr) = MaxIdent(classptr); PingFreq(tmpptr) = PingFreq(classptr); MaxSendq(tmpptr) = MaxSendq(classptr); + MaxSendqHard(tmpptr) = MaxSendq(classptr) * 4; ConFreq(tmpptr) = ConFreq(classptr); CidrIpv4Bitlen(tmpptr) = CidrIpv4Bitlen(classptr); CidrIpv6Bitlen(tmpptr) = CidrIpv6Bitlen(classptr); @@ -342,3 +344,33 @@ get_sendq(struct Client *client_p) return DEFAULT_SENDQ; } + +/* + * get_sendq_hard + * + * inputs - pointer to client + * output - hard sendq limit for this client as found from its class + * side effects - NONE + */ +long +get_sendq_hard(struct Client *client_p) +{ + if(client_p == NULL || IsMe(client_p)) + return DEFAULT_SENDQ; + + if(IsServer(client_p)) + { + struct server_conf *server_p; + server_p = client_p->localClient->att_sconf; + return MaxSendqHard(server_p->class); + } + else + { + struct ConfItem *aconf = client_p->localClient->att_conf; + + if(aconf != NULL && aconf->status & CONF_CLIENT) + return ConfMaxSendqHard(aconf); + } + + return DEFAULT_SENDQ; +} diff --git a/ircd/packet.c b/ircd/packet.c index fe18b1df8..9ee4f7aae 100644 --- a/ircd/packet.c +++ b/ircd/packet.c @@ -108,11 +108,23 @@ parse_client_queued(struct Client *client_p) else allow_read = ConfigFileEntry.client_flood_burst_rate; allow_read *= ConfigFileEntry.client_flood_message_time; + /* allow opers 4 times the amount of messages as users. why 4? * why not. :) --fl_ */ if(IsOper(client_p) && ConfigFileEntry.no_oper_flood) allow_read *= 4; + else + { + /* + * If a client's sendq is greater than the soft limit, do not allow any + * more messages to be read. This allows us to safely handle commands like + * LIST without harming the server. --kaniini + */ + if (rb_linebuf_len(&client_p->localClient->buf_sendq) > (get_sendq(client_p))) + allow_read = 0; + } + /* * Handle flood protection here - if we exceed our flood limit on * messages in this loop, we simply drop out of the loop prematurely. diff --git a/ircd/send.c b/ircd/send.c index cb2112054..a15d9d642 100644 --- a/ircd/send.c +++ b/ircd/send.c @@ -69,20 +69,20 @@ _send_linebuf(struct Client *to, buf_head_t *linebuf) if(!MyConnect(to) || IsIOError(to)) return 0; - if(rb_linebuf_len(&to->localClient->buf_sendq) > get_sendq(to)) + if(rb_linebuf_len(&to->localClient->buf_sendq) > get_sendq_hard(to)) { if(IsServer(to)) { sendto_realops_snomask(SNO_GENERAL, L_ALL, - "Max SendQ limit exceeded for %s: %u > %lu", + "Hard SendQ limit exceeded for %s: %u > %lu", to->name, rb_linebuf_len(&to->localClient->buf_sendq), - get_sendq(to)); + get_sendq_hard(to)); - ilog(L_SERVER, "Max SendQ limit exceeded for %s: %u > %lu", + ilog(L_SERVER, "Hard SendQ limit exceeded for %s: %u > %lu", log_client_name(to, SHOW_IP), rb_linebuf_len(&to->localClient->buf_sendq), - get_sendq(to)); + get_sendq_hard(to)); } dead_link(to, 1);