summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJilles Tjoelker <jilles@irssi.org>2007-11-14 23:02:40 +0000
committerjilles <jilles@dbcabf3a-b0e7-0310-adc4-f8d773084564>2007-11-14 23:02:40 +0000
commit90b66dbe6c11ca5e4484f14cd223f1852c15e783 (patch)
treeb2ac294e433083c167b325a60902589afcbe88ad
parentfabecae6e640f62734d4e5711f1f4a49658c2993 (diff)
downloadirssi-90b66dbe6c11ca5e4484f14cd223f1852c15e783.zip
Rework redirections to deal with multiple concurrent redirects better.
These mostly happen when doing remote whois and the target server is slow. The code uses the source server but will try to do what it can if servers think they need to mask it. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@4638 dbcabf3a-b0e7-0310-adc4-f8d773084564
-rw-r--r--src/irc/core/irc-servers.h2
-rw-r--r--src/irc/core/irc.c2
-rw-r--r--src/irc/core/servers-redirect.c99
-rw-r--r--src/irc/core/servers-redirect.h2
-rw-r--r--src/irc/proxy/listen.c4
-rw-r--r--src/perl/irc/Server.xs10
6 files changed, 80 insertions, 39 deletions
diff --git a/src/irc/core/irc-servers.h b/src/irc/core/irc-servers.h
index 7352b876..cdf5721e 100644
--- a/src/irc/core/irc-servers.h
+++ b/src/irc/core/irc-servers.h
@@ -42,7 +42,7 @@ struct _IRC_SERVER_REC {
GSList *redirects;
GSList *redirect_queue; /* should be updated from redirect_next each time cmdqueue is updated */
REDIRECT_REC *redirect_next;
- REDIRECT_REC *redirect_continue;
+ GSList *redirect_active; /* redirects start event has been received for, must have unique prefix */
char *last_nick; /* last /NICK, kept even if it resulted as not valid change */
diff --git a/src/irc/core/irc.c b/src/irc/core/irc.c
index 797923be..bcee0987 100644
--- a/src/irc/core/irc.c
+++ b/src/irc/core/irc.c
@@ -303,7 +303,7 @@ static void irc_server_event(IRC_SERVER_REC *server, const char *line,
g_strdown(event);
/* check if event needs to be redirected */
- signal = server_redirect_get_signal(server, event, args);
+ signal = server_redirect_get_signal(server, recoded_nick, event, args);
if (signal == NULL)
signal = event;
else
diff --git a/src/irc/core/servers-redirect.c b/src/irc/core/servers-redirect.c
index 24b9f98d..fb540c3a 100644
--- a/src/irc/core/servers-redirect.c
+++ b/src/irc/core/servers-redirect.c
@@ -46,6 +46,7 @@ struct _REDIRECT_REC {
REDIRECT_CMD_REC *cmd;
time_t created;
int failures;
+ char *prefix;
unsigned int destroyed:1;
unsigned int aborted:1;
@@ -110,6 +111,7 @@ void server_redirect_destroy(REDIRECT_REC *rec)
{
redirect_cmd_unref(rec->cmd);
+ g_free_not_null(rec->prefix);
g_free_not_null(rec->arg);
g_free_not_null(rec->failure_signal);
g_free_not_null(rec->default_signal);
@@ -386,13 +388,29 @@ static const char *redirect_match(REDIRECT_REC *redirect, const char *event,
else {
cmdpos = redirect_cmd_list_find(redirect->cmd->stop,
event);
- match_list = cmdpos != NULL ? MATCH_STOP : MATCH_NONE;
+ if (cmdpos != NULL)
+ match_list = MATCH_STOP;
+ else if (redirect->default_signal != NULL &&
+ args == NULL &&
+ strncmp(event, "event ", 6) == 0 &&
+ i_isdigit(event[6])) {
+ /* If there is a default signal, the
+ * redirection has already started and
+ * this is a numeric, use it */
+ /* XXX this should depend on the
+ * REDIRECT_CMD_REC, not REDIRECT_REC */
+ if (signal == NULL)
+ signal = redirect->default_signal;
+ match_list = MATCH_START;
+ } else {
+ match_list = MATCH_NONE;
+ }
}
}
if (signal == NULL && cmdpos == NULL) {
/* event not found from specified redirection events nor
- registered command events */
+ registered command events, and no default signal */
return NULL;
}
@@ -428,8 +446,7 @@ static void redirect_abort(IRC_SERVER_REC *server, REDIRECT_REC *rec)
signal_emit(rec->last_signal, 1, server);
}
- if (server->redirect_continue == rec)
- server->redirect_continue = NULL;
+ server->redirect_active = g_slist_remove(server->redirect_active, rec);
server_redirect_destroy(rec);
}
@@ -452,6 +469,10 @@ static REDIRECT_REC *redirect_find(IRC_SERVER_REC *server, const char *event,
for (tmp = server->redirects; tmp != NULL; tmp = tmp->next) {
REDIRECT_REC *rec = tmp->data;
+ /* already active, don't try to start it again */
+ if (g_slist_find(server->redirect_active, rec) != NULL)
+ continue;
+
match_signal = redirect_match(rec, event, args, match);
if (match_signal != NULL && *match != MATCH_NONE) {
redirect = rec;
@@ -488,10 +509,13 @@ static REDIRECT_REC *redirect_find(IRC_SERVER_REC *server, const char *event,
}
static const char *
-server_redirect_get(IRC_SERVER_REC *server, const char *event,
- const char *args, REDIRECT_REC **redirect, int *match)
+server_redirect_get(IRC_SERVER_REC *server, const char *prefix,
+ const char *event, const char *args,
+ REDIRECT_REC **redirect, int *match)
{
const char *signal;
+ GSList *ptr, *next;
+ REDIRECT_REC *r;
*redirect = NULL;
*match = MATCH_NONE;
@@ -499,33 +523,39 @@ server_redirect_get(IRC_SERVER_REC *server, const char *event,
if (server->redirects == NULL)
return NULL;
- if (server->redirect_continue == NULL) {
- /* find the redirection */
- *redirect = redirect_find(server, event, args, &signal, match);
- } else {
+ for (ptr = server->redirect_active; ptr != NULL; ptr = next) {
+ next = ptr->next;
+ r = ptr->data;
+ if (prefix != NULL && r->prefix != NULL &&
+ strcmp(prefix, r->prefix)) {
+ /* not from this server */
+ continue;
+ }
/* redirection is already started, now we'll just need to
keep redirecting until stop-event is found. */
- *redirect = server->redirect_continue;
+ *redirect = r;
signal = redirect_match(*redirect, event, NULL, match);
if (signal == NULL) {
- /* unknown event - redirect to the default signal. */
- if (strncmp(event, "event ", 6) == 0 &&
- i_isdigit(event[6])) {
- signal = (*redirect)->default_signal;
- if (*match == MATCH_NONE)
- *match = MATCH_START;
- } else {
- /* not a numeric, so we've lost the
- stop event.. */
- (*redirect)->aborted = TRUE;
- redirect_abort(server, *redirect);
+ /* not a numeric, so we've lost the
+ stop event.. */
+ (*redirect)->aborted = TRUE;
+ redirect_abort(server, *redirect);
- *redirect = NULL;
- signal = NULL;
- }
+ *redirect = NULL;
}
+ if (*redirect != NULL)
+ break;
+ }
+
+ if (*redirect == NULL) {
+ /* find the redirection */
+ *redirect = redirect_find(server, event, args, &signal, match);
}
+ /* remember which server is replying to our request */
+ if (*redirect != NULL && prefix != NULL && (*redirect)->prefix == NULL)
+ (*redirect)->prefix = g_strdup(prefix);
+
if (*redirect != NULL && (*redirect)->first_signal != NULL &&
!(*redirect)->first_signal_sent) {
/* emit the first_signal */
@@ -537,6 +567,7 @@ server_redirect_get(IRC_SERVER_REC *server, const char *event,
}
const char *server_redirect_get_signal(IRC_SERVER_REC *server,
+ const char *prefix,
const char *event,
const char *args)
{
@@ -544,22 +575,26 @@ const char *server_redirect_get_signal(IRC_SERVER_REC *server,
const char *signal;
int match;
- signal = server_redirect_get(server, event, args, &redirect, &match);
- if (match != MATCH_STOP || redirect == NULL)
- server->redirect_continue = redirect;
- else {
+ signal = server_redirect_get(server, prefix, event, args, &redirect, &match);
+ if (redirect == NULL)
+ ;
+ else if (match != MATCH_STOP) {
+ if (g_slist_find(server->redirect_active, redirect) == NULL)
+ server->redirect_active = g_slist_prepend(server->redirect_active, redirect);
+ } else {
/* stop event - remove this redirection next time this
function is called (can't destroy now or our return
value would be corrupted) */
if (--redirect->count <= 0)
redirect->destroyed = TRUE;
- server->redirect_continue = NULL;
+ server->redirect_active = g_slist_remove(server->redirect_active, redirect);
}
return signal;
}
const char *server_redirect_peek_signal(IRC_SERVER_REC *server,
+ const char *prefix,
const char *event,
const char *args,
int *redirected)
@@ -568,7 +603,7 @@ const char *server_redirect_peek_signal(IRC_SERVER_REC *server,
const char *signal;
int match;
- signal = server_redirect_get(server, event, args, &redirect, &match);
+ signal = server_redirect_get(server, prefix, event, args, &redirect, &match);
*redirected = match != MATCH_NONE;
return signal;
}
@@ -578,6 +613,8 @@ static void sig_disconnected(IRC_SERVER_REC *server)
if (!IS_IRC_SERVER(server))
return;
+ g_slist_free(server->redirect_active);
+ server->redirect_active = NULL;
g_slist_foreach(server->redirects,
(GFunc) server_redirect_destroy, NULL);
g_slist_free(server->redirects);
diff --git a/src/irc/core/servers-redirect.h b/src/irc/core/servers-redirect.h
index c9be1613..6182e3ab 100644
--- a/src/irc/core/servers-redirect.h
+++ b/src/irc/core/servers-redirect.h
@@ -64,6 +64,7 @@ void server_redirect_command(IRC_SERVER_REC *server, const char *command,
/* Returns the redirection signal for specified event.
This is the function that contains the real redirecting logic. */
const char *server_redirect_get_signal(IRC_SERVER_REC *server,
+ const char *prefix,
const char *event,
const char *args);
/* Returns the redirection signal for specified event.
@@ -72,6 +73,7 @@ const char *server_redirect_get_signal(IRC_SERVER_REC *server,
`redirected' is set to TRUE, if this event belongs to redirection even
while there might be no redirection signal. */
const char *server_redirect_peek_signal(IRC_SERVER_REC *server,
+ const char *prefix,
const char *event,
const char *args,
int *redirected);
diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c
index c250ed16..bab08421 100644
--- a/src/irc/proxy/listen.c
+++ b/src/irc/proxy/listen.c
@@ -391,7 +391,7 @@ static void sig_server_event(IRC_SERVER_REC *server, const char *line,
while (*args == ' ') args++;
g_strdown(event);
- signal = server_redirect_peek_signal(server, event, args, &redirected);
+ signal = server_redirect_peek_signal(server, nick, event, args, &redirected);
if ((signal != NULL && strncmp(signal, "proxy ", 6) != 0) ||
(signal == NULL && redirected)) {
/* we want to send this to one client (or proxy itself) only */
@@ -401,7 +401,7 @@ static void sig_server_event(IRC_SERVER_REC *server, const char *line,
}
if (signal != NULL) {
- server_redirect_get_signal(server, event, args);
+ server_redirect_get_signal(server, nick, event, args);
if (sscanf(signal+6, "%p", &client) == 1) {
/* send it to specific client only */
if (g_slist_find(proxy_clients, client) != NULL)
diff --git a/src/perl/irc/Server.xs b/src/perl/irc/Server.xs
index a3359bbc..a330fb20 100644
--- a/src/perl/irc/Server.xs
+++ b/src/perl/irc/Server.xs
@@ -116,24 +116,26 @@ CODE:
event_hash2list(hvref(signals)));
char *
-server_redirect_get_signal(server, event, args)
+server_redirect_get_signal(server, prefix, event, args)
Irssi::Irc::Server server
+ char *prefix
char *event
char *args
CODE:
- RETVAL = (char *) server_redirect_get_signal(server, event, args);
+ RETVAL = (char *) server_redirect_get_signal(server, prefix, event, args);
OUTPUT:
RETVAL
char *
-server_redirect_peek_signal(server, event, args)
+server_redirect_peek_signal(server, prefix, event, args)
Irssi::Irc::Server server
+ char *prefix
char *event
char *args
PREINIT:
int redirection;
CODE:
- RETVAL = (char *) server_redirect_peek_signal(server, event, args, &redirection);
+ RETVAL = (char *) server_redirect_peek_signal(server, prefix, event, args, &redirection);
OUTPUT:
RETVAL