diff options
-rw-r--r-- | include/users.h | 26 | ||||
-rw-r--r-- | src/inspircd.cpp | 58 | ||||
-rw-r--r-- | src/modules/m_ident.cpp | 30 | ||||
-rw-r--r-- | src/users.cpp | 43 |
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; +} |