From 0883de2c491a8c79aec13d25bab429aea4362a10 Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Sun, 22 Dec 2019 20:16:57 +0000 Subject: Significantly reduce memory usage by only initialising channel struct elements when they are used for the first time. --- functions.c | 126 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 74 insertions(+), 52 deletions(-) (limited to 'functions.c') 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; -- cgit v1.2.3