typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;
extern user_hash clientlist;
-const char* OneToEither[] = { "PRIVMSG", "NOTICE", NULL };
-const char* OneToMany[] = { "NICK", "QUIT", "JOIN", "PART", "MODE", "INVITE", "KICK", "KILL", NULL };
-const char* OneToOne[] = { "REHASH", "DIE", "TRACE", "WHOIS", NULL };
-
class TreeServer;
class TreeSocket;
bool DoOneToOne(std::string prefix, std::string command, std::deque<std::string> params, std::string target);
bool DoOneToAllButSender(std::string prefix, std::string command, std::deque<std::string> params, std::string omit);
bool DoOneToMany(std::string prefix, std::string command, std::deque<std::string> params);
+bool DoOneToAllButSenderRaw(std::string data,std::string omit);
class TreeServer
{
}
return false;
}
+
+ // removes child nodes of this node, and of that node, etc etc
+ bool Tidy()
+ {
+ bool stillchildren = true;
+ while (stillchildren)
+ {
+ stillchildren = false;
+ for (std::vector<TreeServer*>::iterator a = Children.begin(); a < Children.end(); a++)
+ {
+ TreeServer* s = (TreeServer*)*a;
+ s->Tidy();
+ Children.erase(a);
+ delete s;
+ stillchildren = true;
+ break;
+ }
+ }
+ return true;
+ }
};
class Link
ServerState LinkState;
std::string InboundServerName;
std::string InboundDescription;
+ int num_lost_users;
+ int num_lost_servers;
public:
}
}
+ void SquitServer(TreeServer* Current)
+ {
+ // recursively squit the servers attached to 'Current'
+ for (unsigned int q = 0; q < Current->ChildCount(); q++)
+ {
+ TreeServer* recursive_server = Current->GetChild(q);
+ this->SquitServer(recursive_server);
+ }
+ // Now we've whacked the kids, whack self
+ log(DEBUG,"Deleted %s",Current->GetName().c_str());
+ num_lost_servers++;
+ bool quittingpeople = true;
+ while (quittingpeople)
+ {
+ quittingpeople = false;
+ for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
+ {
+ if (!strcasecmp(u->second->server,Current->GetName().c_str()))
+ {
+ log(DEBUG,"Quitting user %s of server %s",u->second->nick,u->second->server);
+ Srv->QuitUser(u->second,Current->GetName()+" "+std::string(Srv->GetServerName()));
+ num_lost_users++;
+ quittingpeople = true;
+ break;
+ }
+ }
+ }
+ }
+
+ void Squit(TreeServer* Current,std::string reason)
+ {
+ if (Current)
+ {
+ std::deque<std::string> params;
+ params.push_back(Current->GetName());
+ params.push_back(":"+reason);
+ DoOneToAllButSender(Current->GetParent()->GetName(),"SQUIT",params,Current->GetName());
+ if (Current->GetParent() == TreeRoot)
+ {
+ Srv->SendOpers("Server \002"+Current->GetName()+"\002 split: "+reason);
+ }
+ else
+ {
+ Srv->SendOpers("Server \002"+Current->GetName()+"\002 split from server \002"+Current->GetParent()->GetName()+"\002 with reason: "+reason);
+ }
+ num_lost_servers = 0;
+ num_lost_users = 0;
+ SquitServer(Current);
+ Current->Tidy();
+ Current->GetParent()->DelChild(Current);
+ delete Current;
+ WriteOpers("Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers);
+ }
+ else
+ {
+ log(DEBUG,"Squit from unknown server");
+ }
+ }
+
bool ForceJoin(std::string source, std::deque<std::string> params)
{
if (params.size() < 1)
}
TreeServer* Node = new TreeServer(servername,description,ParentOfThis,NULL);
ParentOfThis->AddChild(Node);
+ params[3] = ":" + params[3];
DoOneToAllButSender(prefix,"SERVER",params,prefix);
- Srv->SendOpers("*** Server "+prefix+" introduced server "+servername+" ("+description+")");
+ Srv->SendOpers("*** Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")");
return true;
}
// node.
TreeServer* Node = new TreeServer(servername,description,TreeRoot,this);
TreeRoot->AddChild(Node);
- DoOneToAllButSender(servername,"SERVER",params,servername);
+ DoOneToAllButSender(TreeRoot->GetName(),"SERVER",params,servername);
this->DoBurst(Node);
return true;
}
{
if ((x->Name == servername) && (x->RecvPass == password))
{
- Srv->SendOpers("*** Verified incoming server connection from "+servername+"["+this->GetIP()+"] ("+description+")");
+ Srv->SendOpers("*** Verified incoming server connection from \002"+servername+"\002["+this->GetIP()+"] ("+description+")");
this->InboundServerName = servername;
this->InboundDescription = description;
// this is good. Send our details: Our server name and description and hopcount of 0,
return false;
}
- std::deque<std::string> Split(std::string line)
+ std::deque<std::string> Split(std::string line, bool stripcolon)
{
std::deque<std::string> n;
std::stringstream s(line);
bool ProcessLine(std::string line)
{
- Srv->SendToModeMask("o",WM_AND,"inbound-line: '"+line+"'");
-
- std::deque<std::string> params = this->Split(line);
+ Srv->Log(DEBUG,"inbound-line: '"+line+"'");
+ std::deque<std::string> params = this->Split(line,true);
std::string command = "";
std::string prefix = "";
if (((params[0].c_str())[0] == ':') && (params.size() > 1))
this->LinkState = CONNECTED;
Node = new TreeServer(InboundServerName,InboundDescription,TreeRoot,this);
TreeRoot->AddChild(Node);
- DoOneToAllButSender(InboundServerName,"SERVER",params,InboundServerName);
+ params.clear();
+ params.push_back(InboundServerName);
+ params.push_back("*");
+ params.push_back("1");
+ params.push_back(":"+InboundDescription);
+ DoOneToAllButSender(TreeRoot->GetName(),"SERVER",params,InboundServerName);
this->DoBurst(Node);
}
else if (command == "ERROR")
{
return this->RemoteServer(prefix,params);
}
+ else if (command == "SQUIT")
+ {
+ if (params.size() == 2)
+ {
+ this->Squit(FindServer(params[0]),params[1]);
+ }
+ return true;
+ }
else
{
// not a special inter-server command.
return true;
}
}
- return DoOneToAllButSender(prefix,command,params,sourceserv);
+ return DoOneToAllButSenderRaw(line,sourceserv);
}
return true;
{
if (this->LinkState == CONNECTING)
{
- Srv->SendOpers("*** CONNECT: Connection to "+myhost+" timed out.");
+ Srv->SendOpers("*** CONNECT: Connection to \002"+myhost+"\002 timed out.");
}
}
virtual void OnClose()
{
+ // Connection closed.
+ // If the connection is fully up (state CONNECTED)
+ // then propogate a netsplit to all peers.
+ std::string quitserver = this->myhost;
+ if (this->InboundServerName != "")
+ {
+ quitserver = this->InboundServerName;
+ }
+ TreeServer* s = FindServer(quitserver);
+ if (s)
+ {
+ std::deque<std::string> params;
+ params.push_back(quitserver);
+ params.push_back(":Remote host closed the connection");
+ DoOneToAllButSender(Srv->GetServerName(),"SQUIT",params,quitserver);
+ Squit(s,"Remote host closed the connection");
+ }
}
virtual int OnIncomingConnection(int newsock, char* ip)
}
};
+bool DoOneToAllButSenderRaw(std::string data,std::string omit)
+{
+ for (unsigned int x = 0; x < TreeRoot->ChildCount(); x++)
+ {
+ TreeServer* Route = TreeRoot->GetChild(x);
+ if ((Route->GetSocket()) && (Route->GetName() != omit) && (BestRouteTo(omit) != Route))
+ {
+ TreeSocket* Sock = Route->GetSocket();
+ log(DEBUG,"Sending RAW to %s",Route->GetName().c_str());
+ Sock->WriteLine(data);
+ }
+ }
+ return true;
+}
+
bool DoOneToAllButSender(std::string prefix, std::string command, std::deque<std::string> params, std::string omit)
{
log(DEBUG,"ALLBUTONE: Comes from %s SHOULD NOT go back to %s",prefix.c_str(),omit.c_str());
char matrix[128][80];
for (unsigned int t = 0; t < 128; t++)
{
- matrix[line][0] = '\0';
+ matrix[t][0] = '\0';
}
line = 0;
// The only recursive bit is called here.
return 0;
}
+ virtual void OnUserNotice(userrec* user, void* dest, int target_type, std::string text)
+ {
+ if (target_type == TYPE_USER)
+ {
+ userrec* d = (userrec*)dest;
+ if ((std::string(d->server) != Srv->GetServerName()) && (std::string(user->server) == Srv->GetServerName()))
+ {
+ std::deque<std::string> params;
+ params.clear();
+ params.push_back(d->nick);
+ params.push_back(":"+text);
+ DoOneToOne(user->nick,"NOTICE",params,d->server);
+ }
+ }
+ else
+ {
+ if (std::string(user->server) == Srv->GetServerName())
+ {
+ chanrec *c = (chanrec*)dest;
+ std::deque<std::string> params;
+ params.push_back(c->name);
+ params.push_back(":"+text);
+ DoOneToMany(user->nick,"NOTICE",params);
+ }
+ }
+ }
+
virtual void OnUserMessage(userrec* user, void* dest, int target_type, std::string text)
{
if (target_type == TYPE_USER)
DoOneToOne(user->nick,"PRIVMSG",params,d->server);
}
}
+ else
+ {
+ if (std::string(user->server) == Srv->GetServerName())
+ {
+ chanrec *c = (chanrec*)dest;
+ std::deque<std::string> params;
+ params.push_back(c->name);
+ params.push_back(":"+text);
+ DoOneToMany(user->nick,"PRIVMSG",params);
+ }
+ }
}
virtual void OnUserJoin(userrec* user, chanrec* channel)