From 751bee2c2ceb7e9426bf00a669da5679c20ee41a Mon Sep 17 00:00:00 2001
From: Luke Bratch <luke@bratch.co.uk>
Date: Fri, 17 May 2019 19:23:46 +0100
Subject: Condense multiple arrays being passed around into one nice big struct
 to be passed around (huge change) and improve efficiency of
 sendtoallclients() loop.

---
 blabouncer.c | 229 ++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 118 insertions(+), 111 deletions(-)

diff --git a/blabouncer.c b/blabouncer.c
index 2a3bf7e..559e2b1 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -8,14 +8,14 @@
 // - "01:53:47 -!- ServerMode/#test [b] by irc.tghost.co.uk" on existing clients when new client connects
 // - Keep track of changing user modes
 // - Should replay log do more than PRIVMSGs?
-// - Consider moving the three fd-related arrays into one struct
 // - Check authentication before even getting to the send functions to save unnecessary processing
 // - Configurable auto channels
 // - Comma separated channel list in JOINs/PARTs
 // - Only send some things to the requesting client (e.g. LIST replies)
 // - Alert when clients connect/authenticate/disconnect
-// - Perhaps rename arr_ssl and server_ssl since they may not even be OpenSSL sockets
+// - Perhaps rename clients.ssl and server_ssl since they may not even be OpenSSL sockets
 // - Is it possible to replay JOINs/PARTs accurately?
+// - New clients don't get their own server mode (e.g. blabounce(+i))
 //
 // Example WHOIS reply:
 // BOUNCER-SERVER RECEIVED: :irc.tghost.co.uk 307 blabounce l_bratch :is identified for this nick
@@ -109,14 +109,20 @@ struct settings {
   int replaylogging;
 };
 
-// Return index of requested client FD within arr_clients
-// This is used because at least arr_clients, arr_authed, and ssl share the same element order.
+// Structure of connected clients, their socket/file descriptors, their authentication status, and their OpenSSL structures
+struct client {
+  int fd; // Client socket fd - 0 means not connected, greater than 0 means connected and the value is the fd number (so we know which ones to try to read and send to)
+  int authed; // Client authentication status - 0 means not authenticated, 1 means authenticated.
+  SSL *ssl; // OpenSSL structures when using TLS, or faked by casting fd ints to SSL* if not. - TODO - Can we drop one of either "int fd" or "SSL *ssl" now?
+};
+
+// Return index of requested client FD within the clients array.
 // TODO - Use this wherever we are calculating the position (various places) instead of
 // duplicating code.
