From 0bea530df3f718b34a1022a871f4f78a41c2bee6 Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Wed, 12 Jun 2019 21:29:28 +0100 Subject: Handle failing to reconnect to the server upon timeout or disconnection by looping the reconnection and keeping clients informed. --- TODO | 6 +++-- blabouncer.c | 75 +++++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/TODO b/TODO index 4c106d8..cfd260b 100644 --- a/TODO +++ b/TODO @@ -7,6 +7,8 @@ Add various auto replay options: Might need to #include in blabouncer.c to make some operating systems and/or compilers happy. -Handle re-connecting to the server failing. - Allow reloading the configuration file while running (at least for things like replayseconds, replaymode) - BLABOUNCER command and SIGHUP? + +Don't pass server PONGs to clients. + +"error: createchannel(): channel name already exists.\n: Success" printed to terminal upon server reconnection. diff --git a/blabouncer.c b/blabouncer.c index c416c3e..bbb22cd 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -492,6 +492,8 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { snprintf(outgoingmsg, MAXDATASIZE, "PING timeouttest"); } sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, clients, settings); + // Back to top of loop + continue; } else { // ...and we've already PINGed the server and haven't heard back yet, so let's assume we've timed out // TODO - Code duplication, make a function and share with socket error code below @@ -502,23 +504,34 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { sendtoallclients(clients, alertmsg, 0, settings); if (settings->servertls) { // Finish up with OpenSSL if using server TLS - SSL_free(server_ssl); + if (server_ssl != NULL) SSL_free(server_ssl); + // Set to NULL so we can check if we already free()d this on a previous attempt + server_ssl = NULL; } // Close the socket close(*serversockfd); - // Make a new one - *serversockfd = createserversocket(settings->ircserver, settings->ircserverport); - - // Set reconnection marker for other functions to know we're reconnecting - ircdstate.reconnecting = 1; - // Set oldnick in case we change nick when reconnecting so we can inform existing clients - strcpy(ircdstate.oldnick, ircdstate.ircnick); - connecttoircserver(&serverctx, &server_ssl, serversockfd, &ircdstate, settings, clients); + // Make a new one and reconnect + if ((*serversockfd = createserversocket(settings->ircserver, settings->ircserverport)) == -1) { + // We failed + debugprint(DEBUG_CRIT, "dochat(): Couldn't reconnect to server, will try again.\n"); + // Tell clients + char alertmsg[MAXDATASIZE]; + snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :Couldn't reconnect to server, will try again.", ircdstate.ircnick); + sendtoallclients(clients, alertmsg, 0, settings); + // Don't go back to the top of the loop yet, perhaps some clients are waiting to tell us something - TODO - Could this ever happen in this state? + } else { + // We succeeded + // Set reconnection marker for other functions to know we're reconnecting + ircdstate.reconnecting = 1; + // Set oldnick in case we change nick when reconnecting so we can inform existing clients + strcpy(ircdstate.oldnick, ircdstate.ircnick); + connecttoircserver(&serverctx, &server_ssl, serversockfd, &ircdstate, settings, clients); + // Back to top of loop + continue; + } } - // Back to top of loop - continue; } else { - // No timeout is occuring, back to the top of the loop + // No timeout is occuring, the pselect() just timed out (which is fine and expected), back to the top of the loop continue; } } @@ -543,28 +556,38 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) { // If there was a socket error (receive error or socket closed) // TODO - Code duplication, make a function and share with timeout code above if (servernumbytes < 1) { - printf("Server socket had an error (sockread return code %d), reconnecting!\n", servernumbytes); - // Tell all clients if we timed out + debugprint(DEBUG_CRIT, "Server socket had an error (sockread return code %d), reconnecting!\n", servernumbytes); + // Tell all clients if we had an error char alertmsg[MAXDATASIZE]; snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :Server socket had an error (sockread return code %d), reconnecting!", ircdstate.ircnick, servernumbytes); sendtoallclients(clients, alertmsg, 0, settings); if (settings->servertls) { // Finish up with OpenSSL if using server TLS - SSL_free(server_ssl); + if (server_ssl != NULL) SSL_free(server_ssl); + // Set to NULL so we can check if we already free()d this on a previous attempt + server_ssl = NULL; } // Close the socket close(*serversockfd); - // Make a new one - *serversockfd = createserversocket(settings->ircserver, settings->ircserverport); - - // Set reconnection marker for other functions to know we're reconnecting - ircdstate.reconnecting = 1; - // Set oldnick in case we change nick when reconnecting so we can inform existing clients - strcpy(ircdstate.oldnick, ircdstate.ircnick); - connecttoircserver(&serverctx, &server_ssl, serversockfd, &ircdstate, settings, clients); - - // Back to top of loop - continue; + // Make a new one and reconnect + if ((*serversockfd = createserversocket(settings->ircserver, settings->ircserverport)) == -1) { + // We failed + debugprint(DEBUG_CRIT, "dochat(): Couldn't reconnect to server, will try again.\n"); + // Tell clients + char alertmsg[MAXDATASIZE]; + snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :Couldn't reconnect to server, will try again.", ircdstate.ircnick); + sendtoallclients(clients, alertmsg, 0, settings); + // Don't go back to the top of the loop yet, perhaps some clients are waiting to tell us something - TODO - Could this ever happen in this state? + } else { + // We succeeded + // Set reconnection marker for other functions to know we're reconnecting + ircdstate.reconnecting = 1; + // Set oldnick in case we change nick when reconnecting so we can inform existing clients + strcpy(ircdstate.oldnick, ircdstate.ircnick); + connecttoircserver(&serverctx, &server_ssl, serversockfd, &ircdstate, settings, clients); + // Back to top of loop + continue; + } } serverbuf[servernumbytes] = '\0'; -- cgit v1.2.3