summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/connection.h42
-rw-r--r--include/servers.h42
-rw-r--r--src/Makefile4
-rw-r--r--src/connection.cpp339
-rw-r--r--src/inspircd.cpp58
-rw-r--r--src/servers.cpp352
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;
}