summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/users.h26
-rw-r--r--src/inspircd.cpp58
-rw-r--r--src/modules/m_ident.cpp30
-rw-r--r--src/users.cpp43
4 files changed, 120 insertions, 37 deletions
diff --git a/include/users.h b/include/users.h
index 73e1a1173..b747669c9 100644
--- a/include/users.h
+++ b/include/users.h
@@ -184,12 +184,21 @@ class userrec : public connection
*/
std::string recvq;
+ /** User's send queue.
+ * Lines waiting to be sent are stored here until their buffer is flushed.
+ */
+ std::string sendq;
+
/** Flood counters
*/
long lines_in;
time_t reset_due;
long threshold;
+ /* Write error string
+ */
+ std::string WriteError;
+
userrec();
virtual ~userrec() { }
@@ -253,7 +262,22 @@ class userrec : public connection
* it is ok to read the buffer before calling GetBuffer().
*/
std::string GetBuffer();
-
+
+ /** Sets the write error for a connection. This is done because the actual disconnect
+ * of a client may occur at an inopportune time such as half way through /LIST output.
+ * The WriteErrors of clients are checked at a more ideal time (in the mainloop) and
+ * errored clients purged.
+ */
+ void SetWriteError(std::string error);
+
+ /** Returns the write error which last occured on this connection or an empty string
+ * if none occured.
+ */
+ std::string GetWriteError();
+
+ void AddWriteBuf(std::string data);
+ void FlushWriteBuf();
+
};
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index 8da1f7bf5..d5ba7f890 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -596,6 +596,7 @@ void Write(int sock,char *text, ...)
char textbuffer[MAXBUF];
va_list argsPtr;
char tb[MAXBUF];
+ int res;
va_start (argsPtr, text);
vsnprintf(textbuffer, MAXBUF, text, argsPtr);
@@ -604,16 +605,14 @@ void Write(int sock,char *text, ...)
chop(tb);
if ((sock != -1) && (sock != FD_MAGIC_NUMBER))
{
- int MOD_RESULT = 0;
- FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 512 ? 512 : bytes));
- if (!MOD_RESULT)
- write(sock,tb,bytes > 512 ? 512 : bytes);
if (fd_ref_table[sock])
{
- fd_ref_table[sock]->bytes_out += (bytes > 512 ? 512 : bytes);
- fd_ref_table[sock]->cmds_out++;
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes));
+ fd_ref_table[sock]->AddWriteBuf(tb);
+ statsSent += bytes;
}
- statsSent += (bytes > 512 ? 512 : bytes);
+ else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
}
}
@@ -629,6 +628,7 @@ void WriteServ(int sock, char* text, ...)
return;
}
char textbuffer[MAXBUF],tb[MAXBUF];
+ int res;
va_list argsPtr;
va_start (argsPtr, text);
@@ -638,16 +638,14 @@ void WriteServ(int sock, char* text, ...)
chop(tb);
if ((sock != -1) && (sock != FD_MAGIC_NUMBER))
{
- int MOD_RESULT = 0;
- FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 512 ? 512 : bytes));
- if (!MOD_RESULT)
- write(sock,tb,bytes > 512 ? 512 : bytes);
if (fd_ref_table[sock])
{
- fd_ref_table[sock]->bytes_out += (bytes > 512 ? 512 : bytes);
- fd_ref_table[sock]->cmds_out++;
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes));
+ fd_ref_table[sock]->AddWriteBuf(tb);
+ statsSent += bytes;
}
- statsSent += (bytes > 512 ? 512 : bytes);
+ else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
}
}
@@ -664,6 +662,7 @@ void WriteFrom(int sock, userrec *user,char* text, ...)
}
char textbuffer[MAXBUF],tb[MAXBUF];
va_list argsPtr;
+ int res;
va_start (argsPtr, text);
vsnprintf(textbuffer, MAXBUF, text, argsPtr);
@@ -672,16 +671,14 @@ void WriteFrom(int sock, userrec *user,char* text, ...)
chop(tb);
if ((sock != -1) && (sock != FD_MAGIC_NUMBER))
{
- int MOD_RESULT = 0;
- FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 512 ? 512 : bytes));
- if (!MOD_RESULT)
- write(sock,tb,bytes > 512 ? 512 : bytes);
if (fd_ref_table[sock])
{
- fd_ref_table[sock]->bytes_out += (bytes > 512 ? 512 : bytes);
- fd_ref_table[sock]->cmds_out++;
+ int MOD_RESULT = 0;
+ FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes));
+ fd_ref_table[sock]->AddWriteBuf(tb);
+ statsSent += bytes;
}
- statsSent += (bytes > 512 ? 512 : bytes);
+ else log(DEFAULT,"ERROR! attempted write to a user with no fd_ref_table entry!!!");
}
}
@@ -2752,7 +2749,7 @@ void ShowMOTD(userrec *user)
snprintf(buf,65535,":%s 376 %s :End of message of the day.\r\n", ServerName, user->nick);
WholeMOTD = WholeMOTD + buf;
// only one write operation
- send(user->fd,WholeMOTD.c_str(),WholeMOTD.length(),0);
+ user->AddWriteBuf(WholeMOTD);
statsSent += WholeMOTD.length();
}
@@ -4342,6 +4339,14 @@ int InspIRCd(char** argv, int argc)
// we don't check the state of remote users.
if ((curr->fd != -1) && (curr->fd != FD_MAGIC_NUMBER))
{
+ curr->FlushWriteBuf();
+ if (curr->GetWriteError() != "")
+ {
+ log(DEBUG,"InspIRCd: write error: %s",curr->GetWriteError().c_str());
+ kill_link(curr,curr->GetWriteError().c_str());
+ goto label;
+ }
+
FD_SET (curr->fd, &sfd);
// registration timeout -- didnt send USER/NICK/HOST in the time specified in
@@ -4400,6 +4405,15 @@ int InspIRCd(char** argv, int argc)
// we don't check the state of remote users.
if ((curr->fd != -1) && (curr->fd != FD_MAGIC_NUMBER))
{
+
+ curr->FlushWriteBuf();
+ if (curr->GetWriteError() != "")
+ {
+ log(DEBUG,"InspIRCd: write error: %s",curr->GetWriteError().c_str());
+ kill_link(curr,curr->GetWriteError().c_str());
+ goto label;
+ }
+
// registration timeout -- didnt send USER/NICK/HOST in the time specified in
// their connection class.
if ((TIME > curr->timeout) && (curr->registered != 7))
diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp
index fda3c9086..0e79cf496 100644
--- a/src/modules/m_ident.cpp
+++ b/src/modules/m_ident.cpp
@@ -54,19 +54,20 @@ Server *Srv;
class RFC1413
{
protected:
- int fd; // file descriptor
- userrec* u; // user record that the lookup is associated with
- sockaddr_in addr; // address we're connecting to
- in_addr addy; // binary ip address
- int state; // state (this class operates on a state engine)
- char ibuf[MAXBUF]; // input buffer
- sockaddr_in sock_us; // our port number
- sockaddr_in sock_them; // their port number
- socklen_t uslen; // length of our port number
- socklen_t themlen; // length of their port number
- int nrecv; // how many bytes we've received
- time_t timeout_end; // how long until the operation times out
- bool timeout; // true if we've timed out and should bail
+ int fd; // file descriptor
+ userrec* u; // user record that the lookup is associated with
+ sockaddr_in addr; // address we're connecting to
+ in_addr addy; // binary ip address
+ int state; // state (this class operates on a state engine)
+ char ibuf[MAXBUF]; // input buffer
+ sockaddr_in sock_us; // our port number
+ sockaddr_in sock_them; // their port number
+ socklen_t uslen; // length of our port number
+ socklen_t themlen; // length of their port number
+ int nrecv; // how many bytes we've received
+ time_t timeout_end; // how long until the operation times out
+ bool timeout; // true if we've timed out and should bail
+ char ident_request[128]; // buffer used to make up the request string
public:
// The destructor makes damn sure the socket is freed :)
@@ -172,7 +173,8 @@ class RFC1413
else
{
// send the request in the following format: theirsocket,oursocket
- Write(this->fd,"%d,%d",ntohs(sock_them.sin_port),ntohs(sock_us.sin_port));
+ snprintf(ident_request,127,"%d,%d\r\n",ntohs(sock_them.sin_port),ntohs(sock_us.sin_port));
+ send(this->fd,ident_request,strlen(ident_request),0);
Srv->Log(DEBUG,"Sent ident request, moving to state 2");
state = IDENT_STATE_WAITDATA;
}
diff --git a/src/users.cpp b/src/users.cpp
index 73e0019aa..0e676600e 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -47,6 +47,7 @@ userrec::userrec()
haspassed = false;
dns_done = false;
recvq = "";
+ sendq = "";
strcpy(result,"");
for (int i = 0; i < MAXCHANS; i++)
{
@@ -217,3 +218,45 @@ std::string userrec::GetBuffer()
return ret;
}
+void userrec::AddWriteBuf(std::string data)
+{
+ std::stringstream stream;
+ stream << sendq << data;
+ sendq = stream.str();
+}
+
+// send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
+void userrec::FlushWriteBuf()
+{
+ if (sendq.length())
+ {
+ char* tb = (char*)this->sendq.c_str();
+ int n_sent = write(this->fd,tb,this->sendq.length());
+ if (n_sent == -1)
+ {
+ this->SetWriteError(strerror(errno));
+ }
+ else
+ {
+ // advance the queue
+ tb += n_sent;
+ this->sendq = tb;
+ // update the user's stats counters
+ this->bytes_out += n_sent;
+ this->cmds_out++;
+ }
+ }
+}
+
+void userrec::SetWriteError(std::string error)
+{
+ log(DEBUG,"Setting error string for %s to '%s'",this->nick,error.c_str());
+ // don't try to set the error twice, its already set take the first string.
+ if (this->WriteError == "")
+ this->WriteError = error;
+}
+
+std::string userrec::GetWriteError()
+{
+ return this->WriteError;
+}