From 41f62a2a3badd6b7dbffb4fdb995c41ef709462c Mon Sep 17 00:00:00 2001 From: peavey Date: Mon, 13 Nov 2006 00:45:37 +0000 Subject: add config option to control whowas behaviour. *may break* git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@5731 e03df62e-2008-0410-955e-edbf42e46eb7 --- docs/inspircd.conf.example | 26 ++++++++++++++++++++++ include/configreader.h | 13 +++++++++++ include/inspircd.h | 4 ++++ include/users.h | 9 ++++++++ src/configreader.cpp | 27 ++++++++++++++++++++++- src/users.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 131 insertions(+), 3 deletions(-) diff --git a/docs/inspircd.conf.example b/docs/inspircd.conf.example index aac661703..a3d90c700 100644 --- a/docs/inspircd.conf.example +++ b/docs/inspircd.conf.example @@ -741,6 +741,32 @@ notimesync="no" allowhalfop="yes"> +#-#-#-#-#-#-#-#-#-#-#-#-#- WHOWAS OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-# +# # +# This tag lets you define the behaviour of the /whowas command of # +# your server. # +# # +# groupsize - Controls the maximum entries per nick shown when # +# performing a /whowas nick. # +# # +# maxgroups - The maximum number of nickgroups that can be added # +# to the list. If max is reached, oldest group will # +# be deleted first like a FIFO. A groupsize of 3 and # +# a maxgroups of 5000 will allow for 5000 nicks to # +# be stored with a history of 3, thus giving a total # +# of 3 * 5000 = 15000 entries. # +# # +# maxkeep - The maximum time a nick is kept in the whowas list # +# before being pruned. Time may be specified in # +# seconds, or in the following format: 1y2w3d4h5m6s # +# meaning one year, two weeks, three days, 4 hours, # +# 5 minutes and 6 seconds. All fields in this format # +# are optional. Minimum is 1 hour, if less InspIRCd # +# will default back to 1 hour. # +# # +# # #-#-#-#-#-#-#-#-#-#-#-#-#- MODULE OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-# diff --git a/include/configreader.h b/include/configreader.h index e6591e7a8..516c6a6ed 100644 --- a/include/configreader.h +++ b/include/configreader.h @@ -120,6 +120,19 @@ class ServerConfig : public Extensible */ ConfigDataHash config_data; + /** Max number of WhoWas entries per user. + */ + int WhoWasGroupSize; + + /** Max number of cumulative user-entries in WhoWas. + * When max reached and added to, push out oldest entry FIFO style. + */ + int WhoWasMaxGroups; + + /** Max seconds a user is kept in WhoWas before being pruned. + */ + int WhoWasMaxKeep; + /** Holds the server name of the local server * as defined by the administrator. */ diff --git a/include/inspircd.h b/include/inspircd.h index baa1fb589..7fecf22ae 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -401,6 +401,10 @@ class InspIRCd : public classbase */ irc::whowas::whowas_users whowas; + /** Whowas container, contains a map of time_t to users tracked by WHOWAS + */ + irc::whowas::whowas_users_fifo whowas_fifo; + /** DNS class, provides resolver facilities to the core and modules */ DNS* Res; diff --git a/include/users.h b/include/users.h index 018336e77..ce8f4eb28 100644 --- a/include/users.h +++ b/include/users.h @@ -828,9 +828,18 @@ namespace irc */ typedef std::map whowas_users; + /** Sets of time and users in whowas list + */ + typedef std::map whowas_users_fifo; + /** Called every hour by the core to remove expired entries */ void MaintainWhoWas(InspIRCd* ServerInstance, time_t TIME); + + /** Prune for WhoWasGroupSize, WhoWasMaxGroups and + * WhoWasMaxKeep on rehash + */ + void PruneWhoWas(InspIRCd* ServerInstance, time_t TIME); }; }; diff --git a/src/configreader.cpp b/src/configreader.cpp index 1b38e7155..ea5d09db9 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -41,6 +41,9 @@ ServerConfig::ServerConfig(InspIRCd* Instance) : ServerInstance(Instance) debugging = 0; LogLevel = DEFAULT; maxbans.clear(); + WhoWasGroupSize = 10; + WhoWasMaxGroups = WhoWasGroupSize * MAXCLIENTS; + WhoWasMaxKeep = 3600*24*3; // 3 days } void ServerConfig::ClearStack() @@ -319,6 +322,24 @@ bool ValidateRules(ServerConfig* conf, const char* tag, const char* value, void* return true; } +bool ValidateWhoWas(ServerConfig* conf, const char* tag, const char* value, void* data) +{ + const char* max = (const char*)data; + conf->WhoWasMaxKeep = conf->GetInstance()->Duration(max); + + if (conf->WhoWasGroupSize < 0) + conf->WhoWasGroupSize = 0; + + if (conf->WhoWasMaxGroups < 0) + conf->WhoWasMaxGroups = 0; + + if (conf->WhoWasMaxKeep < 3600) + conf->WhoWasMaxKeep = 3600; + + irc::whowas::PruneWhoWas(conf->GetInstance(), conf->GetInstance()->Time()); + return true; +} + /* Callback called before processing the first tag */ bool InitConnect(ServerConfig* conf, const char* tag) @@ -511,6 +532,7 @@ bool DoneMaxBans(ServerConfig* conf, const char* tag) void ServerConfig::Read(bool bail, userrec* user) { char debug[MAXBUF]; /* Temporary buffer for debugging value */ + char maxkeep[MAXBUF]; /* Temporary buffer for WhoWasMaxKeep value */ char* data[12]; /* Temporary buffers for reading multiple occurance tags into */ void* ptr[12]; /* Temporary pointers for passing to callbacks */ int r_i[12]; /* Temporary array for casting */ @@ -545,7 +567,7 @@ void ServerConfig::Read(bool bail, userrec* user) {"dns", "timeout", &this->dns_timeout, DT_INTEGER, ValidateDnsTimeout}, {"options", "moduledir", &this->ModPath, DT_CHARPTR, ValidateModPath}, {"disabled", "commands", &this->DisabledCommands, DT_CHARPTR, NoValidation}, - {"options", "userstats", &this->UserStats, DT_CHARPTR, NoValidation}, + {"options", "userstats", &this->UserStats, DT_CHARPTR, NoValidation}, {"options", "customversion", &this->CustomVersion, DT_CHARPTR, NoValidation}, {"options", "hidesplits", &this->HideSplits, DT_BOOLEAN, NoValidation}, {"options", "hidebans", &this->HideBans, DT_BOOLEAN, NoValidation}, @@ -556,6 +578,9 @@ void ServerConfig::Read(bool bail, userrec* user) {"options", "syntaxhints", &this->SyntaxHints, DT_BOOLEAN, NoValidation}, {"options", "cyclehosts", &this->CycleHosts, DT_BOOLEAN, NoValidation}, {"pid", "file", &this->PID, DT_CHARPTR, NoValidation}, + {"whowas", "groupsize", &this->WhoWasGroupSize, DT_INTEGER, NoValidation}, + {"whowas", "maxgroups", &this->WhoWasMaxGroups, DT_INTEGER, NoValidation}, + {"whowas", "maxkeep", &maxkeep, DT_CHARPTR, ValidateWhoWas}, {NULL} }; diff --git a/src/users.cpp b/src/users.cpp index 5d6ac2ce7..f3278186b 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -869,7 +869,7 @@ namespace irc whowas_set* n = (whowas_set*)iter->second; if (n->size()) { - while ((n->begin() != n->end()) && ((*n->begin())->signon < t - 259200)) // 3 days + while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep)) { WhoWasGroup *a = *(n->begin()); DELETE(a); @@ -878,6 +878,51 @@ namespace irc } } } + /* on rehash, refactor maps according to new conf values */ + void PruneWhoWas(InspIRCd* ServerInstance, time_t t) + { + int groupsize = ServerInstance->Config->WhoWasGroupSize; + int maxgroups = ServerInstance->Config->WhoWasMaxGroups; + int maxkeep = ServerInstance->Config->WhoWasMaxKeep; + + int groupcount = 0; + for (whowas_users_fifo::iterator iter = ServerInstance->whowas_fifo.begin(); iter != ServerInstance->whowas_fifo.end(); iter++) + { + groupcount++; + + if (groupcount > maxgroups || iter->first < t - maxkeep) + { + whowas_set* n = (whowas_set*)ServerInstance->whowas.find(iter->second)->second; + if (n->size()) + { + while (n->begin() != n->end()) + { + WhoWasGroup *a = *(n->begin()); + DELETE(a); + n->erase(n->begin()); + } + } + ServerInstance->whowas.erase(iter->second); + ServerInstance->whowas_fifo.erase(iter->first); + } + else { + whowas_set* n = (whowas_set*)ServerInstance->whowas.find(iter->second)->second; + if (n->size()) + { + int nickcount = 0; + while (n->begin() != n->end()) + { + nickcount++; + if (nickcount > groupsize){ + WhoWasGroup *a = *(n->begin()); + DELETE(a); + n->erase(n->begin()); + } + } + } + } + } + } }; }; @@ -895,6 +940,12 @@ void userrec::AddToWhoWas() irc::whowas::WhoWasGroup *a = new irc::whowas::WhoWasGroup(this); n->push_back(a); ServerInstance->whowas[this->nick] = n; + ServerInstance->whowas_fifo[ServerInstance->Time()] = this->nick; + if ((int)(ServerInstance->whowas.size()) > ServerInstance->Config->WhoWasMaxGroups) + { + ServerInstance->whowas.erase(ServerInstance->whowas_fifo.begin()->second); + ServerInstance->whowas_fifo.erase(ServerInstance->whowas_fifo.begin()); + } } else { @@ -902,7 +953,7 @@ void userrec::AddToWhoWas() ServerInstance->Log(DEBUG,"Using existing whowas group for %s",this->nick); - if (group->size() > 10) + if ((int)(group->size()) > ServerInstance->Config->WhoWasMaxGroups) { ServerInstance->Log(DEBUG,"Trimming existing group to ten entries for %s",this->nick); irc::whowas::WhoWasGroup *a = (irc::whowas::WhoWasGroup*)*(group->begin()); -- cgit v1.2.3