The sendq limit is now soft, now we halt processing if a sendq is exceeded, until it is sufficiently drained.
This allows us to implement SAFELIST and other floody commands without hacks.
int max_global;
int max_ident;
int max_sendq;
+ int max_sendq_hard;
int con_freq;
int ping_freq;
int total;
#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)
#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 *);
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;
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);
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;
+}
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.
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);