diff options
-rw-r--r-- | include/connection.h | 42 | ||||
-rw-r--r-- | include/servers.h | 42 | ||||
-rw-r--r-- | src/Makefile | 4 | ||||
-rw-r--r-- | src/connection.cpp | 339 | ||||
-rw-r--r-- | src/inspircd.cpp | 58 | ||||
-rw-r--r-- | src/servers.cpp | 352 |
6 files changed, 420 insertions, 417 deletions
diff --git a/include/connection.h b/include/connection.h index b84d39df9..6f33663af 100644 --- a/include/connection.h +++ b/include/connection.h @@ -270,51 +270,9 @@ class connection : public Extensible */ time_t nping; - /** With a serverrec, this is a list of all established server connections. - * With a userrec this is unused. - */ - std::vector<ircd_connector> connectors; - /** Default constructor */ connection(); - - /** Create a listening socket on 'host' using port number 'p' - */ - bool CreateListener(char* host, int p); - - /** Begin an outbound link to another ircd at targethost. - */ - bool BeginLink(char* targethost, int port, char* password, char* servername, int myport); - - /** Begin an outbound mesh link to another ircd on a network you are already an authenticated member of - */ - bool MeshCookie(char* targethost, int port, unsigned long cookie, char* servername); - - /** Terminate a link to 'targethost' by calling the ircd_connector::CloseConnection method. - */ - void TerminateLink(char* targethost); - - /** Send a message to a server by name, if the server is unavailable directly route the packet via another server - * If the server still cannot be reached after attempting to route the message remotely, returns false. - */ - bool SendPacket(char *message, const char* host); - - /** Returns the next available packet and returns true if data is available. Writes the servername the data came from to 'host'. - * If no data is available this function returns false. - * This function will automatically close broken links and reroute pathways, generating split messages on the network. - */ - bool RecvPacket(std::deque<std::string> &messages, char* host, std::deque<std::string> &sums); - - /** Find the ircd_connector oject related to a certain servername given in 'host' - */ - ircd_connector* FindHost(std::string host); - - /** Add an incoming connection to the connection pool. - * (reserved for core use) - */ - bool AddIncoming(int fd,char* targethost, int sourceport); - }; diff --git a/include/servers.h b/include/servers.h index 09e6ad1c6..e7d7f2547 100644 --- a/include/servers.h +++ b/include/servers.h @@ -75,10 +75,48 @@ class serverrec : public connection /** Destructor */ ~serverrec(); - -}; + /** With a serverrec, this is a list of all established server connections. + */ + std::vector<ircd_connector> connectors; + + + /** Create a listening socket on 'host' using port number 'p' + */ + bool CreateListener(char* host, int p); + + /** Begin an outbound link to another ircd at targethost. + */ + bool BeginLink(char* targethost, int port, char* password, char* servername, int myport); + + /** Begin an outbound mesh link to another ircd on a network you are already an authenticated member of + */ + bool MeshCookie(char* targethost, int port, unsigned long cookie, char* servername); + /** Terminate a link to 'targethost' by calling the ircd_connector::CloseConnection method. + */ + void TerminateLink(char* targethost); + + /** Send a message to a server by name, if the server is unavailable directly route the packet via another server + * If the server still cannot be reached after attempting to route the message remotely, returns false. + */ + bool SendPacket(char *message, const char* host); + + /** Returns the next available packet and returns true if data is available. Writes the servername the data came from to 'host'. + * If no data is available this function returns false. + * This function will automatically close broken links and reroute pathways, generating split messages on the network. + */ + bool RecvPacket(std::deque<std::string> &messages, char* host, std::deque<std::string> &sums); + + /** Find the ircd_connector oject related to a certain servername given in 'host' + */ + ircd_connector* FindHost(std::string host); + + /** Add an incoming connection to the connection pool. + * (reserved for core use) + */ + bool AddIncoming(int fd,char* targethost, int sourceport); +}; #endif diff --git a/src/Makefile b/src/Makefile index 7404fea5a..aeb1a9dd3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -74,7 +74,7 @@ libIRCDdynamic.so: dynamic.cpp ../include/base.h ../include/dynamic.h ../include $(CC) -pipe -I../include $(FLAGS) -export-dynamic -c dynamic.cpp $(CC) -shared -o libIRCDdynamic.so dynamic.o -libIRCDusers.so: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h +libIRCDusers.so: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/connection.h $(CC) -pipe -I../include $(FLAGS) -export-dynamic -c users.cpp $(CC) -shared -o libIRCDusers.so users.o @@ -86,7 +86,7 @@ libIRCDwildcard.so: wildcard.cpp ../include/base.h ../include/wildcard.h ../incl $(CC) -pipe -I../include $(FLAGS) -export-dynamic -c wildcard.cpp $(CC) -shared -o libIRCDwildcard.so wildcard.o -libIRCDservers.so: servers.cpp ../include/base.h ../include/servers.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h +libIRCDservers.so: servers.cpp ../include/base.h ../include/servers.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/connection.h $(CC) -pipe -I../include $(FLAGS) -export-dynamic -c servers.cpp $(CC) -shared -o libIRCDservers.so servers.o diff --git a/src/connection.cpp b/src/connection.cpp index c902c2d22..222251bb4 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -36,8 +36,6 @@ using namespace std; extern std::vector<Module*> modules; extern std::vector<ircd_module*> factory; -std::deque<std::string> xsums; - extern int MODCOUNT; extern time_t TIME; @@ -78,66 +76,6 @@ connection::connection() } -bool connection::CreateListener(char* newhost, int p) -{ - sockaddr_in host_address; - int flags; - in_addr addy; - int on = 0; - struct linger linger = { 0 }; - - this->port = p; - - fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (fd <= 0) - { - return false; - } - - setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on)); - linger.l_onoff = 1; - linger.l_linger = 1; - setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger)); - - // attempt to increase socket sendq and recvq as high as its possible - // to get them on linux. - int sendbuf = 32768; - int recvbuf = 32768; - setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); - setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf)); - - memset((void*)&host_address, 0, sizeof(host_address)); - - host_address.sin_family = AF_INET; - - if (!strcmp(newhost,"")) - { - host_address.sin_addr.s_addr = htonl(INADDR_ANY); - } - else - { - inet_aton(newhost,&addy); - host_address.sin_addr = addy; - } - - host_address.sin_port = htons(p); - - if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0) - { - return false; - } - - // make the socket non-blocking - flags = fcntl(fd, F_GETFL, 0); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); - - this->port = p; - - listen(this->fd,32); - - return true; -} - char* ircd_connector::GetServerIP() { return this->host; @@ -262,43 +200,6 @@ bool ircd_connector::MakeOutboundConnection(char* newhost, int newport) } -bool connection::BeginLink(char* targethost, int newport, char* password, char* servername, int myport) -{ - char connect[MAXBUF]; - - ircd_connector connector; - ircd_connector *cn = this->FindHost(servername); - - - if (cn) - { - WriteOpers("CONNECT aborted: Server %s already exists",servername); - return false; - } - - - if (this->fd) - { - if (connector.MakeOutboundConnection(targethost,newport)) - { - // targethost has been turned into an ip... - // we dont want this as the server name. - connector.SetServerName(servername); - snprintf(connect,MAXBUF,"S %s %s %lu %lu :%s",getservername().c_str(),password,(unsigned long)myport,(unsigned long)GetRevision(),getserverdesc().c_str()); - connector.SetState(STATE_NOAUTH_OUTBOUND); - connector.SetHostAndPort(targethost, newport); - this->connectors.push_back(connector); - return this->SendPacket(connect, servername); - } - else - { - connector.SetState(STATE_DISCONNECTED); - WriteOpers("Could not create outbound connection to %s:%d",targethost,newport); - } - } - return false; -} - void ircd_connector::SetVersionString(std::string newversion) { log(DEBUG,"Set version of %s to %s",this->servername.c_str(),newversion.c_str()); @@ -310,79 +211,6 @@ std::string ircd_connector::GetVersionString() return this->version; } -bool connection::MeshCookie(char* targethost, int newport, unsigned long cookie, char* servername) -{ - char connect[MAXBUF]; - - ircd_connector connector; - - WriteOpers("Establishing meshed link to %s:%d",servername,newport); - - if (this->fd) - { - if (connector.MakeOutboundConnection(targethost,newport)) - { - // targethost has been turned into an ip... - // we dont want this as the server name. - connector.SetServerName(servername); - snprintf(connect,MAXBUF,"- %lu %s :%s",cookie,getservername().c_str(),getserverdesc().c_str()); - connector.SetState(STATE_NOAUTH_OUTBOUND); - connector.SetHostAndPort(targethost, newport); - connector.SetState(STATE_CONNECTED); - this->connectors.push_back(connector); - return this->SendPacket(connect, servername); - } - else - { - connector.SetState(STATE_DISCONNECTED); - WriteOpers("Could not create outbound connection to %s:%d",targethost,newport); - } - } - return false; -} - -bool connection::AddIncoming(int newfd, char* targethost, int sourceport) -{ - ircd_connector connector; - - // targethost has been turned into an ip... - // we dont want this as the server name. - connector.SetServerName(targethost); - connector.SetDescriptor(newfd); - connector.SetState(STATE_NOAUTH_INBOUND); - int flags = fcntl(newfd, F_GETFL, 0); - fcntl(newfd, F_SETFL, flags | O_NONBLOCK); - int sendbuf = 32768; - int recvbuf = 32768; - setsockopt(newfd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); - setsockopt(newfd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf)); - connector.SetHostAndPort(targethost, sourceport); - connector.SetState(STATE_NOAUTH_INBOUND); - log(DEBUG,"connection::AddIncoming() Added connection: %s:%d",targethost,sourceport); - this->connectors.push_back(connector); - return true; -} - -void connection::TerminateLink(char* targethost) -{ - // this locates the targethost in the connection::connectors vector of the class, - // and terminates it by sending it an SQUIT token and closing its descriptor. - // TerminateLink with a null string causes a terminate of ALL links -} - - -// Returns a pointer to the connector for 'host' -ircd_connector* connection::FindHost(std::string findhost) -{ - for (int i = 0; i < this->connectors.size(); i++) - { - if (this->connectors[i].GetServerName() == findhost) - { - return &this->connectors[i]; - } - } - return NULL; -} std::string ircd_connector::GetServerName() { @@ -438,170 +266,3 @@ void ircd_connector::SetDescriptor(int newfd) { this->fd = newfd; } - -bool connection::SendPacket(char *message, const char* sendhost) -{ - if ((!message) || (!sendhost)) - return true; - - ircd_connector* cn = this->FindHost(sendhost); - - if (!strchr(message,'\n')) - { - strlcat(message,"\n",MAXBUF); - } - - if (cn) - { - log(DEBUG,"main: Connection::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str()); - - if (cn->GetState() == STATE_DISCONNECTED) - { - log(DEBUG,"\n\n\n\nMain route to %s is down, seeking alternative\n\n\n\n",sendhost); - // fix: can only route one hop to avoid a loop - if (strncmp(message,"R ",2)) - { - log(DEBUG,"Not a double reroute"); - // this route is down, we must re-route the packet through an available point in the mesh. - for (int k = 0; k < this->connectors.size(); k++) - { - log(DEBUG,"Check connector %d: %s",k,this->connectors[k].GetServerName().c_str()); - // search for another point in the mesh which can 'reach' where we want to go - for (int m = 0; m < this->connectors[k].routes.size(); m++) - { - log(DEBUG,"Check connector %d: %s route %s",k,this->connectors[k].GetServerName().c_str(),this->connectors[k].routes[m].c_str()); - if (!strcasecmp(this->connectors[k].routes[m].c_str(),sendhost)) - { - log(DEBUG,"Found alternative route for packet: %s",this->connectors[k].GetServerName().c_str()); - char buffer[MAXBUF]; - snprintf(buffer,MAXBUF,"R %s %s",sendhost,message); - this->SendPacket(buffer,this->connectors[k].GetServerName().c_str()); - return true; - } - } - } - } - char buffer[MAXBUF]; - snprintf(buffer,MAXBUF,"& %s",sendhost); - NetSendToAllExcept(sendhost,buffer); - log(DEBUG,"\n\nThere are no routes to %s, we're gonna boot the server off!\n\n",sendhost); - DoSplit(sendhost); - return false; - } - - // returns false if the packet could not be sent (e.g. target host down) - if (send(cn->GetDescriptor(),message,strlen(message),0)<0) - { - log(DEBUG,"send() failed for Connection::SendPacket(): %s",strerror(errno)); - log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str()); - cn->CloseConnection(); - cn->SetState(STATE_DISCONNECTED); - // retry the packet along a new route so either arrival OR failure are gauranteed (bugfix) - return this->SendPacket(message,sendhost); - } - return true; - } -} - -bool already_have_sum(std::string sum) -{ - for (int i = 0; i < xsums.size(); i++) - { - if (xsums[i] == sum) - { - return true; - } - } - if (xsums.size() >= 128) - { - xsums.pop_front(); - } - xsums.push_back(sum); - return false; -} - -// receives a packet from any where there is data waiting, first come, first served -// fills the message and host values with the host where the data came from. - -bool connection::RecvPacket(std::deque<std::string> &messages, char* recvhost,std::deque<std::string> &sums) -{ - char data[65536]; - memset(data, 0, 65536); - for (int i = 0; i < this->connectors.size(); i++) - { - if (this->connectors[i].GetState() != STATE_DISCONNECTED) - { - // returns false if the packet could not be sent (e.g. target host down) - int rcvsize = 0; - - // check if theres any data on this socket - // if not, continue onwards to the next. - pollfd polls; - polls.fd = this->connectors[i].GetDescriptor(); - polls.events = POLLIN; - int ret = poll(&polls,1,1); - if (ret <= 0) continue; - - rcvsize = recv(this->connectors[i].GetDescriptor(),data,65000,0); - data[rcvsize] = '\0'; - if (rcvsize == -1) - { - if (errno != EAGAIN) - { - log(DEBUG,"recv() failed for Connection::RecvPacket(): %s",strerror(errno)); - log(DEBUG,"Disabling connector: %s",this->connectors[i].GetServerName().c_str()); - this->connectors[i].CloseConnection(); - this->connectors[i].SetState(STATE_DISCONNECTED); - } - } - int pushed = 0; - if (rcvsize > 0) - { - this->connectors[i].AddBuffer(data); - if (this->connectors[i].BufferIsComplete()) - { - while (this->connectors[i].BufferIsComplete()) - { - std::string text = this->connectors[i].GetBuffer(); - if (text != "") - { - if ((text[0] == ':') && (text.find(" ") != std::string::npos)) - { - std::string orig = text; - log(DEBUG,"Original: %s",text.c_str()); - std::string sum = text.substr(1,text.find(" ")-1); - text = text.substr(text.find(" ")+1,text.length()); - std::string possible_token = text.substr(1,text.find(" ")-1); - if (possible_token.length() > 1) - { - sums.push_back("*"); - text = orig; - log(DEBUG,"Non-mesh, non-tokenized string passed up the chain"); - } - else - { - log(DEBUG,"Packet sum: '%s'",sum.c_str()); - if ((already_have_sum(sum)) && (sum != "*")) - { - // we don't accept dupes - log(DEBUG,"Duplicate packet sum %s from server %s dropped",sum.c_str(),this->connectors[i].GetServerName().c_str()); - continue; - } - sums.push_back(sum.c_str()); - } - } - else sums.push_back("*"); - messages.push_back(text.c_str()); - strlcpy(recvhost,this->connectors[i].GetServerName().c_str(),160); - log(DEBUG,"Connection::RecvPacket() %d:%s->%s",pushed++,recvhost,text.c_str()); - } - } - return true; - } - } - } - } - // nothing new yet -- message and host will be undefined - return false; -} - diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 701b95381..d5156117a 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -2855,49 +2855,45 @@ int InspIRCd(char** argv, int argc) } } + std::deque<std::string> msgs; + std::deque<std::string> sums; for (int x = 0; x < SERVERportCount; x++) { - std::deque<std::string> msgs; - std::deque<std::string> sums; - msgs.clear(); sums.clear(); - if (me[x]) + msgs.clear(); + while ((me[x]) && (me[x]->RecvPacket(msgs, tcp_host, sums))) // returns 0 or more lines (can be multiple lines!) { - sums.clear(); - msgs.clear(); - while (me[x]->RecvPacket(msgs, tcp_host, sums)) + for (int ctr = 0; ctr < msgs.size(); ctr++) { - for (int ctr = 0; ctr < msgs.size(); ctr++) + strlcpy(tcp_msg,msgs[ctr].c_str(),MAXBUF); + strlcpy(tcp_sum,msgs[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))) { - strlcpy(tcp_msg,msgs[ctr].c_str(),MAXBUF); - strlcpy(tcp_sum,msgs[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 (is_uline(tcp_host)) + if ((tcp_msg[0] != 'Y') && (tcp_msg[0] != 'X') && (tcp_msg[0] != 'F')) { - 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); + else + NetSendToAllExcept_WithSum(tcp_host,tcp_msg,tcp_sum); } - //goto label; + 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); } + sums.clear(); // we're done, clear the list for the next operation + msgs.clear(); } } diff --git a/src/servers.cpp b/src/servers.cpp index 45ec5b00e..56e0d0c41 100644 --- a/src/servers.cpp +++ b/src/servers.cpp @@ -19,13 +19,25 @@ using namespace std; #include "inspircd_config.h" #include "servers.h" #include "inspircd.h" -#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <poll.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/utsname.h> +#include <vector> +#include <string> +#include <deque> +#include <sstream> #include <map> #include "inspstring.h" #include "helperfuncs.h" +#include "connection.h" extern time_t TIME; +std::deque<std::string> xsums; + serverrec::serverrec() { strlcpy(name,"",256); @@ -38,6 +50,7 @@ serverrec::serverrec() fd = 0; sync_soon = false; strlcpy(nickserv,"",NICKMAX); + connectors.clear(); } @@ -57,5 +70,342 @@ serverrec::serverrec(char* n, long ver, bool jupe) fd = 0; sync_soon = false; strlcpy(nickserv,"",NICKMAX); + connectors.clear(); +} + +bool serverrec::CreateListener(char* newhost, int p) +{ + sockaddr_in host_address; + int flags; + in_addr addy; + int on = 0; + struct linger linger = { 0 }; + + this->port = p; + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd <= 0) + { + return false; + } + + setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on)); + linger.l_onoff = 1; + linger.l_linger = 1; + setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger)); + + // attempt to increase socket sendq and recvq as high as its possible + // to get them on linux. + int sendbuf = 32768; + int recvbuf = 32768; + setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); + setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf)); + + memset((void*)&host_address, 0, sizeof(host_address)); + + host_address.sin_family = AF_INET; + + if (!strcmp(newhost,"")) + { + host_address.sin_addr.s_addr = htonl(INADDR_ANY); + } + else + { + inet_aton(newhost,&addy); + host_address.sin_addr = addy; + } + + host_address.sin_port = htons(p); + + if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0) + { + return false; + } + + // make the socket non-blocking + flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + + this->port = p; + + listen(this->fd,32); + + return true; +} + + +bool serverrec::BeginLink(char* targethost, int newport, char* password, char* servername, int myport) +{ + char connect[MAXBUF]; + + ircd_connector connector; + ircd_connector *cn = this->FindHost(servername); + + + if (cn) + { + WriteOpers("CONNECT aborted: Server %s already exists",servername); + return false; + } + + + if (this->fd) + { + if (connector.MakeOutboundConnection(targethost,newport)) + { + // targethost has been turned into an ip... + // we dont want this as the server name. + connector.SetServerName(servername); + snprintf(connect,MAXBUF,"S %s %s %lu %lu :%s",getservername().c_str(),password,(unsigned long)myport,(unsigned long)GetRevision(),getserverdesc().c_str()); + connector.SetState(STATE_NOAUTH_OUTBOUND); + connector.SetHostAndPort(targethost, newport); + this->connectors.push_back(connector); + return this->SendPacket(connect, servername); + } + else + { + connector.SetState(STATE_DISCONNECTED); + WriteOpers("Could not create outbound connection to %s:%d",targethost,newport); + } + } + return false; +} + + +bool serverrec::MeshCookie(char* targethost, int newport, unsigned long cookie, char* servername) +{ + char connect[MAXBUF]; + + ircd_connector connector; + + WriteOpers("Establishing meshed link to %s:%d",servername,newport); + + if (this->fd) + { + if (connector.MakeOutboundConnection(targethost,newport)) + { + // targethost has been turned into an ip... + // we dont want this as the server name. + connector.SetServerName(servername); + snprintf(connect,MAXBUF,"- %lu %s :%s",cookie,getservername().c_str(),getserverdesc().c_str()); + connector.SetState(STATE_NOAUTH_OUTBOUND); + connector.SetHostAndPort(targethost, newport); + connector.SetState(STATE_CONNECTED); + this->connectors.push_back(connector); + return this->SendPacket(connect, servername); + } + else + { + connector.SetState(STATE_DISCONNECTED); + WriteOpers("Could not create outbound connection to %s:%d",targethost,newport); + } + } + return false; +} + +bool serverrec::AddIncoming(int newfd, char* targethost, int sourceport) +{ + ircd_connector connector; + + // targethost has been turned into an ip... + // we dont want this as the server name. + connector.SetServerName(targethost); + connector.SetDescriptor(newfd); + connector.SetState(STATE_NOAUTH_INBOUND); + int flags = fcntl(newfd, F_GETFL, 0); + fcntl(newfd, F_SETFL, flags | O_NONBLOCK); + int sendbuf = 32768; + int recvbuf = 32768; + setsockopt(newfd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); + setsockopt(newfd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf)); + connector.SetHostAndPort(targethost, sourceport); + connector.SetState(STATE_NOAUTH_INBOUND); + log(DEBUG,"serverrec::AddIncoming() Added connection: %s:%d",targethost,sourceport); + this->connectors.push_back(connector); + return true; +} + +void serverrec::TerminateLink(char* targethost) +{ + // this locates the targethost in the serverrec::connectors vector of the class, + // and terminates it by sending it an SQUIT token and closing its descriptor. + // TerminateLink with a null string causes a terminate of ALL links +} + +// Returns a pointer to the connector for 'host' +ircd_connector* serverrec::FindHost(std::string findhost) +{ + for (int i = 0; i < this->connectors.size(); i++) + { + if (this->connectors[i].GetServerName() == findhost) + { + return &this->connectors[i]; + } + } + return NULL; +} + +bool serverrec::SendPacket(char *message, const char* sendhost) +{ + if ((!message) || (!sendhost)) + return true; + + ircd_connector* cn = this->FindHost(sendhost); + + if (!strchr(message,'\n')) + { + strlcat(message,"\n",MAXBUF); + } + + if (cn) + { + log(DEBUG,"main: serverrec::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str()); + + if (cn->GetState() == STATE_DISCONNECTED) + { + log(DEBUG,"\n\n\n\nMain route to %s is down, seeking alternative\n\n\n\n",sendhost); + // fix: can only route one hop to avoid a loop + if (strncmp(message,"R ",2)) + { + log(DEBUG,"Not a double reroute"); + // this route is down, we must re-route the packet through an available point in the mesh. + for (int k = 0; k < this->connectors.size(); k++) + { + log(DEBUG,"Check connector %d: %s",k,this->connectors[k].GetServerName().c_str()); + // search for another point in the mesh which can 'reach' where we want to go + for (int m = 0; m < this->connectors[k].routes.size(); m++) + { + if (!strcasecmp(this->connectors[k].routes[m].c_str(),sendhost)) + { + log(DEBUG,"Found alternative route for packet: %s",this->connectors[k].GetServerName().c_str()); + char buffer[MAXBUF]; + snprintf(buffer,MAXBUF,"R %s %s",sendhost,message); + this->SendPacket(buffer,this->connectors[k].GetServerName().c_str()); + return true; + } + } + } + } + char buffer[MAXBUF]; + snprintf(buffer,MAXBUF,"& %s",sendhost); + NetSendToAllExcept(sendhost,buffer); + log(DEBUG,"\n\nThere are no routes to %s, we're gonna boot the server off!\n\n",sendhost); + DoSplit(sendhost); + return false; + } + + // returns false if the packet could not be sent (e.g. target host down) + if (send(cn->GetDescriptor(),message,strlen(message),0)<0) + { + log(DEBUG,"send() failed for serverrec::SendPacket(): %s",strerror(errno)); + log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str()); + cn->CloseConnection(); + cn->SetState(STATE_DISCONNECTED); + // retry the packet along a new route so either arrival OR failure are gauranteed (bugfix) + return this->SendPacket(message,sendhost); + } + return true; + } +} + +bool already_have_sum(std::string sum) +{ + for (int i = 0; i < xsums.size(); i++) + { + if (xsums[i] == sum) + { + return true; + } + } + if (xsums.size() >= 128) + { + xsums.pop_front(); + } + xsums.push_back(sum); + return false; +} + +// receives a packet from any where there is data waiting, first come, first served +// fills the message and host values with the host where the data came from. + +bool serverrec::RecvPacket(std::deque<std::string> &messages, char* recvhost,std::deque<std::string> &sums) +{ + char data[65536]; + memset(data, 0, 65536); + for (int i = 0; i < this->connectors.size(); i++) + { + if (this->connectors[i].GetState() != STATE_DISCONNECTED) + { + // returns false if the packet could not be sent (e.g. target host down) + int rcvsize = 0; + + // check if theres any data on this socket + // if not, continue onwards to the next. + pollfd polls; + polls.fd = this->connectors[i].GetDescriptor(); + polls.events = POLLIN; + int ret = poll(&polls,1,1); + if (ret <= 0) continue; + + rcvsize = recv(this->connectors[i].GetDescriptor(),data,65000,0); + data[rcvsize] = '\0'; + if (rcvsize == -1) + { + if (errno != EAGAIN) + { + log(DEBUG,"recv() failed for serverrec::RecvPacket(): %s",strerror(errno)); + log(DEBUG,"Disabling connector: %s",this->connectors[i].GetServerName().c_str()); + this->connectors[i].CloseConnection(); + this->connectors[i].SetState(STATE_DISCONNECTED); + } + } + int pushed = 0; + if (rcvsize > 0) + { + this->connectors[i].AddBuffer(data); + if (this->connectors[i].BufferIsComplete()) + { + while (this->connectors[i].BufferIsComplete()) + { + std::string text = this->connectors[i].GetBuffer(); + if (text != "") + { + if ((text[0] == ':') && (text.find(" ") != std::string::npos)) + { + std::string orig = text; + log(DEBUG,"Original: %s",text.c_str()); + std::string sum = text.substr(1,text.find(" ")-1); + text = text.substr(text.find(" ")+1,text.length()); + std::string possible_token = text.substr(1,text.find(" ")-1); + if (possible_token.length() > 1) + { + sums.push_back("*"); + text = orig; + log(DEBUG,"Non-mesh, non-tokenized string passed up the chain"); + } + else + { + log(DEBUG,"Packet sum: '%s'",sum.c_str()); + if ((already_have_sum(sum)) && (sum != "*")) + { + // we don't accept dupes + continue; + } + sums.push_back(sum.c_str()); + } + } + else sums.push_back("*"); + messages.push_back(text.c_str()); + strlcpy(recvhost,this->connectors[i].GetServerName().c_str(),160); + log(DEBUG,"serverrec::RecvPacket() %d:%s->%s",pushed++,recvhost,text.c_str()); + } + } + return true; + } + } + } + } + // nothing new yet -- message and host will be undefined + return false; } |