diff options
author | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2005-05-17 16:29:45 +0000 |
---|---|---|
committer | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2005-05-17 16:29:45 +0000 |
commit | fcf2bac28ad748045bd3bc2bea99e77d1b57f693 (patch) | |
tree | 6ec11debe10f9d750b9468d06bc58bf488734c29 /src/servers.cpp | |
parent | ead90099d2867c5d3ecc3a921dcdfdc942c0135f (diff) |
Moved a load of servers-only stuff into serverrec out of the way of userrec
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@1417 e03df62e-2008-0410-955e-edbf42e46eb7
Diffstat (limited to 'src/servers.cpp')
-rw-r--r-- | src/servers.cpp | 352 |
1 files changed, 351 insertions, 1 deletions
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; } |