summaryrefslogtreecommitdiff
path: root/blabouncer.c
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-06-17 01:46:28 +0100
committerLuke Bratch <luke@bratch.co.uk>2019-06-17 01:46:28 +0100
commitc70cd5cccc966a35f175913f2281ce251fd62425 (patch)
treecd95e1bbb28ad4df94db87b9e3080cb05d00645b /blabouncer.c
parentfa37193c83f82784e826b8477ee7d4a4cd96d7cf (diff)
Implement a per-client identifier so auto replay can replay everything a given client has missed.
Diffstat (limited to 'blabouncer.c')
-rw-r--r--blabouncer.c43
1 files changed, 28 insertions, 15 deletions
diff --git a/blabouncer.c b/blabouncer.c
index 95521f1..73bef8c 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -134,6 +134,7 @@ int connecttoircserver(SSL_CTX **serverctx, SSL **server_ssl, int *serversockfd,
ircdstate->timeoutcheck = 0;
// ircdstate.reconnecting is not set here as we want to track reconnections separately
// ircdstate.clientchangetime and ircdstate.clientsnonetime not set here as they are set at startup and only changed when clients connect/disconnect
+ // ircdstate.clientcodes not set here, set on startup and whenever a client sets one
// Populate nick and username from our configuration file for now, real IRCd may change them later (TODO - Is this true of username?)
strcpy(ircdstate->ircnick, settings->ircnick);
@@ -176,7 +177,8 @@ int connecttoircserver(SSL_CTX **serverctx, SSL **server_ssl, int *serversockfd,
// Return 1 if we processed something and expect the caller to not need to do anything more
// Return 0 if we didn't process it and the caller might want to do something
//int processircmessage(int *serversockfd, int *clientsockfd, char *str, int source) {
-int processircmessage(SSL *server_ssl, char *str, int source, struct client *clients, int sourcefd, struct ircdstate *ircdstate, struct channel *channels, struct settings *settings) {
+int processircmessage(SSL *server_ssl, char *str, int source, struct client *clients, int sourcefd, struct ircdstate *ircdstate, struct channel *channels,
+ struct settings *settings, struct clientcodes *clientcodes) {
// Track which space-separated token within this response we're on
int counter = 0;
@@ -215,7 +217,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
// Don't return if we got here because this means we didn't process something in processservermessage()
break;
case SOURCE_CLIENT: // If message(s) were from a real IRC client
- if (processclientmessage(server_ssl, str, clients, sourcefd, ircdstate, channels, settings, tokens, counter)) {
+ if (processclientmessage(server_ssl, str, clients, sourcefd, ircdstate, channels, settings, tokens, counter, clientcodes)) {
// We processed something so return true
free(strcopyPtr);
return 1;
@@ -254,7 +256,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
//
// Return 0 if something went wrong
// Return 1 if everything OK
-int processrawstring(SSL *server_ssl, char *str, int source, struct client *clients, int sourcefd, struct ircdstate *ircdstate, struct channel *channels, struct settings *settings) {
+int processrawstring(SSL *server_ssl, char *str, int source, struct client *clients, int sourcefd, struct ircdstate *ircdstate, struct channel *channels,
+ struct settings *settings, struct clientcodes *clientcodes) {
// Copy to a temporary string so we still have the original in case it's not processed
char *strcopy = strdup(str);
// Keep track of initial pointer for free()ing later
@@ -318,7 +321,7 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie
for (int i = 0; i < messagecount; i++) {
// Copy to a temporary string so we still have the original in case it's not processed
char *messagecopy = strdup(messages[i]);
- if (processircmessage(server_ssl, messagecopy, source, clients, sourcefd, ircdstate, channels, settings)) {
+ if (processircmessage(server_ssl, messagecopy, source, clients, sourcefd, ircdstate, channels, settings, clientcodes)) {
debugprint(DEBUG_FULL, "Message processed: \"%s\", NULLing...\n", messages[i]);
messages[i][0] = '\0';
}
@@ -392,11 +395,25 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
clients[i].pendingwhowas = 0;
clients[i].pendingnames = 0;
clients[i].pendingcap = 0;
+ clients[i].clientcode[0] = '\0';
}
// Struct of various strings from and for the real IRCd (such as the greeting strings, the real IRCd's name,
// our nick!user@host string, our nick, username, real name, etc.)
struct ircdstate ircdstate;
+ // Set reconnection and other things to null/zero for now (not used unless reconnecting to server)
+ ircdstate.oldnick[0] = '\0';
+ ircdstate.reconnecting = 0;
+ ircdstate.clientchangetime = time(NULL);
+ ircdstate.clientsnonetime = time(NULL);
+
+ // Struct of client codes
+ // Used to track the last time a client identifying as a given client connected to handle auto replay for a known client.
+ struct clientcodes clientcodes[MAXCLIENTCODES];
+ for (int i = 0; i < MAXCLIENTCODES; i++) {
+ clientcodes[i].code[0] = '\0';
+ clientcodes[i].lastdisconnected = 0;
+ }
// Struct of channels we're in
struct channel *channels;
@@ -413,11 +430,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
SSL_CTX *serverctx = NULL;
SSL *server_ssl = NULL; // Need to create this either way as referenced later
- // Set reconnection and other things to null/zero for now (not used unless reconnecting to server)
- ircdstate.oldnick[0] = '\0';
- ircdstate.reconnecting = 0;
- ircdstate.clientchangetime = time(NULL);
- ircdstate.clientsnonetime = time(NULL);
+ // Try to connect to IRC!
if (!connecttoircserver(&serverctx, &server_ssl, serversockfd, &ircdstate, settings, clients)) {
fprintf(stderr, "Failed to connect to IRC server, exiting.\n");
debugprint(DEBUG_CRIT, "Failed to connect to IRC server, exiting.\n");
@@ -648,7 +661,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
// Try to process received string (which should contain one or more server responses/commands)
// TODO - What if there were two server respones/commands and only one didn't need relaying?
- if (!processrawstring(server_ssl, serverbuf, SOURCE_SERVER, clients, EXCEPT_NONE, &ircdstate, channels, settings)) {
+ if (!processrawstring(server_ssl, serverbuf, SOURCE_SERVER, clients, EXCEPT_NONE, &ircdstate, channels, settings, clientcodes)) {
fprintf(stderr, "Error: bouncer-server failed to process raw string.\n");
debugprint(DEBUG_CRIT, "Error: bouncer-server failed to process raw string.\n");
}
@@ -713,7 +726,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
if (numclients(clients) >= MAXCLIENTS) {
fprintf(stderr, "too many clients, disconnecting and skipping loop iteration!\n");
debugprint(DEBUG_CRIT, "too many clients, disconnecting and skipping loop iteration!\n");
- disconnectclient(i, clients, &ircdstate, settings);
+ disconnectclient(i, clients, &ircdstate, settings, clientcodes);
continue;
}
addrlen = sizeof remoteaddr;
@@ -779,7 +792,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
debugprint(DEBUG_CRIT, "dochat(): client sockread() error fd '%d'.\n", i);
}
// Disconnect the client
- disconnectclient(i, clients, &ircdstate, settings);
+ disconnectclient(i, clients, &ircdstate, settings, clientcodes);
FD_CLR(i, &rfds); // remove from master set - TODO is this needed at the moment since we just add everything from *clientsockfd to fdmax to rfds
// TODO - Handle the "remove the client" loop not finding the old fd
debugprint(DEBUG_FULL, "bouncer-client: total client connections: %d\n", numclients(clients));
@@ -805,7 +818,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
// Try to process received string (which should contain one or more client responses/commands)
// TODO - What if there were two server respones/commands and only one didn't need relaying?
- if (!processrawstring(server_ssl, clientbuf, SOURCE_CLIENT, clients, i, &ircdstate, channels, settings)) {
+ if (!processrawstring(server_ssl, clientbuf, SOURCE_CLIENT, clients, i, &ircdstate, channels, settings, clientcodes)) {
fprintf(stderr, "Error: bouncer-client failed to process raw string.\n");
debugprint(DEBUG_CRIT, "Error: bouncer-client failed to process raw string.\n");
}
@@ -881,8 +894,8 @@ int main(int argc, char *argv[]) {
exit(1);
} else {
if (strcmp(settings.replaymode, "none") && strcmp(settings.replaymode, "time") && strcmp(settings.replaymode, "lastspoke") &&
- strcmp(settings.replaymode, "noclients") && strcmp(settings.replaymode, "lastchange")) {
- printf("main(): replaymode in configuration file must be one of \"none\", \"time\", \"lastspoke\", \"noclients\", or \"lastchange\".\n");
+ strcmp(settings.replaymode, "noclients") && strcmp(settings.replaymode, "lastchange") && strcmp(settings.replaymode, "perclient")) {
+ printf("main(): replaymode in configuration file must be one of \"none\", \"time\", \"lastspoke\", \"noclients\", \"lastchange\" or \"perclient\".\n");
exit(1);
}
}