From 90b66dbe6c11ca5e4484f14cd223f1852c15e783 Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Wed, 14 Nov 2007 23:02:40 +0000 Subject: 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 --- src/irc/core/irc-servers.h | 2 +- src/irc/core/irc.c | 2 +- src/irc/core/servers-redirect.c | 99 ++++++++++++++++++++++++++++------------- src/irc/core/servers-redirect.h | 2 + 4 files changed, 72 insertions(+), 33 deletions(-) (limited to 'src/irc/core') 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); -- cgit v1.2.3