summaryrefslogtreecommitdiff
path: root/src/servers.cpp
diff options
context:
space:
mode:
authorbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2005-05-17 16:29:45 +0000
committerbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2005-05-17 16:29:45 +0000
commitfcf2bac28ad748045bd3bc2bea99e77d1b57f693 (patch)
tree6ec11debe10f9d750b9468d06bc58bf488734c29 /src/servers.cpp
parentead90099d2867c5d3ecc3a921dcdfdc942c0135f (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.cpp352
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;
}