-int arrindex(int arr_clients[], int clientfd) {
+int arrindex(struct client *clients, int clientfd) {
   // Find the client in the clients array and make sure they are authenticated
   for (int i = 0; i < MAXCLIENTS; i++) {
-    if (arr_clients[i] == clientfd) {
+    if (clients[i].fd == clientfd) {
       return i;
     }
   }
@@ -126,22 +132,25 @@ int arrindex(int arr_clients[], int clientfd) {
 }
 
 // Send whatever string to a specific client by providing the FD
-int sendtoclient(int fd, char *str, int arr_clients[], int arr_authed[], SSL **arr_ssl, struct settings *settings) {
+int sendtoclient(int fd, char *str, struct client *clients, struct settings *settings) {
   appendcrlf(str); // Do this just before sending so callers don't need to worry about it
 
+  int i = 0;
   // Find the client in the clients array and make sure they are authenticated
-  for (int i = 0; i < MAXCLIENTS; i++) {
-    if (arr_clients[i] == fd) {
+  for (i = 0; i < MAXCLIENTS; i++) {
+    if (clients[i].fd == fd) {
       // Found client in array, check authentication status
-      if (!arr_authed[i]) {
-        printf("sendtoclient(): skipping unauthenticated client with fd %d.\n", arr_clients[i]);
+      if (!clients[i].authed) {
+        printf("sendtoclient(): skipping unauthenticated client with fd %d.\n", clients[i].fd);
         return 0;
       }
+      // Break when we get to the correct fd, "i" is now the position in the clients array of our client
+      break;
     }
   }
 
   printf("sendtoclient(): sending \"%s\" (length %zd) to client with fd %d.\n", str, strlen(str), fd);
-  if (socksend(arr_ssl[arrindex(arr_clients, fd)], str, strlen(str), settings->clienttls) == -1) {
+  if (socksend(clients[i].ssl, str, strlen(str), settings->clienttls) == -1) {
     perror("error: sendtoclient() send()\n");
     return 0;
   }
@@ -152,15 +161,15 @@ int sendtoclient(int fd, char *str, int arr_clients[], int arr_authed[], SSL **a
 // Disconnect the client fd "fd" by close()ing it and remove
 // it from the arr_clients array of clients.
 // Also set its authentication status to 0.
-int disconnectclient(int fd, int arr_clients[], int arr_authed[]) {
+int disconnectclient(int fd, struct client *clients) {
   printf("disconnectclient(): disconnecting client fd '%d'\n", fd);
   close(fd); // bye!
   // Remove the client from the clients array
-  for (int j = 0; j < MAXCLIENTS; j++) {
-    if (arr_clients[j] == fd) {
-      printf("found and clearing fd %d from arr_clients[%d]\n", fd, j);
-      arr_clients[j] = 0;
-      arr_authed[j] = 0;
+  for (int i = 0; i < MAXCLIENTS; i++) {
+    if (clients[i].fd == fd) {
+      printf("found and clearing fd %d from clients[%d]\n", fd, i);
+      clients[i].fd = 0;
+      clients[i].authed = 0;
       return 1;
     }
   }
@@ -174,7 +183,7 @@ int disconnectclient(int fd, int arr_clients[], int arr_authed[]) {
 // "except" is used to send to all clients _except_ the fd provided (except = 0 (EXCEPT_NONE) avoids this, i.e. sends to all)
 // "except" is really the "sourcefd" and is also used as part of the authentication check - this is messy and they should perhaps be two separate arguments.
 // TODO - is passing str_len useful if we're appendcrlfing and then using strlen(str) in the send?  I guess not...  (As long as we're always null terminated in the correct place.)
-int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str, int except, int arr_authed[], SSL **arr_ssl, struct settings *settings) {
+int sendtoallclients(struct client *clients, char *str, int except, struct settings *settings) {
 
   char *sendertype;
 
@@ -196,45 +205,43 @@ int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str,
       printf("sendtoallclients(): trusting clientfd of 0.\n");
       break;
     }
-    if (arr_clients[i] == except) {
+    if (clients[i].fd == except) {
       // Found client in array, check authentication status
-      if (!arr_authed[i]) {
-        printf("sendtoallclients(): skipping unauthenticated client with fd %d.\n", arr_clients[i]);
+      if (!clients[i].authed) {
+        printf("sendtoallclients(): skipping unauthenticated client with fd %d.\n", clients[i].fd);
         return 0;
       }
     }
   }
 
-  // relay/send to all clients...
-  for (int i = *clientsockfd + 1; i <= fdmax; i++) {
+  // Relay/send to all clients...
+  for (int i = 0; i < MAXCLIENTS; i++) {
     // Skip the current client if "except" non-zero (no need to send back to itself)
-    if (i == except) {
+    if (clients[i].fd == except) {
       continue;
     }
-    // TODO maybe see if things are in rfds (not sure what this means any more - perhaps it was to do with only sending to connected things which is now solved)
-    // ...but only if they are connected
-    for (int j = 0; j < MAXCLIENTS; j++) {
-      if (arr_clients[j] == i) {
-        if (!arr_authed[j]) {
-          printf("sendtoallclients(): skipping unauthenticated client with fd %d.\n", arr_clients[j]);
-          continue;
-        }
-        printf("sendtoallclients(): %s: sending '%s' to client with fd %d.\n", sendertype, str, i);
-        if (socksend(arr_ssl[arrindex(arr_clients, i)], str, strlen(str), settings->clienttls) == -1) {
-          perror("error: sendtoallclients() send()\n");
-        }
+    // ...but only if they are connected...
+    if (clients[i].fd > 0) {
+      // ...and authenticated
+      if (!clients[i].authed) {
+        printf("sendtoallclients(): skipping unauthenticated client with fd %d.\n", clients[i].fd);
+        continue;
+      }
+      printf("sendtoallclients(): %s: sending '%s' to client with fd %d.\n", sendertype, str, clients[i].fd);
+      if (socksend(clients[i].ssl, str, strlen(str), settings->clienttls) == -1) {
+        printf("error: sendtoallclients() send() with fd '%d'.\n", clients[i].fd);
       }
     }
   }
 
-  return 0;
+  return 1;
 }
 
 // Send whatever string to the real IRC server
 // Client FD and arrays needed to make sure anything relayed from a client is from an authenticated client.
 // clientfd of "0" means trusted, used when we are sending things ourselves that weren't relayed
 // from a real client.
-int sendtoserver(SSL *server_ssl, char *str, int str_len, int clientfd, int arr_clients[], int arr_authed[], struct settings *settings) {
+int sendtoserver(SSL *server_ssl, char *str, int str_len, int clientfd, struct client *clients, struct settings *settings) {
   appendcrlf(str); // Do this just before sending so callers don't need to worry about it
   str_len = strlen(str); // Recalculate str_len in case it changed (TODO: so do we even need to pass it to this function?)
 
@@ -245,10 +252,10 @@ int sendtoserver(SSL *server_ssl, char *str, int str_len, int clientfd, int arr_
       printf("sendtoserver(): trusting clientfd of 0.\n");
       break;
     }
-    if (arr_clients[i] == clientfd) {
+    if (clients[i].fd == clientfd) {
       // Found client in array, check authentication status
-      if (!arr_authed[i]) {
-        printf("sendtoserver(): skipping unauthenticated client with fd %d.\n", arr_clients[i]);
+      if (!clients[i].authed) {
+        printf("sendtoserver(): skipping unauthenticated client with fd %d.\n", clients[i].fd);
         return 0;
       }
     }
@@ -484,7 +491,7 @@ int removechannel(struct channel *channels, char *name) {
 // 'sourcefd' is the client to send to, and replayseconds is the number of
 // seconds of replay to replay.
 // Returns 1 for success or 0 for failure.
-int doreplay(int sourcefd, int replayseconds, int arr_clients[], int arr_authed[], SSL **arr_ssl, struct settings *settings) {
+int doreplay(int sourcefd, int replayseconds, struct client *clients, struct settings *settings) {
   char outgoingmsg[MAXDATASIZE];
 
   // Figure out how many lines to replay
@@ -496,7 +503,7 @@ int doreplay(int sourcefd, int replayseconds, int arr_clients[], int arr_authed[
     exit(1);
   } else if (numlines == 0) {
     snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :0 replay log lines found in the time requested, nothing to send.", settings->ircnick);
-    sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+    sendtoclient(sourcefd, outgoingmsg, clients, settings);
     return 1;
   }
 
@@ -507,7 +514,7 @@ int doreplay(int sourcefd, int replayseconds, int arr_clients[], int arr_authed[
       exit(1);
     }
     printf("Sending replay line: '%s'.\n", outgoingmsg);
-    sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+    sendtoclient(sourcefd, outgoingmsg, clients, settings);
   }
 
   return 1;
@@ -527,7 +534,7 @@ int doreplay(int sourcefd, int replayseconds, int arr_clients[], int arr_authed[
 // 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, int *clientsockfd, char *str, int source, int fdmax, int arr_clients[], int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels, int arr_authed[], SSL **arr_ssl, struct settings *settings) {
+int processircmessage(SSL *server_ssl, char *str, int source, struct client *clients, int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels, struct settings *settings) {
   // Track which space-separated token within this response we're on
   int counter = 0;
 
@@ -564,7 +571,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
           exit(1);
         }
         // sourcefd = 0 as this is a trusted response
-        sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, arr_clients, arr_authed, settings);
+        sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, clients, settings);
 
         // We processed something so return true
         return 1;
@@ -640,7 +647,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
           }
 
           // And then send to all clients
-          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed, arr_ssl, settings);
+          sendtoallclients(clients, str, sourcefd, settings);
           return 1;
         }
 
@@ -662,7 +669,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
           }
 
           // And then send to all clients
-          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed, arr_ssl, settings);
+          sendtoallclients(clients, str, sourcefd, settings);
           return 1;
         }
 
@@ -729,7 +736,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
           setchanneltopicwhotime(channels, tokens[2], prefixcopy, timenowstr);
 
           // And then finally relay to all clients
-          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed, arr_ssl, settings);
+          sendtoallclients(clients, str, sourcefd, settings);
           return 1;
         }
 
@@ -737,7 +744,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
         if (strncmp(tokens[1], "PRIVMSG", strlen(tokens[1])) == 0) {
           printf("Server PRIVMSG found and it is: %s with length %zd!  Next token is '%s'.  Relaying to all clients.\n", tokens[0], strlen(tokens[0]), tokens[2]);
 
-          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed, arr_ssl, settings);
+          sendtoallclients(clients, str, sourcefd, settings);
 
           // Write to replay log if replay logging enabled
           if (settings->replaylogging) {
@@ -777,7 +784,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
           updatechannelnicks(channels, tokens[0], tokens[2]);
 
           // Relay to all clients
-          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed, arr_ssl, settings);
+          sendtoallclients(clients, str, sourcefd, settings);
 
           return 1;
         }
@@ -793,15 +800,15 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
           printf("Password accepted!  Setting fd %d to authenticated.\n", sourcefd);
           // Find the client in the clients array and set them as authenticated
           for (int i = 0; i < MAXCLIENTS; i++) {
-            if (arr_clients[i] == sourcefd) {
+            if (clients[i].fd == sourcefd) {
               // Found client in array, set to authenticated
-              arr_authed[i] = 1;
+              clients[i].authed = 1;
               printf("Found and authenticated fd in arr_authed.\n");
             }
           }
         } else {
           printf("Password rejected, disconnecting fd %d.\n", sourcefd);
-          disconnectclient(sourcefd, arr_clients, arr_authed);
+          disconnectclient(sourcefd, clients);
         }
 
         return 1;
@@ -814,23 +821,23 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
 
         // Send IRC greeting strings (001/RPL_WELCOME, 002/RPL_YOURHOST, 003/RPL_CREATED, 004/RPL_MYINFO) to client
         snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting001);
-        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
         snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting002);
-        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
         snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting003);
-        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
         snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting004);
-        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
 
         // Send our own greeting message
         snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Welcome to blabouncer!", settings->ircnick);
-        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
         snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Blabouncer commands are all prefixed with BLABOUNCER which you can usually send using \"/QUOTE BLABOUNCER\"", settings->ircnick);
-        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
         snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Valid blabouncer commands are:", settings->ircnick);
-        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
         snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [seconds]\" (Where [seconds] is the number of seconds of replay log to replay.)", settings->ircnick);
-        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
 
         // Get the channel count so we can enumerate over all channels.
         // Storing separately so we can skip over blank channels.
@@ -851,7 +858,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
             fprintf(stderr, "Error while preparing USER just connected, channel JOIN responses!\n");
             exit(1);
           }
-          sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+          sendtoclient(sourcefd, outgoingmsg, clients, settings);
 
           // Send topic (or lack thereof) to client
           // If there isn't one set (we guess this if topic timestamp is 0), send 331 RPL_NOTOPIC
@@ -862,7 +869,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
               exit(1);
             }
             // ..and send it to the client
-            sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+            sendtoclient(sourcefd, outgoingmsg, clients, settings);
           // If there is one set, send 332 RPL_TOPIC and 333 RPL_TOPICWHOTIME
           } else {
             // Prepare the topic message...
@@ -871,7 +878,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
               exit(1);
             }
             // ..and send it to the client
-            sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+            sendtoclient(sourcefd, outgoingmsg, clients, settings);
 
             // Next prepare the topic who/when message...
             if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 333 %s %s %s %s", ircdstrings->ircdname, ircdstrings->ircnick, channels[i].name, channels[i].topicwho, channels[i].topicwhen)) {
@@ -879,7 +886,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
               exit(1);
             }
             // ..and send it to the client
-            sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+            sendtoclient(sourcefd, outgoingmsg, clients, settings);
           }
 
           // Send list of names
@@ -899,7 +906,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
               fprintf(stderr, "Error while preparing USER just connected, channel NAMES responses!\n");
               exit(1);
             }
-            sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+            sendtoclient(sourcefd, outgoingmsg, clients, settings);
           }
 
           // Once all names are sent, send the "end of /NAMES" 366 (RPL_ENDOFNAMES) message
@@ -907,11 +914,11 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
             fprintf(stderr, "Error while preparing USER just connected, end of NAMES response!\n");
             exit(1);
           }
-          sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+          sendtoclient(sourcefd, outgoingmsg, clients, settings);
         }
 
         // Catch the client up with the default number of seconds of replay
-        doreplay(sourcefd, settings->replayseconds, arr_clients, arr_authed, arr_ssl, settings);
+        doreplay(sourcefd, settings->replayseconds, clients, settings);
 
         return 1;
       }
@@ -925,7 +932,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
           fprintf(stderr, "Error while preparing PONG response!\n");
           exit(1);
         }
-        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+        sendtoclient(sourcefd, outgoingmsg, clients, settings);
 
         // We processed something so return true
         return 1;
@@ -940,7 +947,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
       // Just send NICK to server and let it change all clients' nicks if needed
       if (strncmp(tokens[0], "NICK", strlen(tokens[0])) == 0) {
         printf("Client NICK found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));
-        sendtoserver(server_ssl, str, strlen(str), sourcefd, arr_clients, arr_authed, settings);
+        sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);
         return 1;
       }
 
@@ -948,7 +955,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
       if (strncmp(tokens[0], "PRIVMSG", strlen(tokens[0])) == 0) {
         printf("Client PRIVMSG found and it is: %s with length %zd!  Sending to server then back to other clients...\n", tokens[0], strlen(tokens[0]));
         // Send original request straight to server
-        sendtoserver(server_ssl, str, strlen(str), sourcefd, arr_clients, arr_authed, settings);
+        sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);
 
         // Rebuild to full PRIVMSG string and relay to all other clients
         char outgoingmsg[MAXDATASIZE]; // String to send to client
@@ -958,7 +965,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
           exit(1);
         }
         // Send to all except source client
