Re-think who_count management.
Should fix hard to trigger bug: fatal("negative who_count").
This commit is contained in:
parent
a7d21b2693
commit
5c17d27a95
141
src/irc.c
141
src/irc.c
@ -396,16 +396,44 @@ static int irc_315(struct link_server *server, struct line *l)
|
|||||||
{
|
{
|
||||||
struct link *link = LINK(server);
|
struct link *link = LINK(server);
|
||||||
if (link->who_client) {
|
if (link->who_client) {
|
||||||
--link->who_client->who_count;
|
if (link->who_client->who_count == 0) {
|
||||||
|
mylog(LOG_DEBUG, "Spurious irc_315");
|
||||||
if (link->who_client->who_count < 0)
|
return OK_COPY_WHO;
|
||||||
fatal("negative who count");
|
}
|
||||||
|
link->who_client->whoc_tstamp = time(NULL);
|
||||||
|
if (link->who_client->who_count > 0) {
|
||||||
|
--link->who_client->who_count;
|
||||||
|
mylog(LOG_INFO,
|
||||||
|
"RPL_ENDOFWHO: "
|
||||||
|
"Decrementing who count for %p: %d",
|
||||||
|
link->who_client, link->who_client->who_count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
l = NULL; /* keep gcc happy */
|
l = NULL; /* keep gcc happy */
|
||||||
|
|
||||||
return OK_COPY_WHO;
|
return OK_COPY_WHO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rotate_who_client(struct link *link)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
mylog(LOG_INFO, "rotate_who_client %p", link->who_client);
|
||||||
|
/* find a client with non-null who_count */
|
||||||
|
link->who_client = NULL;
|
||||||
|
for (i = 0; i < link->l_clientc; i++) {
|
||||||
|
struct link_client *ic = link->l_clientv[i];
|
||||||
|
if (!list_is_empty(&ic->who_queue)) {
|
||||||
|
char *l;
|
||||||
|
while ((l = list_remove_first(&ic->who_queue))) {
|
||||||
|
write_line(CONN(link->l_server), l);
|
||||||
|
free(l);
|
||||||
|
}
|
||||||
|
link->who_client = ic;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parses:join part mode kick kill privmsg quit nick names
|
* parses:join part mode kick kill privmsg quit nick names
|
||||||
* returns: -1 invalid protocol
|
* returns: -1 invalid protocol
|
||||||
@ -540,32 +568,12 @@ int irc_dispatch_server(struct link_server *server, struct line *line)
|
|||||||
s = irc_line_to_string(line);
|
s = irc_line_to_string(line);
|
||||||
write_line(CONN(LINK(server)->who_client), s);
|
write_line(CONN(LINK(server)->who_client), s);
|
||||||
free(s);
|
free(s);
|
||||||
|
}
|
||||||
if (LINK(server)->who_client->who_count == 0) {
|
if (LINK(server)->who_client &&
|
||||||
int i;
|
LINK(server)->who_client->who_count == 0) {
|
||||||
for (i = 0; i < LINK(server)->l_clientc; i++) {
|
mylog(LOG_INFO, "OK_COPY_WHO: who_count for %p is nul",
|
||||||
struct link_client *ic =
|
LINK(server)->who_client);
|
||||||
LINK(server)->l_clientv[i];
|
rotate_who_client(LINK(server));
|
||||||
if (ic == LINK(server)->who_client) {
|
|
||||||
if (!list_is_empty(&ic->who_queue))
|
|
||||||
fatal("who active and queued?");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!list_is_empty(&ic->who_queue)) {
|
|
||||||
char *l;
|
|
||||||
while ((l = list_remove_first(
|
|
||||||
&ic->who_queue))) {
|
|
||||||
write_line(CONN(server), l);
|
|
||||||
free(l);
|
|
||||||
}
|
|
||||||
LINK(server)->who_client = ic;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == LINK(server)->l_clientc)
|
|
||||||
LINK(server)->who_client = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -649,8 +657,16 @@ void unbind_from_link(struct link_client *ic)
|
|||||||
if (i == l->l_clientc)
|
if (i == l->l_clientc)
|
||||||
fatal("unbind_from_link");
|
fatal("unbind_from_link");
|
||||||
|
|
||||||
if (l->who_client == ic)
|
if (l->who_client == ic) {
|
||||||
|
mylog(LOG_INFO, "unbind_from_link: %p: %d",
|
||||||
|
l->who_client, ic->who_count);
|
||||||
l->who_client = NULL;
|
l->who_client = NULL;
|
||||||
|
} else {
|
||||||
|
mylog(LOG_INFO,
|
||||||
|
"unbind_from_link: nothing to do %p != %p: %d",
|
||||||
|
ic, l->who_client,
|
||||||
|
ic->who_count);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = i + 1; i < l->l_clientc; i++)
|
for (i = i + 1; i < l->l_clientc; i++)
|
||||||
l->l_clientv[i - 1] = l->l_clientv[i];
|
l->l_clientv[i - 1] = l->l_clientv[i];
|
||||||
@ -948,6 +964,12 @@ static int irc_cli_who(struct link_client *ic, struct line *line)
|
|||||||
{
|
{
|
||||||
struct link *l = LINK(ic);
|
struct link *l = LINK(ic);
|
||||||
|
|
||||||
|
++ic->who_count;
|
||||||
|
if (ic->who_count == 1)
|
||||||
|
ic->whoc_tstamp = time(NULL);
|
||||||
|
mylog(LOG_INFO, "cli_who: Incrementing who count for %p: %d",
|
||||||
|
ic, ic->who_count);
|
||||||
|
|
||||||
if (l->who_client && l->who_client != ic) {
|
if (l->who_client && l->who_client != ic) {
|
||||||
list_add_first(&ic->who_queue, irc_line_to_string(line));
|
list_add_first(&ic->who_queue, irc_line_to_string(line));
|
||||||
return OK_FORGET;
|
return OK_FORGET;
|
||||||
@ -956,8 +978,6 @@ static int irc_cli_who(struct link_client *ic, struct line *line)
|
|||||||
if (!l->who_client)
|
if (!l->who_client)
|
||||||
l->who_client = ic;
|
l->who_client = ic;
|
||||||
|
|
||||||
++ic->who_count;
|
|
||||||
|
|
||||||
return OK_COPY;
|
return OK_COPY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -973,6 +993,12 @@ static int irc_cli_mode(struct link_client *ic, struct line *line)
|
|||||||
strchr(line->elemv[2], 'b') == NULL)
|
strchr(line->elemv[2], 'b') == NULL)
|
||||||
return OK_COPY;
|
return OK_COPY;
|
||||||
|
|
||||||
|
++ic->who_count;
|
||||||
|
if (ic->who_count == 1)
|
||||||
|
ic->whoc_tstamp = time(NULL);
|
||||||
|
mylog(LOG_INFO, "cli_mode: Incrementing who count for %p: %d",
|
||||||
|
l->who_client, ic->who_count);
|
||||||
|
|
||||||
if (l->who_client && l->who_client != ic) {
|
if (l->who_client && l->who_client != ic) {
|
||||||
list_add_first(&ic->who_queue, irc_line_to_string(line));
|
list_add_first(&ic->who_queue, irc_line_to_string(line));
|
||||||
return OK_FORGET;
|
return OK_FORGET;
|
||||||
@ -981,8 +1007,6 @@ static int irc_cli_mode(struct link_client *ic, struct line *line)
|
|||||||
if (!l->who_client)
|
if (!l->who_client)
|
||||||
l->who_client = ic;
|
l->who_client = ic;
|
||||||
|
|
||||||
++ic->who_count;
|
|
||||||
|
|
||||||
return OK_COPY;
|
return OK_COPY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1486,10 +1510,19 @@ static int irc_368(struct link_server *server, struct line *l)
|
|||||||
{
|
{
|
||||||
struct link *link = LINK(server);
|
struct link *link = LINK(server);
|
||||||
if (link->who_client) {
|
if (link->who_client) {
|
||||||
--link->who_client->who_count;
|
if (link->who_client->who_count == 0) {
|
||||||
|
mylog(LOG_DEBUG, "Spurious irc_368");
|
||||||
|
return OK_COPY_WHO;
|
||||||
|
}
|
||||||
|
link->who_client->whoc_tstamp = time(NULL);
|
||||||
|
|
||||||
if (link->who_client->who_count < 0)
|
if (link->who_client->who_count > 0) {
|
||||||
fatal("negative who count");
|
--link->who_client->who_count;
|
||||||
|
mylog(LOG_INFO,
|
||||||
|
"RPL_ENDOFBANLIST: "
|
||||||
|
"Decrementing who count for %p: %d",
|
||||||
|
link->who_client, link->who_client->who_count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
l = NULL; /* keep gcc happy */
|
l = NULL; /* keep gcc happy */
|
||||||
|
|
||||||
@ -2202,6 +2235,29 @@ void oidentd_dump(list_t *connl)
|
|||||||
/* do not use */
|
/* do not use */
|
||||||
list_t *_connections = NULL;
|
list_t *_connections = NULL;
|
||||||
|
|
||||||
|
void timeout_clean_who_counts(list_t *conns)
|
||||||
|
{
|
||||||
|
list_iterator_t it;
|
||||||
|
for (list_it_init(conns, &it); list_it_item(&it); list_it_next(&it)) {
|
||||||
|
struct link *l = list_it_item(&it);
|
||||||
|
struct link_client *client = l->who_client;
|
||||||
|
|
||||||
|
if (client && client->whoc_tstamp) {
|
||||||
|
time_t now;
|
||||||
|
now = time(NULL);
|
||||||
|
if (now - client->whoc_tstamp > 10) {
|
||||||
|
mylog(LOG_DEBUG, "Yawn, "
|
||||||
|
"forgetting one who reply");
|
||||||
|
if (client->who_count > 0)
|
||||||
|
--client->who_count;
|
||||||
|
client->whoc_tstamp = time(NULL);
|
||||||
|
if (client->who_count == 0)
|
||||||
|
rotate_who_client(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct link_client *reloading_client;
|
struct link_client *reloading_client;
|
||||||
/*
|
/*
|
||||||
* The main loop
|
* The main loop
|
||||||
@ -2268,8 +2324,10 @@ void irc_main(connection_t *inc, list_t *ll)
|
|||||||
struct link *link;
|
struct link *link;
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
|
|
||||||
/* Compute timeouts for next reconnections and lagouts */
|
|
||||||
if (timeleft == 0) {
|
if (timeleft == 0) {
|
||||||
|
/*
|
||||||
|
* Compute timeouts for next reconnections and lagouts
|
||||||
|
*/
|
||||||
static int throttle_prot = S_CONN_DELAY - 1;
|
static int throttle_prot = S_CONN_DELAY - 1;
|
||||||
|
|
||||||
timeleft = 1000;
|
timeleft = 1000;
|
||||||
@ -2328,6 +2386,11 @@ void irc_main(connection_t *inc, list_t *ll)
|
|||||||
list_it_remove(&li);
|
list_it_remove(&li);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cleanup lagging or dangling who_count buffers
|
||||||
|
*/
|
||||||
|
timeout_clean_who_counts(ll);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nc;
|
int nc;
|
||||||
|
@ -155,6 +155,7 @@ struct link_client {
|
|||||||
|
|
||||||
list_t who_queue;
|
list_t who_queue;
|
||||||
int who_count;
|
int who_count;
|
||||||
|
time_t whoc_tstamp;
|
||||||
|
|
||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
int allow_trust;
|
int allow_trust;
|
||||||
|
@ -459,7 +459,7 @@ static unsigned char hash_func(char *pkey)
|
|||||||
char c;
|
char c;
|
||||||
unsigned long hash = 5381; /* 5381 & 0xff makes more sense */
|
unsigned long hash = 5381; /* 5381 & 0xff makes more sense */
|
||||||
|
|
||||||
while (c = *pkey++)
|
while ((c = *pkey++))
|
||||||
hash = ((hash << 5) + hash) ^ c;
|
hash = ((hash << 5) + hash) ^ c;
|
||||||
return (unsigned char)hash;
|
return (unsigned char)hash;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user