/* +------------------------------------+
* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
* InspIRCd: (C) 2002-2011 InspIRCd Development Team
* See: http://wiki.inspircd.org/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "inspircd.h"
#include "socket.h"
#include "xline.h"
#include "main.h"
#include "../spanningtree.h"
#include "utils.h"
#include "treeserver.h"
/** We use this constructor only to create the 'root' item, Utils->TreeRoot, which
* represents our own server. Therefore, it has no route, no parent, and
* no socket associated with it. Its version string is our own local version.
*/
TreeServer::TreeServer(SpanningTreeUtilities* Util)
: Parent(NULL), Socket(NULL), ServerUser(ServerInstance->FakeClient), Utils(Util),
ServerDesc(ServerInstance->Config->ServerDesc), VersionString(ServerInstance->GetVersionString()),
age(ServerInstance->Time()), NextPing(0), LastPingMsec(0), rtt(0),
StartBurst(age), LastPingWasGood(true), Warned(false), bursting(false), Hidden(false)
{
AddHashEntry();
}
/** When we create a new server, we call this constructor to initialize it.
* This constructor initializes the server's Route and Parent, and sets up
* its ping counters so that it will be pinged one minute from now.
*/
TreeServer::TreeServer(SpanningTreeUtilities* Util, const std::string& Name, const std::string& Desc, const std::string &id,
TreeServer* Above, TreeSocket* Sock, bool Hide)
: Parent(Above), Socket(Sock), ServerUser(new FakeUser(id, Name)), Utils(Util), ServerDesc(Desc),
UserCount(0), age(ServerInstance->Time()), NextPing(age + Util->PingFreq), LastPingMsec(0), rtt(0),
StartBurst(age * 1000 + (ServerInstance->Time_ns() / 1000000)),
LastPingWasGood(true), Warned(false), bursting(true), Hidden(Hide)
{
ServerInstance->Logs->Log("m_spanningtree",DEBUG, "Started bursting at time %lu", StartBurst);
AddHashEntry();
}
void TreeServer::FinishBurstInternal()
{
this->bursting = false;
SetNextPingTime(ServerInstance->Time() + Utils->PingFreq);
SetPingFlag();
for(unsigned int q=0; q < ChildCount(); q++)
{
TreeServer* child = GetChild(q);
child->FinishBurstInternal();
}
}
void TreeServer::FinishBurst()
{
FinishBurstInternal();
ServerInstance->XLines->ApplyLines();
long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);
unsigned long bursttime = ts - this->StartBurst;
ServerInstance->SNO->WriteToSnoMask(Parent == Utils->TreeRoot ? 'l' : 'L', "Received end of netburst from \2%s\2 (burst time: %lu %s)",
GetName().c_str(), (bursttime > 10000 ? bursttime / 1000 : bursttime), (bursttime > 10000 ? "secs" : "msecs"));
AddServerEvent(Utils->Creator, GetName());
}
int TreeServer::QuitUsers(const std::string &reason)
{
const char* reason_s = reason.c_str();
std::vector<User*> time_to_die;
for (user_hash::iterator n = ServerInstance->Users->clientlist->begin(); n != ServerInstance->Users->clientlist->end(); n++)
{
if (n->second->server == GetName())
{
time_to_die.push_back(n->second);
}
}
for (std::vector<User*>::iterator n = time_to_die.begin(); n != time_to_die.end(); n++)
{
User* a = (User*)*n;
if (!IS_LOCAL(a))
{
if (this->Utils->quiet_bursts)
a->quietquit = true;
if (ServerInstance->Config->HideSplits)
ServerInstance->Users->QuitUser(a, "*.net *.split", reason_s);
else
ServerInstance->Users->QuitUser(a, reason_s);
}
}
return time_to_die.size();
}
/** This method is used to add the structure to the
* hash_map for linear searches. It is only called
* by the constructors.
*/
void TreeServer::AddHashEntry()
{
ServerInstance->Logs->Log("m_spanningtree",DEBUG, "Setting SID for " + ServerUser->server + " to " + ServerUser->uuid);
Utils->serverlist[ServerUser->server] = this;
Utils->sidlist[ServerUser->uuid] = this;
}
/** This method removes the reference to this object
* from the hash_map which is used for linear searches.
* It is only called by the default destructor.
*/
void TreeServer::DelHashEntry()
{
server_hash::iterator iter = Utils->serverlist.find(GetName());
if (iter != Utils->serverlist.end())
Utils->serverlist.erase(iter);
}
void TreeServer::SetNextPingTime(time_t t)
{
this->NextPing = t;
LastPingWasGood = false;
}
time_t TreeServer::NextPingTime()
{
return NextPing;
}
bool TreeServer::AnsweredLastPing()
{
return LastPingWasGood;
}
void TreeServer::SetPingFlag()
{
LastPingWasGood = true;
}
unsigned int TreeServer::ChildCount()
{
return Children.size();
}
TreeServer* TreeServer::GetChild(unsigned int n)
{
if (n < Children.size())
{
/* Make sure they cant request
* an out-of-range object. After
* all we know what these programmer
* types are like *grin*.
*/
return Children[n];
}
else
{
return NULL;
}
}
void TreeServer::AddChild(TreeServer* Child)
{
Children.push_back(Child);
}
bool TreeServer::DelChild(TreeServer* Child)
{
for (std::vector<TreeServer*>::iterator a = Children.begin(); a != Children.end(); a++)
{
if (*a == Child)
{
Children.erase(a);
return true;
}
}
return false;
}
/** Removes child nodes of this node, and of that node, etc etc.
* This is used during netsplits to automatically tidy up the
* server tree. It is slow, we don't use it for much else.
*/
bool TreeServer::Tidy()
{
while (1)
{
std::vector<TreeServer*>::iterator a = Children.begin();
if (a == Children.end())
return true;
TreeServer* s = *a;
s->Tidy();
s->cull();
Children.erase(a);
delete s;
}
}
CullResult TreeServer::cull()
{
if (ServerUser != ServerInstance->FakeClient)
ServerUser->cull();
return classbase::cull();
}
TreeServer::~TreeServer()
{
/* We'd better tidy up after ourselves, eh? */
this->DelHashEntry();
server_hash::iterator iter = Utils->sidlist.find(GetID());
if (iter != Utils->sidlist.end())
Utils->sidlist.erase(iter);
if (ServerUser != ServerInstance->FakeClient)
delete ServerUser;
}