Skip to content
Browse files

Fix recursion of QuitUser in SendQ quits

  • Loading branch information...
1 parent 09e1f74 commit cbbd56b8290f6569a815cf05ca7bd79279fa1b94 Jackmcbarn committed
Showing with 26 additions and 7 deletions.
  1. +2 −0 include/cull_list.h
  2. +6 −0 include/users.h
  3. +13 −0 src/cull_list.cpp
  4. +5 −7 src/users.cpp
View
2 include/cull_list.h
@@ -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
6 include/users.h
@@ -278,6 +278,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
13 src/cull_list.cpp
@@ -17,6 +17,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->hardsendqmax);
+ ServerInstance->Users->QuitUser(u, "SendQ exceeded");
+ }
+ working.clear();
+ }
std::set<classbase*> gone;
std::vector<classbase*> queue;
queue.reserve(list.size() + 32);
View
12 src/users.cpp
@@ -12,6 +12,7 @@
*/
#include "inspircd.h"
+#include "cull_list.h"
#include "command_parse.h"
#include "dns.h"
#include "inspsocket.h"
@@ -526,16 +527,13 @@ void UserIOHandler::OnDataReady()
void UserIOHandler::AddWriteBuf(const std::string &data)
{
+ if (user->quitting_sendq)
+ return;
size_t len = getSendQSize() + data.length();
if (!user->quitting && len > user->MyClass->hardsendqmax)
{
- /*
- * 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 maximum of %lu (class %s)",
- user->nick.c_str(), user->MyClass->hardsendqmax, user->MyClass->name.c_str());
+ user->quitting_sendq = true;
+ ServerInstance->GlobalCulls->AddSQItem(user);
return;
}

0 comments on commit cbbd56b

Please sign in to comment.
Something went wrong with that request. Please try again.