Fix recursion of QuitUser in SendQ quits

This commit is contained in:
Jackmcbarn 2011-05-23 21:51:08 -04:00
parent f5409f04cd
commit 58ab072505
4 changed files with 26 additions and 7 deletions

View File

@ -22,11 +22,13 @@
class CoreExport CullList
{
std::vector<classbase*> list;
std::vector<LocalUser*> SQlist;
public:
/** Adds an item to the cull list
*/
void AddItem(classbase* item) { list.push_back(item); }
void AddSQItem(LocalUser* item) { SQlist.push_back(item); }
/** Applies the cull list (deletes the contents)
*/

View File

@ -348,6 +348,12 @@ class CoreExport User : public Extensible
*/
unsigned int quitting:1;
/** Recursion fix: user is out of SendQ and will be quit as soon as possible.
* This can't be handled normally because QuitUser itself calls Write on other
* users, which could trigger their SendQ to overrun.
*/
unsigned int quitting_sendq:1;
/** This is true if the user matched an exception (E:Line). It is used to save time on ban checks.
*/
unsigned int exempt:1;

View File

@ -16,6 +16,19 @@
void CullList::Apply()
{
std::vector<LocalUser *> working;
while (!SQlist.empty())
{
working.swap(SQlist);
for(std::vector<LocalUser *>::iterator a = working.begin(); a != working.end(); a++)
{
LocalUser *u = *a;
ServerInstance->SNO->WriteGlobalSno('a', "User %s SendQ exceeds connect class maximum of %lu",
u->nick.c_str(), u->MyClass->GetSendqHardMax());
ServerInstance->Users->QuitUser(u, "SendQ exceeded");
}
working.clear();
}
std::set<classbase*> gone;
std::vector<classbase*> queue;
queue.reserve(list.size() + 32);

View File

@ -193,6 +193,7 @@ User::User(const std::string &uid, const std::string& sid, int type)
signon = idle_lastmsg = 0;
registered = 0;
quietquit = quitting = exempt = dns_done = false;
quitting_sendq = false;
client_sa.sa.sa_family = AF_UNSPEC;
ServerInstance->Logs->Log("USERS", DEBUG, "New UUID for user: %s", uuid.c_str());
@ -519,16 +520,13 @@ eol_found:
void UserIOHandler::AddWriteBuf(const std::string &data)
{
if (user->quitting_sendq)
return;
if (!user->quitting && getSendQSize() + data.length() > user->MyClass->GetSendqHardMax() &&
!user->HasPrivPermission("users/flood/increased-buffers"))
{
/*
* Quit the user FIRST, because otherwise we could recurse
* here and hit the same limit.
*/
ServerInstance->Users->QuitUser(user, "SendQ exceeded");
ServerInstance->SNO->WriteToSnoMask('a', "User %s SendQ exceeds connect class maximum of %lu",
user->nick.c_str(), user->MyClass->GetSendqHardMax());
user->quitting_sendq = true;
ServerInstance->GlobalCulls.AddSQItem(user);
return;
}