-        sendtoallclients(clientsockfd, fdmax, arr_clients, outgoingmsg, sourcefd, arr_authed, arr_ssl, settings);
+        sendtoallclients(clients, outgoingmsg, sourcefd, settings);
 
         // Write to replay log if replay logging enabled
         if (settings->replaylogging) {
@@ -976,7 +983,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
       // Just send JOIN to server and let it talk back to clients as required
       if (strncmp(tokens[0], "JOIN", strlen(tokens[0])) == 0) {
         printf("Client JOIN found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));
-        sendtoserver(server_ssl, str, strlen(str), sourcefd, arr_clients, arr_authed, settings);
+        sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);
         return 1;
       }
 
@@ -985,21 +992,21 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
       if (strncmp(tokens[0], "QUIT", strlen(tokens[0])) == 0) {
         printf("Client QUIT found from fd %d and it is: %s with length %zd!  Disconnecting that fd.\n", sourcefd, tokens[0], strlen(tokens[0]));
         close(sourcefd);
-        disconnectclient(sourcefd, arr_clients, arr_authed);
+        disconnectclient(sourcefd, clients);
         return 1;
       }
 
       // Just send PART to server and let it talk back to clients as required
       if (strncmp(tokens[0], "PART", strlen(tokens[0])) == 0) {
         printf("Client PART found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));
-        sendtoserver(server_ssl, str, strlen(str), sourcefd, arr_clients, arr_authed, settings);
+        sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);
         return 1;
       }
 
       // Just send TOPIC to server and let it talk back to clients as required
       if (strncmp(tokens[0], "TOPIC", strlen(tokens[0])) == 0) {
         printf("Client TOPIC found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));
-        sendtoserver(server_ssl, str, strlen(str), sourcefd, arr_clients, arr_authed, settings);
+        sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);
         return 1;
       }
 
@@ -1015,19 +1022,19 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
           if ((replayseconds = strtol(tokens[2], NULL, 10)) == 0) {
             printf("Invalid number of replay seconds provided by REPLAY.  Telling client.\n");
             snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Invalid number of seconds of replay requested by REPLAY command.", settings->ircnick);
-            sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+            sendtoclient(sourcefd, outgoingmsg, clients, settings);
             return 1;
           }
 
-          doreplay(sourcefd, replayseconds, arr_clients, arr_authed, arr_ssl, settings);
+          doreplay(sourcefd, replayseconds, clients, settings);
           return 1;
         // Unrecognised BLABOUNCER command received, send some help instructions
         } else {
           printf("Client BLABOUNCER unrecognised command found and it is: %s with length %zd!  Sending a help message.\n", tokens[1], strlen(tokens[1]));
           snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Unrecognised BLABOUNCER command received.  Valid commands are:", settings->ircnick);
-          sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+          sendtoclient(sourcefd, outgoingmsg, clients, settings);
           snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [seconds]\" (Where [seconds] is the number of seconds of replay log to replay.)", settings->ircnick);
