#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)
{
try
{
bool cached;
- const char* sip = this->GetIPString();
+ const char* sip = this->GetIPString(false);
/* Special case for 4in6 (Have i mentioned i HATE 4in6?) */
if (!strncmp(sip, "0::ffff:", 8))
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 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
{
- std::string::size_type i = a.rfind('\r');
+ ServerInstance->Logs->Log("recvqdebug", DEBUG, "Current recvq size is %d and I got called with a string of %d\n(%s)", recvq.length(), a.length(), a.c_str());
+ // 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));
+ ServerInstance->Logs->Log("recvqdebug", DEBUG, "Appended a chunk, length is now %d", recvq.length());
- 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
+ */
+ ServerInstance->Logs->Log("recvqdebug", DEBUG, "*** ALERT *** start != a.length, we should probably add more");
+ recvq.append(a, start, (a.length() - start));
}
- return true;
+ ServerInstance->Logs->Log("recvqdebug", DEBUG, "Final recvq length is %d\n(%s)", recvq.length(), recvq.c_str());
}
- 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()
}
}
- 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;
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++;
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);
/* 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
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;
}
* XXX the duplication here is horrid..
* do we really need two methods doing essentially the same thing?
*/
-const char* User::GetIPString()
+const char* User::GetIPString(bool translate4in6)
{
static char buf[1024];
{
strlcpy(&temp[1], buf, sizeof(temp) - 1);
*temp = '0';
+ if (translate4in6 && !strncmp(temp, "0::ffff:", 8))
+ {
+ this->cachedip = temp + 8;
+ return temp + 8;
+ }
+
this->cachedip = temp;
return temp;
}