summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-12-22 20:16:57 +0000
committerLuke Bratch <luke@bratch.co.uk>2019-12-22 20:16:57 +0000
commit0883de2c491a8c79aec13d25bab429aea4362a10 (patch)
tree1c1e1063697f8b5e19d706ef3813f76aad21b70e
parent85dd88a180043e991c19a4c93a6ce5c7fe0a6e88 (diff)
Significantly reduce memory usage by only initialising channel struct elements when they are used for the first time.
-rw-r--r--TODO6
-rw-r--r--blabouncer.c21
-rw-r--r--functions.c126
-rw-r--r--functions.h26
-rw-r--r--message.c56
-rw-r--r--structures.h1
6 files changed, 126 insertions, 110 deletions
diff --git a/TODO b/TODO
index 4e60cfd..d302400 100644
--- a/TODO
+++ b/TODO
@@ -10,8 +10,6 @@ macOS compiler may need limits.h included in structures.h.
NAMES don't seem to be sent to clients (at least old irssi) after weird timeouts like slow QUIT processing.
-Memory usage seems very high. Maybe it's timeouts/reconnecting? Does it only happen with background mode?
-
When blabouncer reconnects to a server, clients (at least XChat) get stuck with just e.g.
[13:14:50]* PONG LAG1574032890090568
[13:15:20]* PONG LAG1574032920149401
@@ -22,3 +20,7 @@ When blabouncer reconnects to a server, clients (at least XChat) get stuck with
In channels with no nicks.
Add BLABOUNCER VERSION.
+
+Sometimes replaymode = "lastspoke" will replay the last message you sent if you spoke last and sometimes it doesn't - change to always include your last message?
+
+Can memory usage be reduced further? (e.g. better channel struct management)
diff --git a/blabouncer.c b/blabouncer.c
index a9eab97..5ee48b5 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -136,6 +136,7 @@ int connecttoircserver(SSL_CTX **serverctx, SSL **server_ssl, int *serversockfd,
// 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
+ // ircdstate->maxchannelcount not set here, set on startup in dochat()
// Populate nicks[0] and username from our configuration file for now, real IRCd may change them later (TODO - Is this true of username?)
strcpy(ircdstate->ircnick, settings->ircnicks[0]);
@@ -435,14 +436,9 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
// Struct of channels we're in
struct channel *channels;
channels = malloc(sizeof(struct channel) * MAXCHANNELS);
- // Set initial channel names to empty strings
- for (int i = 0; i < MAXCHANNELS; i++) {
- channels[i].name[0] = '\0';
- // And all the nicks within it
- for (int j = 0; j < MAXCHANNICKS; j++) {
- channels[i].nicks[j][0] = '\0';
- }
- }
+ ircdstate.maxchannelcount = 0;
+ // Each channel struct element is only initialised upon channel creation to avoid consuming lots of memory here.
+ // The memory is never released once a channel is parted - TODO - Can this channel struct memory usage be improved?
// Initialise OpenSSL (used for both client and server)
init_openssl();
@@ -710,14 +706,13 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
if (strncmp(outgoingmsg, "listchannels", strlen("listchannels")) == 0) {
printf("STDIN command starting: listchannels\n");
- int channelcount = getchannelcount(channels);
+ int channelcount = getchannelcount(channels, ircdstate.maxchannelcount);
- for (int i = 0; i < channelcount; i++) {
+ for (int i = 0; i < ircdstate.maxchannelcount; i++) {
printf("Checking channel[%d] out of %d.\n", i, channelcount);
- // Skip this one and increment channelcount if it's a blank channel
+ // Skip this one if it's a blank channel
if (!channels[i].name[0]) {
- debugprint(DEBUG_FULL, "Skipping channel[%d], incrementing channelcount.\n", i);
- channelcount++;
+ debugprint(DEBUG_FULL, "Skipping blank channel channel[%d].\n", i);
continue;
}
diff --git a/functions.c b/functions.c
index 28c6691..54e7390 100644
--- a/functions.c
+++ b/functions.c
@@ -632,12 +632,12 @@ int disconnectclient(int fd, struct client *clients, struct ircdstate *ircdstate
return 0;
}
-int createchannel(struct channel *channels, char *name, char *topic, char *topicwho, char *topicwhen) {
+int createchannel(struct channel *channels, struct ircdstate *ircdstate, char *name, char *topic, char *topicwho, char *topicwhen) {
debugprint(DEBUG_FULL, "createchannel(): given '%s', '%s', '%s', and '%s'.\n", name, topic, topicwho, topicwhen);
// Make sure the channel doesn't already exist
- for (int i = 0; i < MAXCHANNELS; i++) {
- if (strncmp(channels[i].name, name, strlen(name)) == 0) {
+ for (int i = 0; i < ircdstate->maxchannelcount; i++) {
+ if (strlen(channels[i].name) == strlen(name) && strncmp(channels[i].name, name, strlen(name)) == 0) {
// Note that this may be happening because we just reconnected
debugprint(DEBUG_CRIT, "error: createchannel(): channel name already exists.\n");
return 0;
@@ -645,44 +645,66 @@ int createchannel(struct channel *channels, char *name, char *topic, char *topic
}
}
- // Find a free slot in the array (when the channel name is not set (0th character is '\0'))...
- for (int i = 0; i < MAXCHANNELS; i++) {
+ // Make sure we aren't in too many channels already
+ if (getchannelcount(channels, ircdstate->maxchannelcount) >= MAXCHANNELS - 1) {
+ debugprint(DEBUG_CRIT, "error: createchannel(): already in too many channels (MAXCHANNELS = %d!\n", MAXCHANNELS);
+ return 0;
+ }
+
+ int arrslot = -1;
+
+ // See if there's a free slot in the already used section of the channels array
+ for (int i = 0; i < ircdstate->maxchannelcount; i++) {
if (!channels[i].name[0]) {
- // ...and set the name and topic
- strncpy(channels[i].name, name, strlen(name));
- channels[i].name[strlen(name)] = '\0';
- debugprint(DEBUG_FULL, "createchannel(): name given was '%s', length '%ld'.\n", name, strlen(name));
- debugprint(DEBUG_FULL, "createchannel(): name set to '%s', length '%ld'.\n", channels[i].name, strlen(channels[i].name));
- strncpy(channels[i].topic, topic, strlen(topic));
- channels[i].topic[strlen(topic)] = '\0';
- debugprint(DEBUG_FULL, "createchannel(): topic given was '%s', length '%ld'.\n", topic, strlen(topic));
- debugprint(DEBUG_FULL, "createchannel(): topic set to '%s', length '%ld'.\n", channels[i].topic, strlen(channels[i].topic));
- strncpy(channels[i].topicwho, topicwho, strlen(topicwho));
- channels[i].topicwho[strlen(topicwho)] = '\0';
- strncpy(channels[i].topicwhen, topicwhen, strlen(topicwhen));
- channels[i].topicwhen[strlen(topicwhen)] = '\0';
- channels[i].gotnames = 0;
- // Set nicks to blank
- for (int j = 0; j < MAXCHANNICKS; j++) {
- channels[i].nicks[j][0] = '\0';
- }
- return 1;
+ // We found one, use this slot
+ arrslot = i;
+ debugprint(DEBUG_FULL, "createchannel(): re-using existing slot %d.\n", arrslot);
+ break;
}
}
+ // If we didn't find one, increment the total count and use the next unused slot
+ if (arrslot < 0) {
+ arrslot = ircdstate->maxchannelcount;
+ ircdstate->maxchannelcount++;
+ debugprint(DEBUG_FULL, "createchannel(): using new slot slot %d.\n", arrslot);
+ }
+
+ // If we got a valid slot...
+ if (arrslot >= 0) {
+ // ...set the name and topic
+ strncpy(channels[arrslot].name, name, strlen(name));
+ channels[arrslot].name[strlen(name)] = '\0';
+ debugprint(DEBUG_FULL, "createchannel(): name given was '%s', length '%ld'.\n", name, strlen(name));
+ debugprint(DEBUG_FULL, "createchannel(): name set to '%s', length '%ld'.\n", channels[arrslot].name, strlen(channels[arrslot].name));
+ strncpy(channels[arrslot].topic, topic, strlen(topic));
+ channels[arrslot].topic[strlen(topic)] = '\0';
+ debugprint(DEBUG_FULL, "createchannel(): topic given was '%s', length '%ld'.\n", topic, strlen(topic));
+ debugprint(DEBUG_FULL, "createchannel(): topic set to '%s', length '%ld'.\n", channels[arrslot].topic, strlen(channels[arrslot].topic));
+ strncpy(channels[arrslot].topicwho, topicwho, strlen(topicwho));
+ channels[arrslot].topicwho[strlen(topicwho)] = '\0';
+ strncpy(channels[arrslot].topicwhen, topicwhen, strlen(topicwhen));
+ channels[arrslot].topicwhen[strlen(topicwhen)] = '\0';
+ channels[arrslot].gotnames = 0;
+ // Set nicks to blank
+ for (int i = 0; i < MAXCHANNICKS; i++) {
+ channels[arrslot].nicks[i][0] = '\0';
+ }
+ return 1;
+ }
+
debugprint(DEBUG_CRIT, "error: createchannel() didn't create a channel\n");
// TODO - Make a failed return do something to callers
return 0;
}
-int setchanneltopicwhotime(struct channel *channels, char *channelname, char *who, char *when) {
+int setchanneltopicwhotime(struct channel *channels, int maxchannelcount, char *channelname, char *who, char *when) {
debugprint(DEBUG_FULL, "setchanneltopicwhotime(): given '%s', '%s', and '%s'.\n", channelname, who, when);
-
debugprint(DEBUG_FULL, "setchanneltopicwhotime(): who: '%s' with length '%ld'.\n", who, strlen(who));
debugprint(DEBUG_FULL, "setchanneltopicwhotime(): when: '%s' with length '%ld'.\n", when, strlen(when));
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < maxchannelcount; i++) {
if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) {
strncpy(channels[i].topicwho, who, strlen(who));
channels[i].topicwho[strlen(who)] = '\0';
@@ -696,10 +718,10 @@ int setchanneltopicwhotime(struct channel *channels, char *channelname, char *wh
return 0;
}
-int setchanneltopic(struct channel *channels, char *channelname, char *topic) {
+int setchanneltopic(struct channel *channels, int maxchannelcount, char *channelname, char *topic) {
debugprint(DEBUG_FULL, "setchanneltopic(): given '%s' and '%s'.\n", channelname, topic);
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < maxchannelcount; i++) {
if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) {
strncpy(channels[i].topic, topic, strlen(topic));
channels[i].topic[strlen(topic)] = '\0';
@@ -711,10 +733,10 @@ int setchanneltopic(struct channel *channels, char *channelname, char *topic) {
return 0;
}
-int getchannelcount(struct channel *channels) {
+int getchannelcount(struct channel *channels, int maxchannelcount) {
int count = 0;
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < maxchannelcount; i++) {
if (channels[i].name[0]) {
count++;
}
@@ -725,14 +747,14 @@ int getchannelcount(struct channel *channels) {
return count;
}
-int removechannel(struct channel *channels, char *name) {
+int removechannel(struct channel *channels, int maxchannelcount, char *name) {
debugprint(DEBUG_FULL, "removechannel(): given '%s'.\n", name);
// Clear its topic setter and timestamp...
- setchanneltopicwhotime(channels, name, "", "0");
+ setchanneltopicwhotime(channels, maxchannelcount, name, "", "0");
// Find the channel in the channel array...
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < maxchannelcount; i++) {
if (strncmp(channels[i].name, name, strlen(name)) == 0) {
// ..and NULL its name (0th character = '\0')
channels[i].name[0] = '\0';
@@ -753,9 +775,9 @@ int removechannel(struct channel *channels, char *name) {
// Check if we have the NAMES for the channel 'name' already.
// Return the 1 if we do, 0 if we don't, or -1 if there's an error.
-int channelgotnames(struct channel *channels, char *name) {
+int channelgotnames(struct channel *channels, int maxchannelcount, char *name) {
debugprint(DEBUG_FULL, "channelgotnames(): given '%s'.\n", name);
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < maxchannelcount; i++) {
if (strncmp(channels[i].name, name, strlen(name)) == 0) {
if (channels[i].gotnames) {
debugprint(DEBUG_FULL, "channelgotnames(): channel '%s' gotnames was set, returning '%d'.\n", channels[i].name, channels[i].gotnames);
@@ -774,7 +796,7 @@ int channelgotnames(struct channel *channels, char *name) {
// Check if we are in a channel named "name" or not.
// Return 1 if we are, or 0 if not.
-int inchannel(struct channel *channels, char *name) {
+int inchannel(struct channel *channels, int maxchannelcount, char *name) {
// Make sure the name doesn't have any trailing CR or LF
// (But only if name is at least two characters long already)
if (strlen(name) >= 2) {
@@ -783,7 +805,7 @@ int inchannel(struct channel *channels, char *name) {
}
}
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < maxchannelcount; i++) {
if (strncmp(channels[i].name, name, strlen(name)) == 0) {
debugprint(DEBUG_FULL, "inchannel(): in channel '%s'.\n", name);
return 1;
@@ -798,9 +820,9 @@ int inchannel(struct channel *channels, char *name) {
// Returns the array index in the 'channels' array of the channel
// named 'channel'.
// Returns -1 if there was an error.
-int channelindex(struct channel *channels, char *name) {
+int channelindex(struct channel *channels, int maxchannelcount, char *name) {
debugprint(DEBUG_FULL, "channelindex(): given '%s'.\n", name);
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < maxchannelcount; i++) {
if (strncmp(channels[i].name, name, strlen(name)) == 0) {
return i;
}
@@ -883,7 +905,7 @@ int doreplay(int sourcefd, int replayseconds, struct client *clients, struct set
extractnickfromprefix(tokens[0], 1);
// Check if we're currently in this channel or if the log line is from us
- if (!inchannel(channels, tokens[2] + offset) || strncmp(tokens[0], ircdstate->ircnick, strlen(tokens[0])) == 0) {
+ if (!inchannel(channels, ircdstate->maxchannelcount, tokens[2] + offset) || strncmp(tokens[0], ircdstate->ircnick, strlen(tokens[0])) == 0) {
debugprint(DEBUG_FULL, "Not sending '%s' replay line '%s'.\n", tokens[1], outgoingmsg);
free(strcopyPtr);
continue;
@@ -1348,7 +1370,7 @@ void replacechar(char *str, char find, char replace) {
// Add nick (passed as a :nick!user@host) to channel 'channel'
// Returns 1 on success or 0 on failure
-int addnicktochannel(char *nickuserhost, char *channel, struct channel *channels) {
+int addnicktochannel(char *nickuserhost, char *channel, struct channel *channels, int maxchannelcount) {
debugprint(DEBUG_FULL, "addnicktochannel(): given '%s' and '%s'.\n", nickuserhost, channel);
// Get the nick from the prefix
@@ -1357,7 +1379,7 @@ int addnicktochannel(char *nickuserhost, char *channel, struct channel *channels
// Make sure the channel exists
int chanfound = 0;
int chanindex;
- for (chanindex = 0; chanindex < MAXCHANNELS; chanindex++) {
+ for (chanindex = 0; chanindex < maxchannelcount; chanindex++) {
if (strlen(channels[chanindex].name) == strlen(channel) && !strcmp(channels[chanindex].name, channel)) {
chanfound = 1;
break;
@@ -1393,7 +1415,7 @@ int addnicktochannel(char *nickuserhost, char *channel, struct channel *channels
// Remove nick (passed as a :nick!user@host) from channel 'channel'
// Returns 1 on success or 0 on failure
-int removenickfromchannel(char *nickuserhost, char *channel, struct channel *channels) {
+int removenickfromchannel(char *nickuserhost, char *channel, struct channel *channels, int maxchannelcount) {
debugprint(DEBUG_FULL, "removenickfromchannel(): given '%s' and '%s'.\n", nickuserhost, channel);
// Get the username from the prefix
@@ -1402,7 +1424,7 @@ int removenickfromchannel(char *nickuserhost, char *channel, struct channel *cha
// Make sure the channel exists
int chanfound = 0;
int chanindex;
- for (chanindex = 0; chanindex < MAXCHANNELS; chanindex++) {
+ for (chanindex = 0; chanindex < maxchannelcount; chanindex++) {
if (strlen(channels[chanindex].name) == strlen(channel) && !strcmp(channels[chanindex].name, channel)) {
chanfound = 1;
break;
@@ -1432,7 +1454,7 @@ int removenickfromchannel(char *nickuserhost, char *channel, struct channel *cha
// Remove nick (passed as a :nick!user@host) from all channels
// Returns 1 on success or 0 on failure
-int removenickfromallchannels(char *nickuserhost, struct channel *channels) {
+int removenickfromallchannels(char *nickuserhost, struct channel *channels, int maxchannelcount) {
debugprint(DEBUG_FULL, "removenickfromallchannels(): given '%s'.\n", nickuserhost);
// Get the nick from the prefix
@@ -1440,12 +1462,12 @@ int removenickfromallchannels(char *nickuserhost, struct channel *channels) {
// Make sure the nick has a length of at least one
if (strlen(nickuserhost) < 1) {
- debugprint(DEBUG_CRIT, "updatenickinallchannels(): nick has no length, returning 0!\n");
+ debugprint(DEBUG_CRIT, "removenickfromallchannels(): nick has no length, returning 0!\n");
return 0;
}
// Go through all channels and remove nick if present
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < maxchannelcount; i++) {
// Don't bother checking this channel index if it isn't used
if (!channels[i].name[0]) {
continue;
@@ -1466,7 +1488,7 @@ int removenickfromallchannels(char *nickuserhost, struct channel *channels) {
// Update old nick (passed as a :nick!user@host) to 'newnick' in all channels
// Returns 1 on success or 0 on failure
-int updatenickinallchannels(char *nickuserhost, char *newnick, struct channel *channels) {
+int updatenickinallchannels(char *nickuserhost, char *newnick, struct channel *channels, int maxchannelcount) {
debugprint(DEBUG_FULL, "updatenickinallchannels(): given '%s' and '%s'.\n", nickuserhost, newnick);
// Get the nick from the prefix
@@ -1482,7 +1504,7 @@ int updatenickinallchannels(char *nickuserhost, char *newnick, struct channel *c
}
// Go through all channels and update nick if present
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < maxchannelcount; i++) {
// Go through all nicks in channel
for (int j = 0; j < MAXCHANNICKS; j++) {
// Update the nick in the channel if present
@@ -1498,7 +1520,7 @@ int updatenickinallchannels(char *nickuserhost, char *newnick, struct channel *c
// Populate our channels struct with all nicks in a RPL_NAMREPLY
// Returns 1 on success or 0 on failure
-int addnamereplytochannel(char *namereply, struct channel *channels) {
+int addnamereplytochannel(char *namereply, struct channel *channels, int maxchannelcount) {
//:irc.tghost.co.uk 353 blabounce = #blabouncer :blabounce bbnick ~@l_bratch @l_blabnc Hughbla Bratchbot ars
debugprint(DEBUG_FULL, "addnamereplytochannel(): given '%s'.\n", namereply);
@@ -1572,7 +1594,7 @@ int addnamereplytochannel(char *namereply, struct channel *channels) {
for (int i = 0; i < nickcount; i++) {
stripprefixesfromnick(nicks[i]);
// And add to the channel
- addnicktochannel(nicks[i], channelname, channels);
+ addnicktochannel(nicks[i], channelname, channels, maxchannelcount);
}
return 1;
diff --git a/functions.h b/functions.h
index 7a3e398..49417e8 100644
--- a/functions.h
+++ b/functions.h
@@ -118,28 +118,28 @@ int sendtoserver(SSL *server_ssl, char *strsrc, int str_len, int clientfd, struc
// Also set the pending statuses to 0
int disconnectclient(int fd, struct client *clients, struct ircdstate *ircdstate, struct settings *settings, struct clientcodes *clientcodes);
-int createchannel(struct channel *channels, char *name, char *topic, char *topicwho, char *topicwhen);
+int createchannel(struct channel *channels, struct ircdstate *ircdstate, char *name, char *topic, char *topicwho, char *topicwhen);
-int setchanneltopicwhotime(struct channel *channels, char *channelname, char *who, char *when);
+int setchanneltopicwhotime(struct channel *channels, int maxchannelcount, char *channelname, char *who, char *when);
-int setchanneltopic(struct channel *channels, char *channelname, char *topic);
+int setchanneltopic(struct channel *channels, int maxchannelcount, char *channelname, char *topic);
-int getchannelcount(struct channel *channels);
+int getchannelcount(struct channel *channels, int maxchannelcount);
-int removechannel(struct channel *channels, char *name);
+int removechannel(struct channel *channels, int maxchannelcount, char *name);
// Check if we have the NAMES for the channel 'name' already.
// Return the 1 if we do, 0 if we don't, or -1 if there's an error.
-int channelgotnames(struct channel *channels, char *name);
+int channelgotnames(struct channel *channels, int maxchannelcount, char *name);
// Check if we are in a channel named "name" or not.
// Return 1 if we are, or 0 if not.
-int inchannel(struct channel *channels, char *name);
+int inchannel(struct channel *channels, int maxchannelcount, char *name);
// Returns the array index in the 'channels' array of the channel
// named 'channel'.
// Returns -1 if there was an error.
-int channelindex(struct channel *channels, char *name);
+int channelindex(struct channel *channels, int maxchannelcount, char *name);
// Send the requested number of lines of replay log to the requested client.
// 'sourcefd' is the client to send to, and replayseconds is the number of
@@ -196,23 +196,23 @@ void replacechar(char *str, char find, char replace);
// Add nick (passed as a :nick!user@host) to channel 'channel'
// Returns 1 on success or 0 on failure
-int addnicktochannel(char *nickuserhost, char *channel, struct channel *channels);
+int addnicktochannel(char *nickuserhost, char *channel, struct channel *channels, int maxchannelcount);
// Remove nick(passed as a :nick!user@host) from channel 'channel'
// Returns 1 on success or 0 on failure
-int removenickfromchannel(char *nickuserhost, char *channel, struct channel *channels);
+int removenickfromchannel(char *nickuserhost, char *channel, struct channel *channels, int maxchannelcount);
// Remove nick (passed as a :nick!user@host) from all channels
// Returns 1 on success or 0 on failure
-int removenickfromallchannels(char *nickuserhost, struct channel *channels);
+int removenickfromallchannels(char *nickuserhost, struct channel *channels, int maxchannelcount);
// Update old nick (passed as a :nick!user@host) to 'newnick' in all channels
// Returns 1 on success or 0 on failure
-int updatenickinallchannels(char *nickuserhost, char *newnick, struct channel *channels);
+int updatenickinallchannels(char *nickuserhost, char *newnick, struct channel *channels, int maxchannelcount);
// Populate our channels struct with all nicks in a RPL_NAMREPLY
// Returns 1 on success or 0 on failure
-int addnamereplytochannel(char *namereply, struct channel *channels);
+int addnamereplytochannel(char *namereply, struct channel *channels, int maxchannelcount);
// Strips all leading prefixes (colons, user modes) from a nick
void stripprefixesfromnick(char *nick);
diff --git a/message.c b/message.c
index 8431c31..e30a247 100644
--- a/message.c
+++ b/message.c
@@ -116,14 +116,11 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
}
// Next re-join channels
- // Storing separately so we can skip over blank channels.
- int channelcount = getchannelcount(channels);
- // Join all the channels and make a note of the channel count
- for (int i = 0; i < channelcount; i++) {
- // Skip this one and increment channelcount if it's a blank channel
+ // Join all the channels
+ for (int i = 0; i < ircdstate->maxchannelcount; i++) {
+ // Skip this one if it's a blank channel
if (!channels[i].name[0]) {
- debugprint(DEBUG_FULL, "Reconnection: Skipping channel[%d], incrementing channelcount.\n", i);
- channelcount++;
+ debugprint(DEBUG_FULL, "Reconnection: Skipping blank channel channel[%d].\n", i);
continue;
}
@@ -197,13 +194,13 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
debugprint(DEBUG_FULL, "Server JOIN: nick is ours ('%s' vs '%s').\n", prefixcopy, ircdstate->ircnick);
// TODO - Saner way to initialise this since we don't have the variables yet?
// TODO - Defaulting to type '=' which is "public" since I don't know what else to guess.
- createchannel(channels, tokens[2], "TOPIC", "TOPICWHO", "0");
+ createchannel(channels, ircdstate, tokens[2], "TOPIC", "TOPICWHO", "0");
} else {
debugprint(DEBUG_FULL, "Server JOIN: nick is NOT ours ('%s' vs '%s').\n", prefixcopy, ircdstate->ircnick);
}
// Add the JOINing nick to our local channel struct
- if (!addnicktochannel(tokens[0], tokens[2], channels)) {
+ if (!addnicktochannel(tokens[0], tokens[2], channels, ircdstate->maxchannelcount)) {
debugprint(DEBUG_CRIT, "Failed to add nick to channel struct.\n");
}
@@ -236,13 +233,13 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
extractnickfromprefix(prefixcopy, 1);
if (strncmp(prefixcopy, ircdstate->ircnick, strlen(tokens[0])) == 0) {
debugprint(DEBUG_FULL, "Server PART: nick is ours ('%s' vs '%s').\n", prefixcopy, ircdstate->ircnick);
- removechannel(channels, tokens[2]);
+ removechannel(channels, ircdstate->maxchannelcount, tokens[2]);
} else {
debugprint(DEBUG_FULL, "Server PART: nick is NOT ours ('%s' vs '%s').\n", prefixcopy, ircdstate->ircnick);
}
// Remove the PARTing nick from our local channel struct
- if (!removenickfromchannel(tokens[0], tokens[2], channels)) {
+ if (!removenickfromchannel(tokens[0], tokens[2], channels, ircdstate->maxchannelcount)) {
debugprint(DEBUG_CRIT, "Failed to remove nick from channel struct.\n");
}
@@ -280,7 +277,7 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
char quitnick[MAXDATASIZE];
strcpy(quitnick, tokens[0]);
extractnickfromprefix(quitnick, 1);
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < ircdstate->maxchannelcount; i++) {
if (channels[i].name[0]) {
for (int j = 0; j < MAXCHANNICKS; j++) {
if (strlen(channels[i].nicks[j]) == strlen(quitnick) && !strcmp(channels[i].nicks[j], quitnick)) {
@@ -295,7 +292,7 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
}
// Remove the QUITting nick from our local channel struct
- if (!removenickfromallchannels(tokens[0], channels)) {
+ if (!removenickfromallchannels(tokens[0], channels, ircdstate->maxchannelcount)) {
debugprint(DEBUG_CRIT, "Failed to remove nick from channel structs.\n");
}
@@ -306,9 +303,9 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
// Server 331 (RPL_NOTOPIC) the topic is blank which we track by having a set timestamp of 0
if (strncmp(tokens[1], "331", strlen(tokens[1])) == 0) {
// Might as well blank our current topic value
- setchanneltopic(channels, tokens[3], "");
+ setchanneltopic(channels, ircdstate->maxchannelcount, tokens[3], "");
// Set the topic timestamp to 0 which we use to determine an "unset" topic when new clients connect
- setchanneltopicwhotime(channels, tokens[3], "", "0");
+ setchanneltopicwhotime(channels, ircdstate->maxchannelcount, tokens[3], "", "0");
// Server 332 (RPL_TOPIC) set the channel topic
} else if (strncmp(tokens[1], "332", strlen(tokens[1])) == 0) {
debugprint(DEBUG_FULL, "Server 332 (RPL_TOPIC) found, extracting topic and storing in channel struct.\n");
@@ -316,17 +313,17 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
// Copy to a temporary string so we still have the original in case we need it
char *topiccopy = strdup(str);
extractfinalparameter(topiccopy);
- setchanneltopic(channels, tokens[3], topiccopy);
+ setchanneltopic(channels, ircdstate->maxchannelcount, tokens[3], topiccopy);
free(topiccopy);
// Server 333 (RPL_TOPICWHOTIME) set the channel topic setter and the time it was set
} else if (strncmp(tokens[1], "333", strlen(tokens[1])) == 0) {
debugprint(DEBUG_FULL, "Server 333 (RPL_TOPICWHOTIME) found, extracting who and when, and storing in channel struct.\n");
- setchanneltopicwhotime(channels, tokens[3], tokens[4], tokens[5]);
+ setchanneltopicwhotime(channels, ircdstate->maxchannelcount, tokens[3], tokens[4], tokens[5]);
// Server 353 (RPL_NAMREPLY), relay to all clients if we've just JOINed the channel, or relay to any clients
// who were pending RPL_NAMREPLYs if it's an existing channel.
} else if (strncmp(tokens[1], "353", strlen(tokens[1])) == 0) {
// It must be a new channel and we don't have the NAMES
- if (!channelgotnames(channels, tokens[4])) {
+ if (!channelgotnames(channels, ircdstate->maxchannelcount, tokens[4])) {
debugprint(DEBUG_FULL, "Server 353 received for a new channel, sending to all clients.\n");
// Relay to all clients
sendtoallclients(clients, str, sourcefd, settings);
@@ -344,7 +341,7 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
}
// Update our local channels struct with all nicks from this RPL_NAMREPLY
- if (!addnamereplytochannel(str, channels)) {
+ if (!addnamereplytochannel(str, channels, ircdstate->maxchannelcount)) {
debugprint(DEBUG_CRIT, "Failed to add RPL_NAMREPLY to channels.\n");
}
@@ -354,10 +351,10 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
} else if (strncmp(tokens[1], "366", strlen(tokens[1])) == 0) {
int channelelement;
// It must be a new channel and we don't have the NAMES
- if (!(channelelement = channelgotnames(channels, tokens[3]))) {
+ if (!(channelelement = channelgotnames(channels, ircdstate->maxchannelcount, tokens[3]))) {
debugprint(DEBUG_FULL, "Server 366 received for a new channel, sending to all clients and set as got names.\n");
// We have the names now!
- channels[channelindex(channels, tokens[3])].gotnames = 1;
+ channels[channelindex(channels, ircdstate->maxchannelcount, tokens[3])].gotnames = 1;
// Relay to all clients
sendtoallclients(clients, str, sourcefd, settings);
} else {
@@ -389,7 +386,7 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
// Copy to a temporary string so we still have the original in case we need it
char *topiccopy = strdup(str);
extractfinalparameter(topiccopy);
- setchanneltopic(channels, tokens[2], topiccopy);
+ setchanneltopic(channels, ircdstate->maxchannelcount, tokens[2], topiccopy);
// Extract the author and get the current timestamp
@@ -405,7 +402,7 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
snprintf(timenowstr, timenowlen + 1, "%ld", timenow);
// Actually set the author and timestamp
- setchanneltopicwhotime(channels, tokens[2], prefixcopy, timenowstr);
+ setchanneltopicwhotime(channels, ircdstate->maxchannelcount, tokens[2], prefixcopy, timenowstr);
// And then finally relay to all clients
sendtoallclients(clients, str, sourcefd, settings);
@@ -493,7 +490,7 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
char oldnick[MAXDATASIZE];
strcpy(oldnick, tokens[0]);
extractnickfromprefix(oldnick, 1);
- for (int i = 0; i < MAXCHANNELS; i++) {
+ for (int i = 0; i < ircdstate->maxchannelcount; i++) {
if (channels[i].name[0]) {
for (int j = 0; j < MAXCHANNICKS; j++) {
if (strlen(channels[i].nicks[j]) == strlen(oldnick) && !strcmp(channels[i].nicks[j], oldnick)) {
@@ -508,7 +505,7 @@ int processservermessage(SSL *server_ssl, char *str, struct client *clients, int
}
// Update old nick to the new nick in our local channel struct
- if (!updatenickinallchannels(tokens[0], tokens[2], channels)) {
+ if (!updatenickinallchannels(tokens[0], tokens[2], channels, ircdstate->maxchannelcount)) {
debugprint(DEBUG_CRIT, "Failed to update old nick to new nick in channels.\n");
}
@@ -970,19 +967,18 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int
snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER QUIT [quit message]\" (To quit blabouncer, optionally sending [quit message] to the server.)", ircdstate->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
- // Get the channel count so we can enumerate over all channels.
- // Storing separately so we can skip over blank channels.
- int channelcount = getchannelcount(channels);
+ // Get the channel count so we can iterate over all channels.
+ int channelcount = getchannelcount(channels, ircdstate->maxchannelcount);
// Set the client as pending RPL_NAMREPLYs for 'channelcount' channels
debugprint(DEBUG_FULL, "Setting pendingnames to '%d' for client with fd '%d'.\n", channelcount, sourcefd);
clients[arrindex(clients, sourcefd)].pendingnames = channelcount;
// Get client to join channels, and tell client about those channels
- for (int i = 0; i < channelcount; i++) {
+ for (int i = 0; i < ircdstate->maxchannelcount; i++) {
debugprint(DEBUG_FULL, "JOINing channel[%d] out of %d.\n", i, channelcount);
// Skip this one and increment channelcount if it's a blank channel
if (!channels[i].name[0]) {
- debugprint(DEBUG_FULL, "Skipping channel[%d], incrementing channelcount.\n", i);
+ debugprint(DEBUG_FULL, "Actually, skipping blank channel channel[%d].\n", i);
channelcount++;
continue;
}
diff --git a/structures.h b/structures.h
index 0fbebff..26b7439 100644
--- a/structures.h
+++ b/structures.h
@@ -55,6 +55,7 @@ struct ircdstate {
int clientchangetime; // The last time a client registered or disconnected
int clientsnonetime; // The last time there were no clients registered
int launchtime; // The time blabouncer was launched
+ int maxchannelcount; // The maximum number of channels we've ever been in (so we know how much of the channels struct is initialised)
};
// Structure of settings either to be read from the configuration file or set/changed at runtime