-          sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed, arr_ssl, settings);
+          sendtoclient(sourcefd, outgoingmsg, clients, settings);
           return 1;
         }
       }
@@ -1061,7 +1068,7 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source,
 //
 // Return 0 if something went wrong
 // Return 1 if everything OK
-int processrawstring(SSL *server_ssl, int *clientsockfd, char *str, int source, int fdmax, int arr_clients[], int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels, int arr_authed[], SSL **arr_ssl, struct settings *settings) {
+int processrawstring(SSL *server_ssl, char *str, int source, struct client *clients, int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels, struct settings *settings) {
   // Copy to a temporary string so we still have the original in case it's not processed
   char *strcopy = strdup(str);
 
@@ -1116,7 +1123,7 @@ int processrawstring(SSL *server_ssl, int *clientsockfd, char *str, int source,
   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, clientsockfd, messagecopy, source, fdmax, arr_clients, sourcefd, ircdstrings, channels, arr_authed, arr_ssl, settings)) {
+    if (processircmessage(server_ssl, messagecopy, source, clients, sourcefd, ircdstrings, channels, settings)) {
       printf("Message processed: \"%s\", NULLing...\n", messages[i]);
       messages[i][0] = '\0';
     }
@@ -1132,16 +1139,16 @@ int processrawstring(SSL *server_ssl, int *clientsockfd, char *str, int source,
           // Relay/send to all clients ("except" = 0 because this should send to all clients)
           // TODO - Is this really going to send the original string if we have messed it with it in processrawstring() and friends!?
           printf("bouncer-server: sending unprocessed server message \"%s\" to all clients, length %zd.\n", messages[i], strlen(messages[i]));
-          sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], EXCEPT_NONE, arr_authed, arr_ssl, settings);
+          sendtoallclients(clients, messages[i], EXCEPT_NONE, settings);
           break;
         case SOURCE_CLIENT: // If message(s) were from a real IRC client
           // Send to server
           printf("bouncer-client: sending unprocessed client message \"%s\" to the server, length %zd.\n", messages[i], strlen(messages[i]));
-          sendtoserver(server_ssl, messages[i], strlen(messages[i]), sourcefd, arr_clients, arr_authed, settings);
+          sendtoserver(server_ssl, messages[i], strlen(messages[i]), sourcefd, clients, settings);
 
           printf("bouncer-client: sending unprocessed client message \"%s\" to all other clients, length %zd.\n", messages[i], strlen(messages[i]));
           // send the same thing to all *other* clients (all except for source fd)
-          sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], sourcefd, arr_authed, arr_ssl, settings);
+          sendtoallclients(clients, messages[i], sourcefd, settings);
           break;
         default:
           fprintf(stderr, "Unexpected raw IRC string source for unprocessed message \"%s\", length %zd.!\n", messages[i], strlen(messages[i]));
