diff options
author | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2005-11-25 09:32:17 +0000 |
---|---|---|
committer | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2005-11-25 09:32:17 +0000 |
commit | 6550242735047783301150f3551174797dddc7f5 (patch) | |
tree | b568e1434a30005a03cc1f29a2a282c2936bc78c | |
parent | 3f8978ceef854ab7c91e86751b61a4405c10c4c8 (diff) |
Started removal of server linking code from core and implementation of socket API
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@1930 e03df62e-2008-0410-955e-edbf42e46eb7
-rw-r--r-- | include/socket.h | 16 | ||||
-rw-r--r-- | src/inspircd.cpp | 646 | ||||
-rw-r--r-- | src/modules.cpp | 3 | ||||
-rw-r--r-- | src/socket.cpp | 111 |
4 files changed, 390 insertions, 386 deletions
diff --git a/include/socket.h b/include/socket.h index 499a4d375..fd5e26586 100644 --- a/include/socket.h +++ b/include/socket.h @@ -21,6 +21,7 @@ #include <string> enum InspSocketState { I_DISCONNECTED, I_CONNECTING, I_CONNECTED, I_LISTENING, I_ERROR }; +enum InspSocketError { I_ERR_TIMEOUT, I_ERR_SOCKET, I_ERR_CONNECT }; class InspSocket { @@ -33,15 +34,22 @@ private: in_addr addy; time_t timeout_end; bool timeout; + pollfd polls; + char ibuf[1024]; public: InspSocket(); InspSocket(std::string host, int port, bool listening, unsigned long maxtime); - virtual int OnConnected(); - virtual int OnError(); + virtual bool OnConnected(); + virtual void OnError(InspSocketError e); virtual int OnDisconnect(); - virtual int OnDataReady(); + virtual bool OnDataReady(); + virtual void OnTimeout(); + virtual void OnClose(); + virtual char* Read(); + virtual int Write(std::string data); virtual int OnIncomingConnection(); void SetState(InspSocketState s); - void EngineTrigger(); + bool Poll(); + virtual void Close(); virtual ~InspSocket(); }; diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 8c07f15bf..c305fea92 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -68,6 +68,7 @@ using namespace std; #include "helperfuncs.h" #include "hashcomp.h" #include "socketengine.h" +#include "socket.h" int LogLevel = DEFAULT; char ServerName[MAXBUF]; @@ -106,6 +107,8 @@ extern std::vector<Module*> modules; std::vector<std::string> module_names; extern std::vector<ircd_module*> factory; +std::vector<InspSocket*> module_sockets; + extern int MODCOUNT; int openSockfd[MAXSOCKS]; bool nofork = false; @@ -2735,29 +2738,20 @@ int InspIRCd(char** argv, int argc) dns_poll(); - // *FIX* Instead of closing sockets in kill_link when they receive the ERROR :blah line, we should queue - // them in a list, then reap the list every second or so. - if (((TIME % 5) == 0) && (!expire_run)) + for (std::vector<InspSocket*>::iterator a = module_sockets.begin(); a < module_sockets.end(); a++) { - for (int i = 0; i < ConfValueEnum("link",&config_f); i++) + if (!a->Poll()) { - char Link_ServerName[MAXBUF],Link_AConn[MAXBUF]; - ConfValue("link","name",i,Link_ServerName,&config_f); - ConfValue("link","autoconnect",i,Link_AConn,&config_f); - if ((Link_AConn[0]) && (!GotServer(Link_ServerName))) - { - autoconnects::iterator a = autoconns.find(std::string(Link_ServerName)); - if (a != autoconns.end()) - { - if (TIME > a->second) - { - ConnectServer(Link_ServerName,NULL); - a->second = TIME + atoi(Link_AConn); - } - } - } + delete *a; + module_sockets.erase(a); + break; } + } + // *FIX* Instead of closing sockets in kill_link when they receive the ERROR :blah line, we should queue + // them in a list, then reap the list every second or so. + if (((TIME % 5) == 0) && (!expire_run)) + { expire_lines(); FOREACH_MOD OnBackgroundTimer(TIME); expire_run = true; @@ -2769,414 +2763,340 @@ int InspIRCd(char** argv, int argc) // fix by brain - this must be below any manipulation of the hashmap by modules user_hash::iterator count2 = clientlist.begin(); - engine_server_populate; - char remotehost[MAXBUF],resolved[MAXBUF]; - length = sizeof (client); - incomingSockfd = accept (me[x]->fd, (sockaddr *) &client, &length); - if (incomingSockfd != -1) - { - strlcpy(remotehost,(char *)inet_ntoa(client.sin_addr),MAXBUF); - if(CleanAndResolve(resolved, remotehost) != TRUE) - { - strlcpy(resolved,remotehost,MAXBUF); - } - // add to this connections ircd_connector vector - // *FIX* - we need the LOCAL port not the remote port in &client! - me[x]->AddIncoming(incomingSockfd,resolved,me[x]->port); - } - } - } - } - - std::deque<std::string> msgs; - std::deque<std::string> sums; - for (int x = 0; x < SERVERportCount; x++) - { - if (me[x]) - me[x]->FlushWriteBuffers(); - sums.clear(); - msgs.clear(); - if (me[x]) - has_been_netsplit = false; - while (me[x]->RecvPacket(msgs, tcp_host, sums)) // returns 0 or more lines (can be multiple lines!) - { - if (has_been_netsplit) - { - log(DEBUG,"Netsplit detected in recvpacket, aborting"); - goto label; - } - for (unsigned int ctr = 0; ctr < msgs.size(); ctr++) - { - strlcpy(tcp_msg,msgs[ctr].c_str(),MAXBUF); - strlcpy(tcp_sum,sums[ctr].c_str(),MAXBUF); - log(DEBUG,"Processing: %s",tcp_msg); - if (!tcp_msg[0]) - { - log(DEBUG,"Invalid string from %s [route%lu]",tcp_host,(unsigned long)x); - break; - } - // during a netburst, send all data to all other linked servers - if ((((nb_start>0) && (tcp_msg[0] != 'Y') && (tcp_msg[0] != 'X') && (tcp_msg[0] != 'F'))) || (is_uline(tcp_host))) - { - if (is_uline(tcp_host)) - { - if ((tcp_msg[0] != 'Y') && (tcp_msg[0] != 'X') && (tcp_msg[0] != 'F')) - { - NetSendToAllExcept_WithSum(tcp_host,tcp_msg,tcp_sum); - } - } - else - NetSendToAllExcept_WithSum(tcp_host,tcp_msg,tcp_sum); - } - std::string msg = tcp_msg; - FOREACH_MOD OnPacketReceive(msg,tcp_host); - strlcpy(tcp_msg,msg.c_str(),MAXBUF); - if (me[x]) - handle_link_packet(tcp_msg, tcp_host, me[x], tcp_sum); - if (!me[x]->FindHost(tcp_host)) - { - log(DEBUG,"Connector gone, bailing!"); - goto label; - } - } - goto label; - } - } - while (count2 != clientlist.end()) - { + while (count2 != clientlist.end()) + { #ifdef USE_SELECT - FD_ZERO(&sfd); + FD_ZERO(&sfd); #endif + + total_in_this_set = 0; - total_in_this_set = 0; - - user_hash::iterator xcount = count2; - user_hash::iterator endingiter = count2; + user_hash::iterator xcount = count2; + user_hash::iterator endingiter = count2; - if (count2 == clientlist.end()) break; + if (count2 == clientlist.end()) break; - userrec* curr = NULL; + userrec* curr = NULL; - if (count2->second) - curr = count2->second; + if (count2->second) + curr = count2->second; - if ((long)curr == -1) - goto label; + if ((long)curr == -1) + goto label; - if ((curr) && (curr->fd != 0)) - { + if ((curr) && (curr->fd != 0)) + { #ifdef _POSIX_PRIORITY_SCHEDULING - sched_yield(); + sched_yield(); #endif - // assemble up to 64 sockets into an fd_set - // to implement a pooling mechanism. - // - // This should be up to 64x faster than the - // old implementation. + // assemble up to 64 sockets into an fd_set + // to implement a pooling mechanism. + // + // This should be up to 64x faster than the + // old implementation. #ifdef USE_SELECT - while (total_in_this_set < 1024) - { - if (count2 != clientlist.end()) + while (total_in_this_set < 1024) { - curr = count2->second; - if ((long)curr == -1) - goto label; - int currfd = curr->fd; - // we don't check the state of remote users. - if ((currfd != -1) && (currfd != FD_MAGIC_NUMBER)) + if (count2 != clientlist.end()) { - 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 - // their connection class. - if (((unsigned)TIME > (unsigned)curr->timeout) && (curr->registered != 7)) - { - log(DEBUG,"InspIRCd: registration timeout: %s",curr->nick); - kill_link(curr,"Registration timeout"); + curr = count2->second; + if ((long)curr == -1) goto label; - } - if ((TIME > curr->signon) && (curr->registered == 3) && (AllModulesReportReady(curr))) + int currfd = curr->fd; + // we don't check the state of remote users. + if ((currfd != -1) && (currfd != FD_MAGIC_NUMBER)) { - log(DEBUG,"signon exceed, registered=3, and modules ready, OK"); - curr->dns_done = true; - statsDnsBad++; - FullConnectUser(curr); - if (fd_ref_table[currfd] != curr) // something changed, bail pronto - goto label; - } - if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr))) // both NICK and USER... and DNS - { - log(DEBUG,"dns done, registered=3, and modules ready, OK"); - FullConnectUser(curr); - if (fd_ref_table[currfd] != curr) // something changed, bail pronto - goto label; - } - if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7)) - { - if ((!curr->lastping) && (curr->registered == 7)) + curr->FlushWriteBuf(); + if (curr->GetWriteError() != "") { - log(DEBUG,"InspIRCd: ping timeout: %s",curr->nick); - kill_link(curr,"Ping timeout"); + log(DEBUG,"InspIRCd: write error: %s",curr->GetWriteError().c_str()); + kill_link(curr,curr->GetWriteError().c_str()); goto label; } - Write(curr->fd,"PING :%s",ServerName); - log(DEBUG,"InspIRCd: pinging: %s",curr->nick); - curr->lastping = 0; - curr->nping = TIME+curr->pingmax; // was hard coded to 120 + + FD_SET (curr->fd, &sfd); + + // registration timeout -- didnt send USER/NICK/HOST in the time specified in + // their connection class. + if (((unsigned)TIME > (unsigned)curr->timeout) && (curr->registered != 7)) + { + log(DEBUG,"InspIRCd: registration timeout: %s",curr->nick); + kill_link(curr,"Registration timeout"); + goto label; + } + if ((TIME > curr->signon) && (curr->registered == 3) && (AllModulesReportReady(curr))) + { + log(DEBUG,"signon exceed, registered=3, and modules ready, OK"); + curr->dns_done = true; + statsDnsBad++; + FullConnectUser(curr); + if (fd_ref_table[currfd] != curr) // something changed, bail pronto + goto label; + } + if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr))) // both NICK and USER... and DNS + { + log(DEBUG,"dns done, registered=3, and modules ready, OK"); + FullConnectUser(curr); + if (fd_ref_table[currfd] != curr) // something changed, bail pronto + goto label; + } + if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7)) + { + if ((!curr->lastping) && (curr->registered == 7)) + { + log(DEBUG,"InspIRCd: ping timeout: %s",curr->nick); + kill_link(curr,"Ping timeout"); + goto label; + } + Write(curr->fd,"PING :%s",ServerName); + log(DEBUG,"InspIRCd: pinging: %s",curr->nick); + curr->lastping = 0; + curr->nping = TIME+curr->pingmax; // was hard coded to 120 + } } + count2++; + total_in_this_set++; } - count2++; - total_in_this_set++; + else break; } - else break; - } - endingiter = count2; - count2 = xcount; // roll back to where we were + endingiter = count2; + count2 = xcount; // roll back to where we were #else - // KQUEUE and EPOLL: We don't go through a loop to fill the fd_set so instead we must manually do this loop every now and again. - // TODO: We dont need to do all this EVERY loop iteration, tone down the visits to this if we're using kqueue. - cycle_iter++; - if (cycle_iter > 20) while (count2 != clientlist.end()) - { - cycle_iter = 0; - if (count2 != clientlist.end()) + // KQUEUE and EPOLL: We don't go through a loop to fill the fd_set so instead we must manually do this loop every now and again. + // TODO: We dont need to do all this EVERY loop iteration, tone down the visits to this if we're using kqueue. + cycle_iter++; + if (cycle_iter > 20) while (count2 != clientlist.end()) { - curr = count2->second; - if ((long)curr == -1) - goto label; - int currfd = curr->fd; - // we don't check the state of remote users. - if ((currfd != -1) && (currfd != FD_MAGIC_NUMBER)) + cycle_iter = 0; + if (count2 != clientlist.end()) { - - 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 (((unsigned)TIME > (unsigned)curr->timeout) && (curr->registered != 7)) - { - log(DEBUG,"InspIRCd: registration timeout: %s",curr->nick); - kill_link(curr,"Registration timeout"); - goto label; - - } - if ((TIME > curr->signon) && (curr->registered == 3) && (AllModulesReportReady(curr))) - { - log(DEBUG,"signon exceed, registered=3, and modules ready, OK: %d %d",TIME,curr->signon); - curr->dns_done = true; - statsDnsBad++; - FullConnectUser(curr); - if (fd_ref_table[currfd] != curr) // something changed, bail pronto - goto label; - } - if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr))) - { - log(DEBUG,"dns done, registered=3, and modules ready, OK"); - FullConnectUser(curr); - if (fd_ref_table[currfd] != curr) // something changed, bail pronto - goto label; - } - if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7)) + curr = count2->second; + if ((long)curr == -1) + goto label; + int currfd = curr->fd; + // we don't check the state of remote users. + if ((currfd != -1) && (currfd != FD_MAGIC_NUMBER)) { - if ((!curr->lastping) && (curr->registered == 7)) - { - log(DEBUG,"InspIRCd: ping timeout: %s",curr->nick); - kill_link(curr,"Ping timeout"); - goto label; - } - Write(curr->fd,"PING :%s",ServerName); - log(DEBUG,"InspIRCd: pinging: %s",curr->nick); - curr->lastping = 0; - curr->nping = TIME+curr->pingmax; // was hard coded to 120 + 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 (((unsigned)TIME > (unsigned)curr->timeout) && (curr->registered != 7)) + { + log(DEBUG,"InspIRCd: registration timeout: %s",curr->nick); + kill_link(curr,"Registration timeout"); + goto label; + + } + if ((TIME > curr->signon) && (curr->registered == 3) && (AllModulesReportReady(curr))) + { + log(DEBUG,"signon exceed, registered=3, and modules ready, OK: %d %d",TIME,curr->signon); + curr->dns_done = true; + statsDnsBad++; + FullConnectUser(curr); + if (fd_ref_table[currfd] != curr) // something changed, bail pronto + goto label; + } + if ((curr->dns_done) && (curr->registered == 3) && (AllModulesReportReady(curr))) + { + log(DEBUG,"dns done, registered=3, and modules ready, OK"); + FullConnectUser(curr); + if (fd_ref_table[currfd] != curr) // something changed, bail pronto + goto label; + } + if ((TIME > curr->nping) && (isnick(curr->nick)) && (curr->registered == 7)) + { + if ((!curr->lastping) && (curr->registered == 7)) + { + log(DEBUG,"InspIRCd: ping timeout: %s",curr->nick); + kill_link(curr,"Ping timeout"); + goto label; + } + Write(curr->fd,"PING :%s",ServerName); + log(DEBUG,"InspIRCd: pinging: %s",curr->nick); + curr->lastping = 0; + curr->nping = TIME+curr->pingmax; // was hard coded to 120 + } } } + else break; + count2++; } - else break; - count2++; - } - // increment the counter right to the end of the list, as kqueue processes everything in one go + // increment the counter right to the end of the list, as kqueue processes everything in one go #endif - v = 0; - engine_fill; + v = 0; + engine_fill; #ifdef _POSIX_PRIORITY_SCHEDULING - sched_yield(); + sched_yield(); #endif - result = EAGAIN; - if (engine_check) - { - log(DEBUG,"Data waiting on socket %d",cu->fd); - int MOD_RESULT = 0; - int result2 = 0; - FOREACH_RESULT(OnRawSocketRead(cu->fd,data,65535,result2)); - if (!MOD_RESULT) + result = EAGAIN; + if (engine_check) { - result = cu->ReadData(data, 65535); - } - else - { - log(DEBUG,"Data result returned by module: %d",MOD_RESULT); - result = result2; - } - log(DEBUG,"Read result: %d",result); - if (result) - { - statsRecv += result; - // perform a check on the raw buffer as an array (not a string!) to remove - // characters 0 and 7 which are illegal in the RFC - replace them with spaces. - // hopefully this should stop even more people whining about "Unknown command: *" - for (int checker = 0; checker < result; checker++) - { - if ((data[checker] == 0) || (data[checker] == 7)) - data[checker] = ' '; - } - if (result > 0) - data[result] = '\0'; - userrec* current = cu; - int currfd = current->fd; - int floodlines = 0; - // add the data to the users buffer - if (result > 0) - if (!current->AddBuffer(data)) + log(DEBUG,"Data waiting on socket %d",cu->fd); + int MOD_RESULT = 0; + int result2 = 0; + FOREACH_RESULT(OnRawSocketRead(cu->fd,data,65535,result2)); + if (!MOD_RESULT) { - // AddBuffer returned false, theres too much data in the user's buffer and theyre up to no good. - if (current->registered == 7) - { - kill_link(current,"RecvQ exceeded"); - } - else - { - WriteOpers("*** Excess flood from %s",current->ip); - log(DEFAULT,"Excess flood from: %s",current->ip); - add_zline(120,ServerName,"Flood from unregistered connection",current->ip); - apply_lines(); - } - goto label; + result = cu->ReadData(data, 65535); } - if (current->recvq.length() > (unsigned)NetBufferSize) + else { - if (current->registered == 7) - { - kill_link(current,"RecvQ exceeded"); - } - else - { - WriteOpers("*** Excess flood from %s",current->ip); - log(DEFAULT,"Excess flood from: %s",current->ip); - add_zline(120,ServerName,"Flood from unregistered connection",current->ip); - apply_lines(); - } - goto label; + log(DEBUG,"Data result returned by module: %d",MOD_RESULT); + result = result2; } - // while there are complete lines to process... - while (current->BufferIsReady()) + log(DEBUG,"Read result: %d",result); + if (result) { - floodlines++; - if (TIME > current->reset_due) + statsRecv += result; + // perform a check on the raw buffer as an array (not a string!) to remove + // characters 0 and 7 which are illegal in the RFC - replace them with spaces. + // hopefully this should stop even more people whining about "Unknown command: *" + for (int checker = 0; checker < result; checker++) { - current->reset_due = TIME + current->threshold; - current->lines_in = 0; + if ((data[checker] == 0) || (data[checker] == 7)) + data[checker] = ' '; } - current->lines_in++; - if (current->lines_in > current->flood) - { - log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); - WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); - kill_link(current,"Excess flood"); - goto label; - } - if ((floodlines > current->flood) && (current->flood != 0)) + if (result > 0) + data[result] = '\0'; + userrec* current = cu; + int currfd = current->fd; + int floodlines = 0; + // add the data to the users buffer + if (result > 0) + if (!current->AddBuffer(data)) { + // AddBuffer returned false, theres too much data in the user's buffer and theyre up to no good. if (current->registered == 7) { - log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); - WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); - kill_link(current,"Excess flood"); + kill_link(current,"RecvQ exceeded"); } else { + WriteOpers("*** Excess flood from %s",current->ip); + log(DEFAULT,"Excess flood from: %s",current->ip); add_zline(120,ServerName,"Flood from unregistered connection",current->ip); - apply_lines(); - } - goto label; + apply_lines(); + } + goto label; } - char sanitized[MAXBUF]; - // use GetBuffer to copy single lines into the sanitized string - std::string single_line = current->GetBuffer(); - current->bytes_in += single_line.length(); - current->cmds_in++; - if (single_line.length()>512) + if (current->recvq.length() > (unsigned)NetBufferSize) { - log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); - WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); - kill_link(current,"Excess flood"); + if (current->registered == 7) + { + kill_link(current,"RecvQ exceeded"); + } + else + { + WriteOpers("*** Excess flood from %s",current->ip); + log(DEFAULT,"Excess flood from: %s",current->ip); + add_zline(120,ServerName,"Flood from unregistered connection",current->ip); + apply_lines(); + } goto label; } - strlcpy(sanitized,single_line.c_str(),MAXBUF); - if (*sanitized) + // while there are complete lines to process... + while (current->BufferIsReady()) { - userrec* old_comp = fd_ref_table[currfd]; - // we're gonna re-scan to check if the nick is gone, after every - // command - if it has, we're gonna bail - process_buffer(sanitized,current); - // look for the user's record in case it's changed... if theyve quit, - // we cant do anything more with their buffer, so bail. - // there used to be an ugly, slow loop here. Now we have a reference - // table, life is much easier (and FASTER) - userrec* new_comp = fd_ref_table[currfd]; - if ((currfd < 0) || (!fd_ref_table[currfd]) || (old_comp != new_comp)) + floodlines++; + if (TIME > current->reset_due) + { + current->reset_due = TIME + current->threshold; + current->lines_in = 0; + } + current->lines_in++; + if (current->lines_in > current->flood) + { + log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); + WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); + kill_link(current,"Excess flood"); goto label; - + } + if ((floodlines > current->flood) && (current->flood != 0)) + { + if (current->registered == 7) + { + log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); + WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); + kill_link(current,"Excess flood"); + } + else + { + add_zline(120,ServerName,"Flood from unregistered connection",current->ip); + apply_lines(); + } + goto label; + } + char sanitized[MAXBUF]; + // use GetBuffer to copy single lines into the sanitized string + std::string single_line = current->GetBuffer(); + current->bytes_in += single_line.length(); + current->cmds_in++; + if (single_line.length()>512) + { + log(DEFAULT,"Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); + WriteOpers("*** Excess flood from: %s!%s@%s",current->nick,current->ident,current->host); + kill_link(current,"Excess flood"); + goto label; + } + strlcpy(sanitized,single_line.c_str(),MAXBUF); + if (*sanitized) + { + userrec* old_comp = fd_ref_table[currfd]; + // we're gonna re-scan to check if the nick is gone, after every + // command - if it has, we're gonna bail + process_buffer(sanitized,current); + // look for the user's record in case it's changed... if theyve quit, + // we cant do anything more with their buffer, so bail. + // there used to be an ugly, slow loop here. Now we have a reference + // table, life is much easier (and FASTER) + userrec* new_comp = fd_ref_table[currfd]; + if ((currfd < 0) || (!fd_ref_table[currfd]) || (old_comp != new_comp)) + goto label; + + } } + goto label; } - goto label; - } - if ((result == -1) && (errno != EAGAIN) && (errno != EINTR)) + if ((result == -1) && (errno != EAGAIN) && (errno != EINTR)) + { + log(DEBUG,"killing: %s",cu->nick); + kill_link(cu,strerror(errno)); + goto label; + } + } + // result EAGAIN means nothing read + if (result == EAGAIN) + { + } + else + if (result == 0) + { + engine_cleanup; + } + else if (result > 0) { - log(DEBUG,"killing: %s",cu->nick); - kill_link(cu,strerror(errno)); - goto label; } - } - // result EAGAIN means nothing read - if (result == EAGAIN) - { - } - else - if (result == 0) - { - engine_cleanup; - } - else if (result > 0) - { } } + for (int q = 0; q < total_in_this_set; q++) + { + count2++; + } } - for (int q = 0; q < total_in_this_set; q++) - { - count2++; - } - } - + #ifdef _POSIX_PRIORITY_SCHEDULING - sched_yield(); + sched_yield(); #endif diff --git a/src/modules.cpp b/src/modules.cpp index 35372a71e..a77d94d7c 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -59,6 +59,7 @@ using namespace std; #include "inspstring.h" #include "helperfuncs.h" #include "hashcomp.h" +#include "socket.h" #ifdef USE_KQUEUE extern int kq; @@ -74,6 +75,8 @@ extern std::vector<ircd_module*> factory; extern std::vector<std::string> include_stack; +extern std::vector<InspSocket*> module_sockets; + extern time_t TIME; extern int LogLevel; diff --git a/src/socket.cpp b/src/socket.cpp index 2b6f84cd3..cb019a3c2 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -25,6 +25,7 @@ using namespace std; #include <string> #include <unistd.h> #include <fcntl.h> +#include <poll.h> #include <sstream> #include <iostream> #include <fstream> @@ -66,6 +67,7 @@ InspSocket::InspSocket(std::string host, int port, bool listening, unsigned long if ((this->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { this->state = I_ERROR; + this->OnError(I_ERR_SOCKET); return; } this->port = port; @@ -82,9 +84,8 @@ InspSocket::InspSocket(std::string host, int port, bool listening, unsigned long { if (errno != EINPROGRESS) { - shutdown(this->fd,2); - close(this->fd); - this->fd = -1; + this->Close(); + this->OnError(I_ERR_CONNECT); this->state = I_ERROR; return; } @@ -94,37 +95,109 @@ InspSocket::InspSocket(std::string host, int port, bool listening, unsigned long } } -void InspSocket::EngineTrigger() +void InspSocket::Close() { - switch (this->state) + if (this->fd != -1) { - case I_CONNECTING: - this->OnConnected(); - break; - case I_LISTENING: - this->OnIncomingConnection(); - break; - case I_CONNECTED: - this->OnDataReady(); - break; - default: - break; + this->OnClose(); + shutdown(this->fd,2); + close(this->fd); + this->fd = -1; } } +char* InspSocket::Read() +{ + int n = recv(this->fd,this->ibuf,sizeof(this->ibuf),0); + if (n > 0) + { + return ibuf; + } + else + { + return NULL; + } +} + +// There are two possible outcomes to this function. +// It will either write all of the data, or an undefined amount. +// If an undefined amount is written the connection has failed +// and should be aborted. +int InspSocket::Write(std::string data) +{ + char* d = (char*)data.c_str(); + unsigned int written = 0; + int n = 0; + int s = data.length(); + while ((written < data.length()) && (n >= 0)) + { + n = send(this->fd,d,s,0); + if (n > 0) + { + // If we didnt write everything, advance + // the pointers so that when we retry + // the next time around the loop, we try + // to write what we failed to write before. + written += n; + s -= n; + d += n; + } + } + return written; +} + +bool InspSocket::Poll() +{ + if (time(NULL) > timeout_end) + { + this->OnTimeout(); + this->Close(); + this->OnError(I_ERR_TIMEOUT); + timeout = true; + this->state = I_ERROR; + return false; + } + polls.fd = this->fd; + state == I_CONNECTING ? polls.events = POLLOUT : polls.events = POLLIN; + int ret = poll(&polls,1,1); + + if (ret > 0) + { + switch (this->state) + { + case I_CONNECTING: + return this->OnConnected(); + break; + case I_LISTENING: + this->OnIncomingConnection(); + break; + case I_CONNECTED: + return this->OnDataReady(); + break; + default: + break; + } + } + + return true; +} + void InspSocket::SetState(InspSocketState s) { this->state = s; } -int InspSocket::OnConnected() { return 0; } -int InspSocket::OnError() { return 0; } +bool InspSocket::OnConnected() { return true; } +void InspSocket::OnError(InspSocketError e) { return; } int InspSocket::OnDisconnect() { return 0; } int InspSocket::OnIncomingConnection() { return 0; } -int InspSocket::OnDataReady() { return 0; } +bool InspSocket::OnDataReady() { return true; } +void InspSocket::OnTimeout() { return; } +void InspSocket::OnClose() { return; } InspSocket::~InspSocket() { + this->Close(); } /* |