]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/connection.cpp
Updated to keep lowermap const within hashcomp.cpp
[user/henk/code/inspircd.git] / src / connection.cpp
index cd994ea652870b469d6474a617ea01feb4b70e21..384f626e2f2f59f0cbefa57ec3fa6d9bc5d29897 100644 (file)
 #include <vector>
 #include <string>
 #include <deque>
+#include <sstream>
 #include "inspircd.h"
 #include "modules.h"
 #include "inspstring.h"
+#include "helperfuncs.h"
 
 using namespace std;
 
@@ -34,10 +36,42 @@ 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;
 
+
+/**
+ * The InspIRCd mesh network is maintained by a tree of objects which reference *themselves*.
+ * Every local server has an array of 32 *serverrecs, known as me[]. Each of these represents
+ * a local listening port, and is not null if the user has opened a listening port on the server.
+ * It is assumed nobody will ever want to open more than 32 listening server ports at any one
+ * time (i mean come on, why would you want more, the ircd works fine with ONE).
+ * Each me[] entry has multiple classes within it of type ircd_connector. These are stored in a vector
+ * and each represents a server linked via this socket. If the connection was created outbound,
+ * the connection is bound to the default ip address by using me[defaultRoute] (defaultRoute being
+ * a global variable which indicates the default server to make connections on). If the connection
+ * was created inbound, it is attached to the port the connection came in on. There may be as many
+ * ircd_connector objects as needed in each me[] entry. Each ircd_connector implements the specifics
+ * of an ircd connection in the mesh, however each ircd may have multiple ircd_connector connections
+ * to it, to maintain the mesh link.
+ */
+
+char* xsumtable = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+// creates a random id for a line for detection of duplicate messages
+std::string CreateSum()
+{
+       char sum[9];
+       sum[0] = ':';
+       sum[8] = '\0';
+       for(int q = 1; q < 8; q++)
+               sum[q] = xsumtable[rand()%52];
+       return sum;
+}
+
 connection::connection()
 {
        fd = 0;
@@ -139,9 +173,15 @@ void ircd_connector::SetServerPort(int p)
 
 void ircd_connector::AddBuffer(std::string a)
 {
+       std::string b = "";
        for (int i = 0; i < a.length(); i++)
                if (a[i] != '\r')
-                       ircdbuffer = ircdbuffer + a[i];
+                       b = b + a[i];
+
+       std::stringstream stream(ircdbuffer);
+       stream << b;
+       log(DEBUG,"AddBuffer: %s",b.c_str());
+       ircdbuffer = stream.str();
 }
 
 bool ircd_connector::BufferIsComplete()
@@ -154,24 +194,26 @@ bool ircd_connector::BufferIsComplete()
 
 void ircd_connector::ClearBuffer()
 {
-       while ((ircdbuffer != "") && (ircdbuffer[0] != '\n'))
-       {
-               ircdbuffer.erase(ircdbuffer.begin());
-       }
-       if (ircdbuffer != "")
-               ircdbuffer.erase(ircdbuffer.begin());
+       ircdbuffer = "";
 }
 
 std::string ircd_connector::GetBuffer()
 {
-       std::string z = "";
-       long t = 0;
-       while (ircdbuffer[t] != '\n')
-       {
-               z = z + ircdbuffer[t];
-               t++;
-       }
-       return z;
+       // Fix by Brain 28th Apr 2005
+       // seems my stringstream code isnt liked by linux
+       // EVEN THOUGH IT IS CORRECT! Fixed by using a different
+       // (SLOWER) algorithm...
+        char* line = (char*)ircdbuffer.c_str();
+        std::string ret = "";
+        while ((*line != '\n') && (strlen(line)))
+        {
+                ret = ret + *line;
+                line++;
+        }
+        if ((*line == '\n') || (*line == '\r'))
+                line++;
+        ircdbuffer = line;
+        return ret;
 }
 
 bool ircd_connector::MakeOutboundConnection(char* newhost, int newport)
@@ -257,6 +299,17 @@ bool connection::BeginLink(char* targethost, int newport, char* password, char*
        return false;
 }
 
+void ircd_connector::SetVersionString(std::string newversion)
+{
+       log(DEBUG,"Set version of %s to %s",this->servername.c_str(),newversion.c_str());
+       this->version = newversion;
+}
+
+std::string ircd_connector::GetVersionString()
+{
+       return this->version;
+}
+
 bool connection::MeshCookie(char* targethost, int newport, unsigned long cookie, char* servername)
 {
        char connect[MAXBUF];
@@ -404,16 +457,19 @@ bool connection::SendPacket(char *message, const char* sendhost)
                
                if (cn->GetState() == STATE_DISCONNECTED)
                {
-                       log(DEBUG,"Main route to %s is down, seeking alternative",host);
+                       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());
@@ -428,7 +484,7 @@ bool connection::SendPacket(char *message, const char* sendhost)
                        char buffer[MAXBUF];
                        snprintf(buffer,MAXBUF,"& %s",sendhost);
                        NetSendToAllExcept(sendhost,buffer);
-                       log(DEBUG,"There are no routes to %s, we're gonna boot the server off!",sendhost);
+                       log(DEBUG,"\n\nThere are no routes to %s, we're gonna boot the server off!\n\n",sendhost);
                        DoSplit(sendhost);
                        return false;
                }
@@ -447,20 +503,46 @@ bool connection::SendPacket(char *message, const char* sendhost)
        }
 }
 
+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)
+bool connection::RecvPacket(std::deque<std::string> &messages, char* recvhost,std::deque<std::string> &sums)
 {
-       char data[4096];
-       memset(data, 0, 4096);
+       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;
-                       rcvsize = recv(this->connectors[i].GetDescriptor(),data,32,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)
                        {
@@ -472,15 +554,48 @@ bool connection::RecvPacket(std::deque<std::string> &messages, char* recvhost)
                                        this->connectors[i].SetState(STATE_DISCONNECTED);
                                }
                        }
+                       int pushed = 0;
                        if (rcvsize > 0)
                        {
                                this->connectors[i].AddBuffer(data);
                                if (this->connectors[i].BufferIsComplete())
                                {
-                                       messages.push_back(this->connectors[i].GetBuffer().c_str());
-                                       strlcpy(host,this->connectors[i].GetServerName().c_str(),160);
-                                       log(DEBUG,"main: Connection::RecvPacket() got '%s' from %s",this->connectors[i].GetBuffer().c_str(),recvhost);
-                                       this->connectors[i].ClearBuffer();
+                                       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;
                                }
                        }
@@ -490,8 +605,3 @@ bool connection::RecvPacket(std::deque<std::string> &messages, char* recvhost)
        return false;
 }
 
-long connection::GenKey()
-{
-       return (random()*time(NULL));
-}
-