@@ -1162,9 +1169,6 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
   int servernumbytes; // Number of bytes received from remote server
   char outgoingmsg[MAXDATASIZE]; // String to send to server
   int outgoingmsgrc; // Return code from getstdin() for outgoing message
-  int arr_clients[MAXCLIENTS]; // Array of all client FDs - 0 means not connected, greater than 0 means connected and the value is the fd number (so we know which ones to try to read)
-  int arr_authed[MAXCLIENTS]; // Array of client authentication statuses - 0 means not authenticated, 1 means authenticated.  Element numbers match those of arr_clients.
-  SSL *arr_ssl[MAXCLIENTS]; // Array of OpenSSL structures when using TLS, or faked by casting fd ints to SSL* if not. - TODO - Can we drop one of either arr_clients or arr_ssl now?
   int num_clients = 0; // Current number of clients
 
   int fdmax; // highest numbered socket fd
@@ -1179,10 +1183,13 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
 
   fd_set rfds; // set of read fds to monitor with select() - 0: stdin, 1: stdout, 2: stderr, 3 and higher: sockets (at time of writing, 3: real IRC server, 4: client listener, 5 and higher: clients)
 
+  // Set up clients structure
+  struct client clients[MAXCLIENTS];
+
   // Set all the clients to be "not connected" and "not authenticated"
   for (int i = 0; i < MAXCLIENTS; i++) {
-    arr_clients[i] = 0;
-    arr_authed[i] = 0;
+    clients[i].fd = 0;
+    clients[i].authed = 0;
   }
 
   // Initialise OpenSSL (used for both client and server)
