From a595cf3435c7f458058d1f217458da7701c735ca Mon Sep 17 00:00:00 2001 From: brain Date: Sun, 27 Nov 2005 20:33:20 +0000 Subject: Added tree walk algorithm which finds out which directly-connected server to send data to when there is a one-to-one message git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@1970 e03df62e-2008-0410-955e-edbf42e46eb7 --- src/modules/m_spanningtree.cpp | 122 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) (limited to 'src/modules') diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp index 8ec9e564e..478dc5d9a 100644 --- a/src/modules/m_spanningtree.cpp +++ b/src/modules/m_spanningtree.cpp @@ -19,15 +19,34 @@ using namespace std; #include #include #include +#include "globals.h" +#include "inspircd_config.h" +#ifdef GCC3 +#include +#else +#include +#endif #include "users.h" #include "channels.h" #include "modules.h" #include "socket.h" #include "helperfuncs.h" #include "inspircd.h" +#include "inspstring.h" +#include "hashcomp.h" +#include "message.h" + +#ifdef GCC3 +#define nspace __gnu_cxx +#else +#define nspace std +#endif enum ServerState { LISTENER, CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED }; +typedef nspace::hash_map, irc::StrHashComp> user_hash; +extern user_hash clientlist; + class TreeServer; class TreeSocket; @@ -101,6 +120,23 @@ class TreeServer return this->Parent; } + unsigned int ChildCount() + { + return Children.size(); + } + + TreeServer* GetChild(unsigned int n) + { + if (n < Children.size()) + { + return Children[n]; + } + else + { + return NULL; + } + } + void AddChild(TreeServer* Child) { Children.push_back(Child); @@ -137,6 +173,49 @@ ConfigReader *Conf; TreeServer *TreeRoot; std::vector LinkBlocks; +TreeServer* RouteEnumerate(TreeServer* Current, std::string ServerName) +{ + if (Current->GetName() == ServerName) + return Current; + for (unsigned int q = 0; q < Current->ChildCount(); q++) + { + TreeServer* found = RouteEnumerate(Current->GetChild(),ServerName); + if (found) + { + return found; + } + } + return NULL; +} + +// Returns the locally connected server we must route a +// message through to reach server 'ServerName'. This +// only applies to one-to-one and not one-to-many routing. +TreeServer* BestRouteTo(std::string ServerName) +{ + log(DEBUG,"Finding best route to %s",ServerName.c_str()); + // first, find the server by recursively walking the tree + TreeServer* Found = RouteEnumerate(TreeRoot,ServerName); + // did we find it? If not, they did something wrong, abort. + if (!Found) + { + log(DEBUG,"Failed to find %s by walking tree!",ServerName.c_str()); + return NULL; + } + else + { + // The server exists, follow its parent nodes until + // the parent of the current is 'TreeRoot', we know + // then that this is a directly-connected server. + while ((Found) && (Found->GetParent() != TreeRoot)) + { + Found = Found->GetParent(); + } + log(DEBUG,"Route to %s is via %s",ServerName.c_str(),Found->GetName().c_str()); + return Found; + } +} + class TreeSocket : public InspSocket { std::string myhost; @@ -201,11 +280,54 @@ class TreeSocket : public InspSocket return true; } + // recursively send the server tree with distances as hops + void SendServers(TreeServer* Current, TreeServer* s, int hops) + { + char command[1024]; + for (unsigned int q = 0; q < Current->ChildCount(); q++) + { + TreeServer* recursive_server = Current->GetChild(q); + if (recursive_server != s) + { + // :source.server SERVER server.name hops :Description + snprintf(command,1024,":%s SERVER %s * %d :%s",Current->GetName().c_str(),recursive_server->GetName().c_str(),hops,recursive_server->GetDesc().c_str()); + this->WriteLine(command); + // down to next level + this->SendServers(recursive_server, s, hops+1); + } + } + } + + // send all users and their channels + void SendUsers(TreeServer* Current) + { + char data[MAXBUF]; + for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++) + { + snprintf(data,MAXBUF,":%s NICK %lu %s %s %s %s +%s %s :%s",u->second->server,(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->modes,u->second->ip,u->second->fullname); + this->WriteLine(data); + if (strchr(u->second->modes,'o')) + { + this->WriteLine(":"+std::string(u->second->nick)+" OPERTYPE "+std::string(u->second->oper)); + } + char* chl = chlist(u->second,u->second); + if (*chl) + { + this->WriteLine(":"+std::string(u->second->nick)+" JOIN "+std::string(chl)); + } + } + } + void DoBurst(TreeServer* s) { log(DEBUG,"Beginning network burst"); Srv->SendOpers("*** Bursting to "+s->GetName()+"."); this->WriteLine("BURST"); + // Send server tree + this->SendServers(TreeRoot,s,1); + // Send users and their channels + this->SendUsers(s); + // TODO: Send everything else this->WriteLine("ENDBURST"); } -- cgit v1.2.3