]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/users.cpp
code tidyups
[user/henk/code/inspircd.git] / src / users.cpp
index cdacdc5c2ab52f126e59a093306e7f3bf8071310..b81cd6d912d2bd6ca3bc8bbdc3833183144f12ae 100644 (file)
 #include "bancache.h"
 #include "commands/cmd_whowas.h"
 
+/* XXX: Used for speeding up WriteCommon operations */
+unsigned long uniq_id = 1;
+
 static unsigned long* already_sent = NULL;
 
 
 void InitializeAlreadySent(SocketEngine* SE)
 {
        already_sent = new unsigned long[SE->GetMaxFds()];
-       memset(already_sent, 0, sizeof(already_sent));
+       memset(already_sent, 0, SE->GetMaxFds() * sizeof(unsigned long));
 }
 
-/* XXX: Used for speeding up WriteCommon operations */
-unsigned long uniq_id = 1;
 
 std::string User::ProcessNoticeMasks(const char *sm)
 {
@@ -506,42 +507,68 @@ bool User::HasPermission(const std::string &command)
        return false;
 }
 
-/** NOTE: We cannot pass a const reference to this method.
- * The string is changed by the workings of the method,
- * so that if we pass const ref, we end up copying it to
- * something we can change anyway. Makes sense to just let
- * the compiler do that copy for us.
- */
-bool User::AddBuffer(std::string a)
+bool User::AddBuffer(const std::string &a)
 {
-       try
-       {
-               std::string::size_type i = a.rfind('\r');
+       std::string::size_type start = 0;
+       std::string::size_type i = a.find('\r');
 
+       /*
+        * The old implementation here took a copy, and rfind() on \r, removing as it found them, before
+        * copying a second time onto the recvq. That's ok, but involves three copies minimum (recv() to buffer,
+        * buffer to here, here to recvq) - The new method now copies twice (recv() to buffer, buffer to recvq).
+        *
+        * We use find() instead of rfind() for clarity, however unlike the old code, our scanning of the string is
+        * contiguous: as we specify a startpoint, we never see characters we have scanned previously, making this
+        * marginally faster in cases with a number of \r hidden early on in the buffer.
+        *
+        * How it works:
+        * Start at first pos of string, find first \r, append everything in the chunk (excluding \r) to recvq. Set
+        * i ahead of the \r, search for next \r, add next chunk to buffer... repeat.
+        *              -- w00t (7 may, 2008)
+        */
+       if (i == std::string::npos)
+       {
+               // no \r that we need to dance around, just add to buffer
+               recvq.append(a);
+       }
+       else
+       {
+               // While we can find the end of a chunk to add
                while (i != std::string::npos)
                {
-                       a.erase(i, 1);
-                       i = a.rfind('\r');
-               }
+                       // Append the chunk that we have
+                       recvq.append(a, start, (i - start));
 
-               if (a.length())
-                       recvq.append(a);
+                       // Start looking for the next one
+                       start = i + 1;
+                       i = a.find('\r', start);
+               }
 
-               if (this->MyClass && (recvq.length() > this->MyClass->GetRecvqMax()))
+               if (start != a.length())
                {
-                       this->SetWriteError("RecvQ exceeded");
-                       ServerInstance->SNO->WriteToSnoMask('A', "User %s RecvQ of %lu exceeds connect class maximum of %lu",this->nick,(unsigned long int)recvq.length(),this->MyClass->GetRecvqMax());
-                       return false;
+                       /*
+                        * This is here to catch a corner case when we get something like:
+                        * NICK w0
+                        * 0t\r\nU
+                        * SER ...
+                        * in successive calls to us.
+                        *
+                        * Without this conditional, the 'U' on the second case will be dropped,
+                        * which is most *certainly* not the behaviour we want!
+                        *              -- w00t
+                        */
+                       recvq.append(a, start, (a.length() - start));
                }
-
-               return true;
        }
 
-       catch (...)
+       if (this->MyClass && (recvq.length() > this->MyClass->GetRecvqMax()))
        {
-               ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::AddBuffer()");
+               this->SetWriteError("RecvQ exceeded");
+               ServerInstance->SNO->WriteToSnoMask('A', "User %s RecvQ of %lu exceeds connect class maximum of %lu",this->nick,(unsigned long int)recvq.length(),this->MyClass->GetRecvqMax());
                return false;
        }
+
+       return true;
 }
 
 bool User::BufferIsReady()
@@ -788,8 +815,11 @@ void User::UnOper()
                        }
                }
 
-               const char* parameters[] = { this->nick, moderemove.c_str() };
-               ServerInstance->Parser->CallHandler("MODE", parameters, 2, this);
+               std::vector<std::string> parameters;
+               parameters.push_back(this->nick);
+               parameters.push_back(moderemove);
+
+               ServerInstance->Parser->CallHandler("MODE", parameters, this);
 
                /* unset their oper type (what IS_OPER checks), and remove +o */
                *this->oper = 0;
@@ -859,6 +889,25 @@ void User::CheckClass()
        this->MaxChans = a->GetMaxChans();
 }
 
+void User::CheckLines()
+{
+       const char* check[] = { "G" , "K", NULL };
+
+       if (!this->exempt)
+       {
+               for (int n = 0; check[n]; ++n)
+               {
+                       XLine *r = ServerInstance->XLines->MatchesLine(check[n], this);
+
+                       if (r)
+                       {
+                               r->Apply(this);
+                               return;
+                       }
+               }
+       }
+}
+
 void User::FullConnect()
 {
        ServerInstance->stats->statsConnects++;
@@ -881,24 +930,7 @@ void User::FullConnect()
                return;
        }
 
-       if (!this->exempt)
-       {
-               GLine *r = (GLine *)ServerInstance->XLines->MatchesLine("G", this);
-
-               if (r)
-               {
-                       r->Apply(this);
-                       return;
-               }
-
-               KLine *n = (KLine *)ServerInstance->XLines->MatchesLine("K", this);
-
-               if (n)
-               {
-                       n->Apply(this);
-                       return;
-               }
-       }
+       CheckLines();
 
        this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network);
        this->WriteNumeric(001, "%s :Welcome to the %s IRC Network %s!%s@%s",this->nick, ServerInstance->Config->Network, this->nick, this->ident, this->host);
@@ -918,9 +950,9 @@ void User::FullConnect()
 
        /* Trigger LUSERS output, give modules a chance too */
        int MOD_RESULT = 0;
-       FOREACH_RESULT(I_OnPreCommand, OnPreCommand("LUSERS", NULL, 0, this, true, "LUSERS"));
+       FOREACH_RESULT(I_OnPreCommand, OnPreCommand("LUSERS", std::vector<std::string>(), this, true, "LUSERS"));
        if (!MOD_RESULT)
-               ServerInstance->CallCommandHandler("LUSERS", NULL, 0, this);
+               ServerInstance->CallCommandHandler("LUSERS", std::vector<std::string>(), this);
 
        /*
         * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff
@@ -990,8 +1022,10 @@ bool User::ForceNickChange(const char* newnick)
        Command* nickhandler = ServerInstance->Parser->GetHandler("NICK");
        if (nickhandler) // wtfbbq, when would this not be here
        {
+               std::vector<std::string> parameters;
                nickhandler->HandleInternal(1, dummy);
-               bool result = (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS);
+               parameters.push_back(newnick);
+               bool result = (ServerInstance->Parser->CallHandler("NICK", parameters, this) == CMD_SUCCESS);
                nickhandler->HandleInternal(0, dummy);
                return result;
        }