@@ -1235,13 +1242,13 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
   // Send our NICK
   snprintf(outgoingmsg, MAXDATASIZE, "NICK %s", ircdstrings.ircnick); // TODO - Check for success (with return code)
   // sourcefd = 0 as this is a trusted message
-  sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, arr_clients, arr_authed, settings);
+  sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, clients, settings);
 
   // Send our USER
   snprintf(outgoingmsg, MAXDATASIZE, "USER %s 8 * : %s", ircdstrings.ircusername, settings->ircrealname); // TODO - Check for success (with return code)
                                                                                 // TODO - Send a more intelligent/correct USER string
   // sourcefd = 0 as this is a trusted message
-  sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, arr_clients, arr_authed, settings);
+  sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, clients, settings);
 
   // Struct of channels we're in
   struct channel *channels;
@@ -1270,9 +1277,9 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
     // TODO - make sure *serversockfd stays at the same value (probably 3?) in all cases - what if the server disconnects/reconnects/etc.
     // TODO - now that only connected clients are monitored, perhaps tracking using both fdmax and num_client loops is unnecessary?
     for (int i = 0; i < MAXCLIENTS; i++) {
-      if (arr_clients[i] > 0) {
-        printf("monitoring fd %d.\n", arr_clients[i]);
-        FD_SET(arr_clients[i], &rfds);
+      if (clients[i].fd > 0) {
+        printf("monitoring fd %d.\n", clients[i].fd);
+        FD_SET(clients[i].fd, &rfds);
       }
     }
 
@@ -1305,7 +1312,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, clientsockfd, serverbuf, SOURCE_SERVER, fdmax, arr_clients, EXCEPT_NONE, &ircdstrings, channels, arr_authed, arr_ssl, settings)) {
+      if (!processrawstring(server_ssl, serverbuf, SOURCE_SERVER, clients, EXCEPT_NONE, &ircdstrings, channels, settings)) {
         fprintf(stderr, "Error: bouncer-server failed to process raw string.\n");
         exit(1);
       }
@@ -1357,7 +1364,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
       }
 
       // sourcefd = 0 as this is a trusted message
