diff options
-rw-r--r-- | include/inspircd.h | 10 | ||||
-rw-r--r-- | src/channels.cpp | 26 | ||||
-rw-r--r-- | src/cmd_kill.cpp | 6 | ||||
-rw-r--r-- | src/cmd_list.cpp | 2 | ||||
-rw-r--r-- | src/cmd_quit.cpp | 11 | ||||
-rw-r--r-- | src/cmd_rehash.cpp | 1 | ||||
-rw-r--r-- | src/cmd_stats.cpp | 6 | ||||
-rw-r--r-- | src/cmd_trace.cpp | 2 | ||||
-rw-r--r-- | src/cmd_who.cpp | 2 | ||||
-rw-r--r-- | src/command_parse.cpp | 83 | ||||
-rw-r--r-- | src/commands.cpp | 12 | ||||
-rw-r--r-- | src/cull_list.cpp | 16 | ||||
-rw-r--r-- | src/helperfuncs.cpp | 26 | ||||
-rw-r--r-- | src/inspircd.cpp | 36 | ||||
-rw-r--r-- | src/mode.cpp | 4 | ||||
-rw-r--r-- | src/modules.cpp | 3 | ||||
-rw-r--r-- | src/modules/m_check.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_httpd_stats.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_redirect.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_safelist.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_spanningtree.cpp | 36 | ||||
-rw-r--r-- | src/modules/m_spy.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_tline.cpp | 2 | ||||
-rw-r--r-- | src/users.cpp | 35 |
24 files changed, 136 insertions, 195 deletions
diff --git a/include/inspircd.h b/include/inspircd.h index 9f2ae630a..3d9002f53 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -401,11 +401,11 @@ class InspIRCd : public classbase /** Client list, a hash_map containing all clients, local and remote */ - user_hash clientlist; + user_hash* clientlist; /** Channel list, a hash_map containing all channels */ - chan_hash chanlist; + chan_hash* chanlist; /** Local client list, a vector containing only local clients */ @@ -1129,6 +1129,12 @@ class InspIRCd : public classbase */ void Cleanup(); + /** This copies the user and channel hash_maps into new hash maps. + * This frees memory used by the hash_map allocator (which it neglects + * to free, most of the time, using tons of ram) + */ + void RehashUsersAndChans(); + /** Begin execution of the server. * NOTE: this function NEVER returns. Internally, * after performing some initialisation routines, diff --git a/src/channels.cpp b/src/channels.cpp index 8a44479e0..ea7edd71f 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -217,7 +217,7 @@ chanrec* chanrec::JoinUser(InspIRCd* Instance, userrec *user, const char* cn, bo /* create a new one */ Ptr = new chanrec(Instance); - Instance->chanlist[cname] = Ptr; + (*(Instance->chanlist))[cname] = Ptr; strlcpy(Ptr->name, cname,CHANMAX); @@ -341,12 +341,12 @@ chanrec* chanrec::JoinUser(InspIRCd* Instance, userrec *user, const char* cn, bo { Instance->Log(DEBUG,"BLAMMO, Whacking channel."); /* Things went seriously pear shaped, so take this away. bwahaha. */ - chan_hash::iterator n = Instance->chanlist.find(cname); - if (n != Instance->chanlist.end()) + chan_hash::iterator n = Instance->chanlist->find(cname); + if (n != Instance->chanlist->end()) { Ptr->DelUser(user); DELETE(Ptr); - Instance->chanlist.erase(n); + Instance->chanlist->erase(n); } } @@ -464,13 +464,13 @@ long chanrec::PartUser(userrec *user, const char* reason) if (!this->DelUser(user)) /* if there are no users left on the channel... */ { - chan_hash::iterator iter = ServerInstance->chanlist.find(this->name); + chan_hash::iterator iter = ServerInstance->chanlist->find(this->name); /* kill the record */ - if (iter != ServerInstance->chanlist.end()) + if (iter != ServerInstance->chanlist->end()) { ServerInstance->Log(DEBUG,"del_channel: destroyed: %s", this->name); FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this)); - ServerInstance->chanlist.erase(iter); + ServerInstance->chanlist->erase(iter); } return 0; } @@ -507,12 +507,12 @@ long chanrec::ServerKickUser(userrec* user, const char* reason, bool triggereven if (!this->DelUser(user)) { - chan_hash::iterator iter = ServerInstance->chanlist.find(this->name); + chan_hash::iterator iter = ServerInstance->chanlist->find(this->name); /* kill the record */ - if (iter != ServerInstance->chanlist.end()) + if (iter != ServerInstance->chanlist->end()) { FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this)); - ServerInstance->chanlist.erase(iter); + ServerInstance->chanlist->erase(iter); } return 0; } @@ -580,13 +580,13 @@ long chanrec::KickUser(userrec *src, userrec *user, const char* reason) if (!this->DelUser(user)) /* if there are no users left on the channel */ { - chan_hash::iterator iter = ServerInstance->chanlist.find(this->name); + chan_hash::iterator iter = ServerInstance->chanlist->find(this->name); /* kill the record */ - if (iter != ServerInstance->chanlist.end()) + if (iter != ServerInstance->chanlist->end()) { FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this)); - ServerInstance->chanlist.erase(iter); + ServerInstance->chanlist->erase(iter); } return 0; } diff --git a/src/cmd_kill.cpp b/src/cmd_kill.cpp index bc59f8492..001f48e2c 100644 --- a/src/cmd_kill.cpp +++ b/src/cmd_kill.cpp @@ -56,12 +56,12 @@ CmdResult cmd_kill::Handle (const char** parameters, int pcnt, userrec *user) u->WriteCommonExcept("QUIT :%s", killreason); FOREACH_MOD(I_OnRemoteKill, OnRemoteKill(user, u, killreason)); - user_hash::iterator iter = ServerInstance->clientlist.find(u->nick); + user_hash::iterator iter = ServerInstance->clientlist->find(u->nick); - if (iter != ServerInstance->clientlist.end()) + if (iter != ServerInstance->clientlist->end()) { ServerInstance->Log(DEBUG,"deleting user hash value %d", iter->second); - ServerInstance->clientlist.erase(iter); + ServerInstance->clientlist->erase(iter); } if (u->registered == REG_ALL) diff --git a/src/cmd_list.cpp b/src/cmd_list.cpp index b1bb44172..920d77f34 100644 --- a/src/cmd_list.cpp +++ b/src/cmd_list.cpp @@ -31,7 +31,7 @@ CmdResult cmd_list::Handle (const char** parameters, int pcnt, userrec *user) if ((pcnt == 1) && (*parameters[0] == '<')) pcnt = 0; - for (chan_hash::const_iterator i = ServerInstance->chanlist.begin(); i != ServerInstance->chanlist.end(); i++) + for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) { // attempt to match a glob pattern if (pcnt && !match(i->second->name, parameters[0])) diff --git a/src/cmd_quit.cpp b/src/cmd_quit.cpp index 0065987cf..db71bbdb1 100644 --- a/src/cmd_quit.cpp +++ b/src/cmd_quit.cpp @@ -26,7 +26,7 @@ extern "C" command_t* init_command(InspIRCd* Instance) CmdResult cmd_quit::Handle (const char** parameters, int pcnt, userrec *user) { - user_hash::iterator iter = ServerInstance->clientlist.find(user->nick); + user_hash::iterator iter = ServerInstance->clientlist->find(user->nick); char reason[MAXBUF]; std::string quitmsg = "Client exited"; @@ -82,17 +82,18 @@ CmdResult cmd_quit::Handle (const char** parameters, int pcnt, userrec *user) if (IS_LOCAL(user)) { ServerInstance->SE->DelFd(user); - if (find(ServerInstance->local_users.begin(),ServerInstance->local_users.end(),user) != ServerInstance->local_users.end()) + std::vector<userrec*>::iterator x = find(ServerInstance->local_users.begin(),ServerInstance->local_users.end(),user); + if (x != ServerInstance->local_users.end()) { ServerInstance->Log(DEBUG,"Delete local user"); - ServerInstance->local_users.erase(find(ServerInstance->local_users.begin(),ServerInstance->local_users.end(),user)); + ServerInstance->local_users.erase(x); } user->CloseSocket(); } - if (iter != ServerInstance->clientlist.end()) + if (iter != ServerInstance->clientlist->end()) { - ServerInstance->clientlist.erase(iter); + ServerInstance->clientlist->erase(iter); } if (user->registered == REG_ALL) { diff --git a/src/cmd_rehash.cpp b/src/cmd_rehash.cpp index 47554d5ac..518b7fbf4 100644 --- a/src/cmd_rehash.cpp +++ b/src/cmd_rehash.cpp @@ -37,6 +37,7 @@ CmdResult cmd_rehash::Handle (const char** parameters, int pcnt, userrec *user) ServerInstance->WriteOpers("%s is rehashing config file %s",user->nick,ServerConfig::CleanFilename(CONFIG_FILE)); ServerInstance->CloseLog(); ServerInstance->OpenLog(NULL,0); + ServerInstance->RehashUsersAndChans(); ServerInstance->Config->Read(false,user); } if (old_disabled != ServerInstance->Config->DisabledCommands) diff --git a/src/cmd_stats.cpp b/src/cmd_stats.cpp index f31248659..f609864a9 100644 --- a/src/cmd_stats.cpp +++ b/src/cmd_stats.cpp @@ -120,7 +120,7 @@ void DoStats(InspIRCd* ServerInstance, char statschar, userrec* user, string_lis case 'P': { int idx = 0; - for (user_hash::iterator i = ServerInstance->clientlist.begin(); i != ServerInstance->clientlist.end(); i++) + for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++) { if ((*i->second->oper) && (!ServerInstance->ULine(i->second->server))) { @@ -169,8 +169,8 @@ void DoStats(InspIRCd* ServerInstance, char statschar, userrec* user, string_lis { rusage R; results.push_back(sn+" 240 "+user->nick+" :InspIRCd(CLASS) "+ConvToStr(sizeof(InspIRCd))+" bytes"); - results.push_back(sn+" 249 "+user->nick+" :Users(HASH_MAP) "+ConvToStr(ServerInstance->clientlist.size())+" ("+ConvToStr(ServerInstance->clientlist.size()*sizeof(userrec))+" bytes, "+ConvToStr(ServerInstance->clientlist.bucket_count())+" buckets)"); - results.push_back(sn+" 249 "+user->nick+" :Channels(HASH_MAP) "+ConvToStr(ServerInstance->chanlist.size())+" ("+ConvToStr(ServerInstance->chanlist.size()*sizeof(chanrec))+" bytes, "+ConvToStr(ServerInstance->chanlist.bucket_count())+" buckets)"); + results.push_back(sn+" 249 "+user->nick+" :Users(HASH_MAP) "+ConvToStr(ServerInstance->clientlist->size())+" ("+ConvToStr(ServerInstance->clientlist->size()*sizeof(userrec))+" bytes, "+ConvToStr(ServerInstance->clientlist->bucket_count())+" buckets)"); + results.push_back(sn+" 249 "+user->nick+" :Channels(HASH_MAP) "+ConvToStr(ServerInstance->chanlist->size())+" ("+ConvToStr(ServerInstance->chanlist->size()*sizeof(chanrec))+" bytes, "+ConvToStr(ServerInstance->chanlist->bucket_count())+" buckets)"); results.push_back(sn+" 249 "+user->nick+" :Commands(VECTOR) "+ConvToStr(ServerInstance->Parser->cmdlist.size())+" ("+ConvToStr(ServerInstance->Parser->cmdlist.size()*sizeof(command_t))+" bytes)"); results.push_back(sn+" 249 "+user->nick+" :MOTD(VECTOR) "+ConvToStr(ServerInstance->Config->MOTD.size())+", RULES(VECTOR) "+ConvToStr(ServerInstance->Config->RULES.size())); results.push_back(sn+" 249 "+user->nick+" :Modules(VECTOR) "+ConvToStr(ServerInstance->modules.size())+" ("+ConvToStr(ServerInstance->modules.size()*sizeof(Module))+")"); diff --git a/src/cmd_trace.cpp b/src/cmd_trace.cpp index d34252f38..23a72f199 100644 --- a/src/cmd_trace.cpp +++ b/src/cmd_trace.cpp @@ -24,7 +24,7 @@ extern "C" command_t* init_command(InspIRCd* Instance) CmdResult cmd_trace::Handle (const char** parameters, int pcnt, userrec *user) { - for (user_hash::iterator i = ServerInstance->clientlist.begin(); i != ServerInstance->clientlist.end(); i++) + for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++) { if (i->second) { diff --git a/src/cmd_who.cpp b/src/cmd_who.cpp index bd9457d6f..11b001eab 100644 --- a/src/cmd_who.cpp +++ b/src/cmd_who.cpp @@ -234,7 +234,7 @@ CmdResult cmd_who::Handle (const char** parameters, int pcnt, userrec *user) } else { - for (user_hash::iterator i = ServerInstance->clientlist.begin(); i != ServerInstance->clientlist.end(); i++) + for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++) { if (whomatch(i->second, matchtext, opt_realname, opt_showrealhost, opt_mode)) { diff --git a/src/command_parse.cpp b/src/command_parse.cpp index cb43df1a1..07b41c4cb 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -106,89 +106,6 @@ long InspIRCd::Duration(const char* str) return total; } -/* All other ircds when doing this check usually just look for a string of *@* or *. We're smarter than that, though. */ - -bool InspIRCd::HostMatchesEveryone(const std::string &mask, userrec* user) -{ - char buffer[MAXBUF]; - char itrigger[MAXBUF]; - long matches = 0; - - if (!Config->ConfValue(Config->config_data, "insane","trigger", 0, itrigger, MAXBUF)) - strlcpy(itrigger,"95.5",MAXBUF); - - if (Config->ConfValueBool(Config->config_data, "insane","hostmasks", 0)) - return false; - - for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++) - { - strlcpy(buffer,u->second->ident,MAXBUF); - charlcat(buffer,'@',MAXBUF); - strlcat(buffer,u->second->host,MAXBUF); - if (match(buffer,mask.c_str())) - matches++; - } - float percent = ((float)matches / (float)clientlist.size()) * 100; - if (percent > (float)atof(itrigger)) - { - WriteOpers("*** \2WARNING\2: %s tried to set a G/K/E line mask of %s, which covers %.2f%% of the network!",user->nick,mask.c_str(),percent); - return true; - } - return false; -} - -bool InspIRCd::IPMatchesEveryone(const std::string &ip, userrec* user) -{ - char itrigger[MAXBUF]; - long matches = 0; - - if (!Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF)) - strlcpy(itrigger,"95.5",MAXBUF); - - if (Config->ConfValueBool(Config->config_data, "insane","ipmasks",0)) - return false; - - for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++) - { - if (match(u->second->GetIPString(),ip.c_str(),true)) - matches++; - } - - float percent = ((float)matches / (float)clientlist.size()) * 100; - if (percent > (float)atof(itrigger)) - { - WriteOpers("*** \2WARNING\2: %s tried to set a Z line mask of %s, which covers %.2f%% of the network!",user->nick,ip.c_str(),percent); - return true; - } - return false; -} - -bool InspIRCd::NickMatchesEveryone(const std::string &nick, userrec* user) -{ - char itrigger[MAXBUF]; - long matches = 0; - - if (!Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF)) - strlcpy(itrigger,"95.5",MAXBUF); - - if (Config->ConfValueBool(Config->config_data, "insane","nickmasks",0)) - return false; - - for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++) - { - if (match(u->second->nick,nick.c_str())) - matches++; - } - - float percent = ((float)matches / (float)clientlist.size()) * 100; - if (percent > (float)atof(itrigger)) - { - WriteOpers("*** \2WARNING\2: %s tried to set a Q line mask of %s, which covers %.2f%% of the network!",user->nick,nick.c_str(),percent); - return true; - } - return false; -} - /* LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list. * There are two overriden versions of this method, one of which takes two potential lists and the other takes one. * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once, diff --git a/src/commands.cpp b/src/commands.cpp index 9b127b8bf..aa43685d4 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -113,7 +113,7 @@ bool InspIRCd::HostMatchesEveryone(const std::string &mask, userrec* user) if (Config->ConfValueBool(Config->config_data, "insane","hostmasks", 0)) return false; - for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++) + for (user_hash::iterator u = clientlist->begin(); u != clientlist->end(); u++) { strlcpy(buffer,u->second->ident,MAXBUF); charlcat(buffer,'@',MAXBUF); @@ -121,7 +121,7 @@ bool InspIRCd::HostMatchesEveryone(const std::string &mask, userrec* user) if (match(buffer,mask.c_str())) matches++; } - float percent = ((float)matches / (float)clientlist.size()) * 100; + float percent = ((float)matches / (float)clientlist->size()) * 100; if (percent > (float)atof(itrigger)) { WriteOpers("*** \2WARNING\2: %s tried to set a G/K/E line mask of %s, which covers %.2f%% of the network!",user->nick,mask.c_str(),percent); @@ -141,13 +141,13 @@ bool InspIRCd::IPMatchesEveryone(const std::string &ip, userrec* user) if (Config->ConfValueBool(Config->config_data, "insane","ipmasks",0)) return false; - for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++) + for (user_hash::iterator u = clientlist->begin(); u != clientlist->end(); u++) { if (match(u->second->GetIPString(),ip.c_str(),true)) matches++; } - float percent = ((float)matches / (float)clientlist.size()) * 100; + float percent = ((float)matches / (float)clientlist->size()) * 100; if (percent > (float)atof(itrigger)) { WriteOpers("*** \2WARNING\2: %s tried to set a Z line mask of %s, which covers %.2f%% of the network!",user->nick,ip.c_str(),percent); @@ -167,13 +167,13 @@ bool InspIRCd::NickMatchesEveryone(const std::string &nick, userrec* user) if (Config->ConfValueBool(Config->config_data, "insane","nickmasks",0)) return false; - for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++) + for (user_hash::iterator u = clientlist->begin(); u != clientlist->end(); u++) { if (match(u->second->nick,nick.c_str())) matches++; } - float percent = ((float)matches / (float)clientlist.size()) * 100; + float percent = ((float)matches / (float)clientlist->size()) * 100; if (percent > (float)atof(itrigger)) { WriteOpers("*** \2WARNING\2: %s tried to set a Q line mask of %s, which covers %.2f%% of the network!",user->nick,nick.c_str(),percent); diff --git a/src/cull_list.cpp b/src/cull_list.cpp index 628c80019..b19054b0d 100644 --- a/src/cull_list.cpp +++ b/src/cull_list.cpp @@ -25,22 +25,8 @@ bool CullList::IsValid(userrec* user) if (es != exempt.end()) esignon = es->second; - for (user_hash::iterator u = ServerInstance->clientlist.begin(); u != ServerInstance->clientlist.end(); u++) + for (user_hash::iterator u = ServerInstance->clientlist->begin(); u != ServerInstance->clientlist->end(); u++) { - /* - * BUGFIX - * - * Because there is an undetermined period of time between a user existing, - * and this function being called, we have to check for the following condition: - * - * Between CullList::AddItem(u) being called, and CullList::IsValid(u) being called, - * the user with the pointer u has quit, but only to be REPLACED WITH A NEW USER WHO - * BECAUSE OF ALLOCATION RULES, HAS THE SAME MEMORY ADDRESS! To prevent this, we - * cross reference each pointer to the user's signon time, and if the signon times - * do not match, we return false here to indicate this user is NOT valid as it - * seems to differ from the pointer snapshot we got a few seconds earlier. Should - * prevent a few random crashes during netsplits. - */ if (user == u->second) return (u->second->signon == esignon); } diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp index 4f303d32c..506b6e2d6 100644 --- a/src/helperfuncs.cpp +++ b/src/helperfuncs.cpp @@ -228,9 +228,9 @@ void InspIRCd::WriteMode(const char* modes, int flags, const char* text, ...) userrec* InspIRCd::FindNick(const std::string &nick) { - user_hash::iterator iter = clientlist.find(nick); + user_hash::iterator iter = clientlist->find(nick); - if (iter == clientlist.end()) + if (iter == clientlist->end()) /* Couldn't find it */ return NULL; @@ -239,9 +239,9 @@ userrec* InspIRCd::FindNick(const std::string &nick) userrec* InspIRCd::FindNick(const char* nick) { - user_hash::iterator iter = clientlist.find(nick); + user_hash::iterator iter = clientlist->find(nick); - if (iter == clientlist.end()) + if (iter == clientlist->end()) return NULL; return iter->second; @@ -251,9 +251,9 @@ userrec* InspIRCd::FindNick(const char* nick) chanrec* InspIRCd::FindChan(const char* chan) { - chan_hash::iterator iter = chanlist.find(chan); + chan_hash::iterator iter = chanlist->find(chan); - if (iter == chanlist.end()) + if (iter == chanlist->end()) /* Couldn't find it */ return NULL; @@ -262,9 +262,9 @@ chanrec* InspIRCd::FindChan(const char* chan) chanrec* InspIRCd::FindChan(const std::string &chan) { - chan_hash::iterator iter = chanlist.find(chan); + chan_hash::iterator iter = chanlist->find(chan); - if (iter == chanlist.end()) + if (iter == chanlist->end()) /* Couldn't find it */ return NULL; @@ -299,20 +299,20 @@ void InspIRCd::SendError(const std::string &s) // this function counts all users connected, wether they are registered or NOT. int InspIRCd::UserCount() { - return clientlist.size(); + return clientlist->size(); } // this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state int InspIRCd::RegisteredUserCount() { - return clientlist.size() - this->UnregisteredUserCount(); + return clientlist->size() - this->UnregisteredUserCount(); } int InspIRCd::InvisibleUserCount() { int c = 0; - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + for (user_hash::const_iterator i = clientlist->begin(); i != clientlist->end(); i++) { c += ((i->second->registered == REG_ALL) && (i->second->modes[UM_INVISIBLE])); } @@ -324,7 +324,7 @@ int InspIRCd::OperCount() { int c = 0; - for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + for (user_hash::const_iterator i = clientlist->begin(); i != clientlist->end(); i++) { if (*(i->second->oper)) c++; @@ -348,7 +348,7 @@ int InspIRCd::UnregisteredUserCount() long InspIRCd::ChannelCount() { - return chanlist.size(); + return chanlist->size(); } long InspIRCd::LocalUserCount() diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 6b9359751..5cfb55ab1 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -138,10 +138,37 @@ void InspIRCd::Rehash(int status) SI->WriteOpers("Rehashing config file %s due to SIGHUP",ServerConfig::CleanFilename(CONFIG_FILE)); SI->CloseLog(); SI->OpenLog(NULL,0); + SI->RehashUsersAndChans(); SI->Config->Read(false,NULL); FOREACH_MOD_I(SI,I_OnRehash,OnRehash("")); } +/** Because hash_map doesnt free its buckets when we delete items (this is a 'feature') + * we must occasionally rehash the hash (yes really). + * We do this by copying the entries from the old hash to a new hash, causing all + * empty buckets to be weeded out of the hash. We dont do this on a timer, as its + * very expensive, so instead we do it when the user types /REHASH and expects a + * short delay anyway. + */ +void InspIRCd::RehashUsersAndChans() +{ + user_hash* old_users = this->clientlist; + chan_hash* old_chans = this->chanlist; + + this->clientlist = new user_hash(); + this->chanlist = new chan_hash(); + + for (user_hash::const_iterator n = old_users->begin(); n != old_users->end(); n++) + this->clientlist->insert(*n); + + delete old_users; + + for (chan_hash::const_iterator n = old_chans->begin(); n != old_chans->end(); n++) + this->chanlist->insert(*n); + + delete old_chans; +} + void InspIRCd::CloseLog() { this->Logger->Close(); @@ -234,7 +261,10 @@ InspIRCd::InspIRCd(int argc, char** argv) modules.resize(255); factory.resize(255); - + + this->clientlist = new user_hash(); + this->chanlist = new chan_hash(); + this->Config = new ServerConfig(this); this->Config->opertypes.clear(); this->Config->operclass.clear(); @@ -565,11 +595,11 @@ bool InspIRCd::UnloadModule(const char* filename) return false; } /* Give the module a chance to tidy out all its metadata */ - for (chan_hash::iterator c = this->chanlist.begin(); c != this->chanlist.end(); c++) + for (chan_hash::iterator c = this->chanlist->begin(); c != this->chanlist->end(); c++) { modules[j]->OnCleanup(TYPE_CHANNEL,c->second); } - for (user_hash::iterator u = this->clientlist.begin(); u != this->clientlist.end(); u++) + for (user_hash::iterator u = this->clientlist->begin(); u != this->clientlist->end(); u++) { modules[j]->OnCleanup(TYPE_USER,u->second); } diff --git a/src/mode.cpp b/src/mode.cpp index 4642c296f..dfa846364 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -638,13 +638,13 @@ bool ModeParser::DelMode(ModeHandler* mh) switch (mh->GetModeType()) { case MODETYPE_USER: - for (user_hash::iterator i = ServerInstance->clientlist.begin(); i != ServerInstance->clientlist.end(); i++) + for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++) { mh->RemoveMode(i->second); } break; case MODETYPE_CHANNEL: - for (chan_hash::iterator i = ServerInstance->chanlist.begin(); i != ServerInstance->chanlist.end(); i++) + for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) { mh->RemoveMode(i->second); } diff --git a/src/modules.cpp b/src/modules.cpp index 8c38914e9..acd2ae469 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -345,6 +345,7 @@ const std::string& InspIRCd::GetModuleName(Module* m) void InspIRCd::RehashServer() { this->WriteOpers("*** Rehashing config file"); + this->RehashUsersAndChans(); this->Config->Read(false,NULL); } @@ -358,7 +359,7 @@ void InspIRCd::RehashServer() chanrec* InspIRCd::GetChannelIndex(long index) { int target = 0; - for (chan_hash::iterator n = this->chanlist.begin(); n != this->chanlist.end(); n++, target++) + for (chan_hash::iterator n = this->chanlist->begin(); n != this->chanlist->end(); n++, target++) { if (index == target) return n->second; diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index a7d2485ee..aa4e1f6cd 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -128,7 +128,7 @@ class cmd_check : public command_t long x = 0; /* hostname or other */ - for (user_hash::const_iterator a = ServerInstance->clientlist.begin(); a != ServerInstance->clientlist.end(); a++) + for (user_hash::const_iterator a = ServerInstance->clientlist->begin(); a != ServerInstance->clientlist->end(); a++) { if (match(a->second->host, parameters[0]) || match(a->second->dhost, parameters[0])) { diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp index 7d11d41e4..eb9933ecc 100644 --- a/src/modules/m_httpd_stats.cpp +++ b/src/modules/m_httpd_stats.cpp @@ -102,8 +102,8 @@ class ModuleHttpStats : public Module data << "<div class='totals'>"; data << "<h2>Totals</h2>"; data << "<table>"; - data << "<tr><td>Users</td><td>" << ServerInstance->clientlist.size() << "</td></tr>"; - data << "<tr><td>Channels</td><td>" << ServerInstance->chanlist.size() << "</td></tr>"; + data << "<tr><td>Users</td><td>" << ServerInstance->clientlist->size() << "</td></tr>"; + data << "<tr><td>Channels</td><td>" << ServerInstance->chanlist->size() << "</td></tr>"; data << "<tr><td>Opers</td><td>" << ServerInstance->all_opers.size() << "</td></tr>"; data << "<tr><td>Sockets</td><td>" << (ServerInstance->SE->GetMaxFds() - ServerInstance->SE->GetRemainingFds()) << " (Max: " << ServerInstance->SE->GetMaxFds() << " via socket engine '" << ServerInstance->SE->GetName() << "')</td></tr>"; data << "</table>"; diff --git a/src/modules/m_redirect.cpp b/src/modules/m_redirect.cpp index 6f602e62d..b6600da91 100644 --- a/src/modules/m_redirect.cpp +++ b/src/modules/m_redirect.cpp @@ -66,7 +66,7 @@ class Redirect : public ModeHandler } else { - for (chan_hash::const_iterator i = ServerInstance->chanlist.begin(); i != ServerInstance->chanlist.end(); i++) + for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) { if ((i->second != channel) && (i->second->IsModeSet('L')) && (irc::string(i->second->GetModeParameter('L').c_str()) == irc::string(channel->name))) { diff --git a/src/modules/m_safelist.cpp b/src/modules/m_safelist.cpp index f318300c5..7441f0ea5 100644 --- a/src/modules/m_safelist.cpp +++ b/src/modules/m_safelist.cpp @@ -78,7 +78,7 @@ class ListTimer : public InspTimer userrec* u = (userrec*)(*iter); ListData* ld; u->GetExt("safelist_cache", ld); - if ((size_t)ld->list_position > ServerInstance->chanlist.size()) + if ((size_t)ld->list_position > ServerInstance->chanlist->size()) { u->Shrink("safelist_cache"); DELETE(ld); diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp index 864feb8b5..3290878f4 100644 --- a/src/modules/m_spanningtree.cpp +++ b/src/modules/m_spanningtree.cpp @@ -357,7 +357,7 @@ class TreeServer : public classbase ServerInstance->Log(DEBUG,"Removing all users from server %s",this->ServerName.c_str()); const char* reason_s = reason.c_str(); std::vector<userrec*> time_to_die; - for (user_hash::iterator n = ServerInstance->clientlist.begin(); n != ServerInstance->clientlist.end(); n++) + for (user_hash::iterator n = ServerInstance->clientlist->begin(); n != ServerInstance->clientlist->end(); n++) { if (!strcmp(n->second->server, this->ServerName.c_str())) { @@ -1880,9 +1880,9 @@ class TreeSocket : public InspSocket const char* tempnick = params[1].c_str(); Instance->Log(DEBUG,"Introduce client %s!%s@%s",tempnick,params[4].c_str(),params[2].c_str()); - user_hash::iterator iter = this->Instance->clientlist.find(tempnick); + user_hash::iterator iter = this->Instance->clientlist->find(tempnick); - if (iter != this->Instance->clientlist.end()) + if (iter != this->Instance->clientlist->end()) { // nick collision Instance->Log(DEBUG,"Nick collision on %s!%s@%s: %lu %lu",tempnick,params[4].c_str(),params[2].c_str(),(unsigned long)age,(unsigned long)iter->second->age); @@ -1892,7 +1892,7 @@ class TreeSocket : public InspSocket } userrec* _new = new userrec(this->Instance); - this->Instance->clientlist[tempnick] = _new; + (*(this->Instance->clientlist))[tempnick] = _new; _new->SetFd(FD_MAGIC_NUMBER); strlcpy(_new->nick, tempnick,NICKMAX-1); strlcpy(_new->host, params[2].c_str(),63); @@ -2027,44 +2027,44 @@ class TreeSocket : public InspSocket std::string buffer; std::string n = this->Instance->Config->ServerName; const char* sn = n.c_str(); - int iterations = 0; + /* Yes, these arent too nice looking, but they get the job done */ - for (std::vector<ZLine*>::iterator i = Instance->XLines->zlines.begin(); i != Instance->XLines->zlines.end(); i++, iterations++) + for (std::vector<ZLine*>::iterator i = Instance->XLines->zlines.begin(); i != Instance->XLines->zlines.end(); i++) { snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); buffer.append(data); } - for (std::vector<QLine*>::iterator i = Instance->XLines->qlines.begin(); i != Instance->XLines->qlines.end(); i++, iterations++) + for (std::vector<QLine*>::iterator i = Instance->XLines->qlines.begin(); i != Instance->XLines->qlines.end(); i++) { snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); buffer.append(data); } - for (std::vector<GLine*>::iterator i = Instance->XLines->glines.begin(); i != Instance->XLines->glines.end(); i++, iterations++) + for (std::vector<GLine*>::iterator i = Instance->XLines->glines.begin(); i != Instance->XLines->glines.end(); i++) { snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); buffer.append(data); } - for (std::vector<ELine*>::iterator i = Instance->XLines->elines.begin(); i != Instance->XLines->elines.end(); i++, iterations++) + for (std::vector<ELine*>::iterator i = Instance->XLines->elines.begin(); i != Instance->XLines->elines.end(); i++) { snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); buffer.append(data); } - for (std::vector<ZLine*>::iterator i = Instance->XLines->pzlines.begin(); i != Instance->XLines->pzlines.end(); i++, iterations++) + for (std::vector<ZLine*>::iterator i = Instance->XLines->pzlines.begin(); i != Instance->XLines->pzlines.end(); i++) { snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); buffer.append(data); } - for (std::vector<QLine*>::iterator i = Instance->XLines->pqlines.begin(); i != Instance->XLines->pqlines.end(); i++, iterations++) + for (std::vector<QLine*>::iterator i = Instance->XLines->pqlines.begin(); i != Instance->XLines->pqlines.end(); i++) { snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); buffer.append(data); } - for (std::vector<GLine*>::iterator i = Instance->XLines->pglines.begin(); i != Instance->XLines->pglines.end(); i++, iterations++) + for (std::vector<GLine*>::iterator i = Instance->XLines->pglines.begin(); i != Instance->XLines->pglines.end(); i++) { snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); buffer.append(data); } - for (std::vector<ELine*>::iterator i = Instance->XLines->pelines.begin(); i != Instance->XLines->pelines.end(); i++, iterations++) + for (std::vector<ELine*>::iterator i = Instance->XLines->pelines.begin(); i != Instance->XLines->pelines.end(); i++) { snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); buffer.append(data); @@ -2079,10 +2079,9 @@ class TreeSocket : public InspSocket { char data[MAXBUF]; std::deque<std::string> list; - int iterations = 0; std::string n = this->Instance->Config->ServerName; const char* sn = n.c_str(); - for (chan_hash::iterator c = this->Instance->chanlist.begin(); c != this->Instance->chanlist.end(); c++, iterations++) + for (chan_hash::iterator c = this->Instance->chanlist->begin(); c != this->Instance->chanlist->end(); c++) { SendFJoins(Current, c->second); if (*c->second->topic) @@ -2106,8 +2105,7 @@ class TreeSocket : public InspSocket char data[MAXBUF]; std::deque<std::string> list; std::string dataline; - int iterations = 0; - for (user_hash::iterator u = this->Instance->clientlist.begin(); u != this->Instance->clientlist.end(); u++, iterations++) + for (user_hash::iterator u = this->Instance->clientlist->begin(); u != this->Instance->clientlist->end(); u++) { if (u->second->registered == REG_ALL) { @@ -4342,13 +4340,13 @@ class ModuleSpanningTree : public Module float percent; char text[80]; - if (ServerInstance->clientlist.size() == 0) { + if (ServerInstance->clientlist->size() == 0) { // If there are no users, WHO THE HELL DID THE /MAP?!?!?! percent = 0; } else { - percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist.size()) * 100; + percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist->size()) * 100; } snprintf(text, 80, "%s %s%5d [%5.2f%%]", Current->GetName().c_str(), spacer, Current->GetUserCount(), percent); totusers += Current->GetUserCount(); diff --git a/src/modules/m_spy.cpp b/src/modules/m_spy.cpp index 4ef628436..de48284ba 100644 --- a/src/modules/m_spy.cpp +++ b/src/modules/m_spy.cpp @@ -85,7 +85,7 @@ class cmd_spylist : public command_t { ServerInstance->WriteOpers("*** Oper %s used SPYLIST to list +s/+p channels and keys.",user->nick); user->WriteServ("321 %s Channel :Users Name",user->nick); - for (chan_hash::const_iterator i = ServerInstance->chanlist.begin(); i != ServerInstance->chanlist.end(); i++) + for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) { if (pcnt && !match(i->second->name, parameters[0])) continue; diff --git a/src/modules/m_tline.cpp b/src/modules/m_tline.cpp index 65167cece..801218377 100644 --- a/src/modules/m_tline.cpp +++ b/src/modules/m_tline.cpp @@ -39,7 +39,7 @@ class cmd_tline : public command_t float n_match_host = 0; float n_match_ip = 0; - for (user_hash::const_iterator u = ServerInstance->clientlist.begin(); u != ServerInstance->clientlist.end(); u++) + for (user_hash::const_iterator u = ServerInstance->clientlist->begin(); u != ServerInstance->clientlist->end(); u++) { n_counted++; if (match(u->second->GetFullRealHost(),parameters[0])) diff --git a/src/users.cpp b/src/users.cpp index 268e08d2f..712214100 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -761,7 +761,7 @@ void userrec::UnOper() void userrec::QuitUser(InspIRCd* Instance, userrec *user, const std::string &quitreason) { - user_hash::iterator iter = Instance->clientlist.find(user->nick); + user_hash::iterator iter = Instance->clientlist->find(user->nick); std::string reason = quitreason; if (reason.length() > MAXQUIT - 1) @@ -814,15 +814,16 @@ void userrec::QuitUser(InspIRCd* Instance, userrec *user, const std::string &qui user->AddToWhoWas(); } - if (iter != Instance->clientlist.end()) + if (iter != Instance->clientlist->end()) { Instance->Log(DEBUG,"deleting user hash value %lx",(unsigned long)user); if (IS_LOCAL(user)) { - if (find(Instance->local_users.begin(),Instance->local_users.end(),user) != Instance->local_users.end()) - Instance->local_users.erase(find(Instance->local_users.begin(),Instance->local_users.end(),user)); + std::vector<userrec*>::iterator x = find(Instance->local_users.begin(),Instance->local_users.end(),user); + if (x != Instance->local_users.end()) + Instance->local_users.erase(x); } - Instance->clientlist.erase(iter); + Instance->clientlist->erase(iter); DELETE(user); } } @@ -977,7 +978,7 @@ void userrec::AddToWhoWas() void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, insp_inaddr ip) { std::string tempnick = ConvToStr(socket) + "-unknown"; - user_hash::iterator iter = Instance->clientlist.find(tempnick); + user_hash::iterator iter = Instance->clientlist->find(tempnick); const char *ipaddr = insp_ntoa(ip); userrec* New; int j = 0; @@ -991,17 +992,17 @@ void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, * this was probably the cause of 'server ignores me when i hammer it with reconnects' * issue in earlier alphas/betas */ - if (iter != Instance->clientlist.end()) + if (iter != Instance->clientlist->end()) { userrec* goner = iter->second; DELETE(goner); - Instance->clientlist.erase(iter); + Instance->clientlist->erase(iter); } Instance->Log(DEBUG,"AddClient: %d %d %s",socket,port,ipaddr); New = new userrec(Instance); - Instance->clientlist[tempnick] = New; + (*(Instance->clientlist))[tempnick] = New; New->fd = socket; strlcpy(New->nick,tempnick.c_str(),NICKMAX-1); @@ -1198,18 +1199,18 @@ userrec* userrec::UpdateNickHash(const char* New) try { //user_hash::iterator newnick; - user_hash::iterator oldnick = ServerInstance->clientlist.find(this->nick); + user_hash::iterator oldnick = ServerInstance->clientlist->find(this->nick); if (!strcasecmp(this->nick,New)) return oldnick->second; - if (oldnick == ServerInstance->clientlist.end()) + if (oldnick == ServerInstance->clientlist->end()) return NULL; /* doesnt exist */ userrec* olduser = oldnick->second; - ServerInstance->clientlist[New] = olduser; - ServerInstance->clientlist.erase(oldnick); - return ServerInstance->clientlist[New]; + (*(ServerInstance->clientlist))[New] = olduser; + ServerInstance->clientlist->erase(oldnick); + return olduser; } catch (...) @@ -1949,12 +1950,12 @@ void userrec::PurgeEmptyChannels() for (std::vector<chanrec*>::iterator n = to_delete.begin(); n != to_delete.end(); n++) { chanrec* thischan = *n; - chan_hash::iterator i2 = ServerInstance->chanlist.find(thischan->name); - if (i2 != ServerInstance->chanlist.end()) + chan_hash::iterator i2 = ServerInstance->chanlist->find(thischan->name); + if (i2 != ServerInstance->chanlist->end()) { FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second)); DELETE(i2->second); - ServerInstance->chanlist.erase(i2); + ServerInstance->chanlist->erase(i2); this->chans.erase(*n); } } |