-      sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, arr_clients, arr_authed, settings);
+      sendtoserver(server_ssl, outgoingmsg, strlen(outgoingmsg), 0, clients, settings);
     }
 
     // go through all the remaining sockets to see if there's anything from the client sockets (either new connections or existing clients sending messages)
@@ -1391,24 +1398,24 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
             }
             // Find a free element in the clients array and set to new fd value
             for (int j = 0; j < MAXCLIENTS; j++) {
-                if (arr_clients[j] == 0) {
-                  arr_clients[j] = newfd;
+                if (clients[j].fd == 0) {
+                  clients[j].fd = newfd;
                   // Ensure its authentication status is set to 0
-                  arr_authed[j] = 0;
+                  clients[j].authed = 0;
                   // If using TLS then...
                   if (settings->clienttls) {
                     // ...set as OpenSSL FD and SSL_accept it
-                    arr_ssl[j] = SSL_new(ctx);
-                    SSL_set_fd(arr_ssl[j], newfd);
-                    if (SSL_accept(arr_ssl[j]) <= 0) {
-                      printf("SSL_accept failed for fd %d.\n", j);
+                    clients[j].ssl = SSL_new(ctx);
+                    SSL_set_fd(clients[j].ssl, newfd);
+                    if (SSL_accept(clients[j].ssl) <= 0) {
+                      printf("SSL_accept failed for fd %d.\n", clients[j].fd);
                       ERR_print_errors_fp(stderr);
                     } else {
-                      printf("SSL_accept succeeded for fd %d.\n", j);
+                      printf("SSL_accept succeeded for fd %d.\n", clients[j].fd);
                     }
                   } else {
                     // If not using TLS then cast newfd to SSL* even though it will just be the original newfd int really
-                    arr_ssl[j] = (SSL*)(long int)newfd;
+                    clients[j].ssl = (SSL*)(long int)newfd;
                   }
                   break;
                 }
@@ -1421,7 +1428,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
         } else {
           printf("...previous connection!\n");
           // handle data from a client
-          if ((clientnumbytes = sockread(arr_ssl[arrindex(arr_clients, i)], clientbuf, sizeof clientbuf, settings->clienttls)) <= 0) {
+          if ((clientnumbytes = sockread(clients[arrindex(clients, i)].ssl, clientbuf, sizeof clientbuf, settings->clienttls)) <= 0) {
             // got error or connection closed by client
             if (clientnumbytes == 0) {
               // connection closed
@@ -1430,7 +1437,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
               perror("recv");
             }
             // Disconnect the client
-            disconnectclient(i, arr_clients, arr_authed);
+            disconnectclient(i, clients);
             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
             num_clients--; // Track total number of clients
@@ -1447,7 +1454,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, clientsockfd, clientbuf, SOURCE_CLIENT, fdmax, arr_clients, i, &ircdstrings, channels, arr_authed, arr_ssl, settings)) {
+            if (!processrawstring(server_ssl, clientbuf, SOURCE_CLIENT, clients, i, &ircdstrings, channels, settings)) {
               fprintf(stderr, "Error: bouncer-client failed to process raw string.\n");
               exit(1);
             }
-- 
cgit v1.2.3