예제 #1
0
void ModuleSpanningTree::ProtoSendMetaData(void* opaque, Extensible* target, const std::string &extname, const std::string &extdata)
{
	TreeSocket* s = static_cast<TreeSocket*>(opaque);
	User* u = dynamic_cast<User*>(target);
	Channel* c = dynamic_cast<Channel*>(target);
	if (u)
		s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+u->uuid+" "+extname+" :"+extdata);
	else if (c)
		s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+c->name+" "+ConvToStr(c->age)+" "+extname+" :"+extdata);
	else if (!target)
		s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA * "+extname+" :"+extdata);
}
예제 #2
0
void SpanningTreeUtilities::DoOneToOne(const CmdBuilder& params, Server* server)
{
	TreeServer* ts = static_cast<TreeServer*>(server);
	TreeSocket* sock = ts->GetSocket();
	if (sock)
		sock->WriteLine(params);
}
예제 #3
0
void ModuleSpanningTree::ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline)
{
	TreeSocket* s = (TreeSocket*)opaque;
	if (target)
	{
		if (target_type == TYPE_USER)
		{
			userrec* u = (userrec*)target;
			s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+u->nick+" "+ConvToStr(u->age)+" "+modeline);
		}
		else
		{
			chanrec* c = (chanrec*)target;
			s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+modeline);
		}
	}
}
예제 #4
0
void ModuleSpanningTree::ProtoSendMode(void* opaque, TargetTypeFlags target_type, void* target, const parameterlist &modeline, const std::vector<TranslateType> &translate)
{
	TreeSocket* s = (TreeSocket*)opaque;
	std::string output_text = CommandParser::TranslateUIDs(translate, modeline);

	if (target)
	{
		if (target_type == TYPE_USER)
		{
			User* u = (User*)target;
			s->WriteLine(":"+ServerInstance->Config->GetSID()+" MODE "+u->uuid+" "+output_text);
		}
		else if (target_type == TYPE_CHANNEL)
		{
			Channel* c = (Channel*)target;
			s->WriteLine(":"+ServerInstance->Config->GetSID()+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+output_text);
		}
	}
}
예제 #5
0
void ModuleSpanningTree::ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata)
{
	TreeSocket* s = (TreeSocket*)opaque;
	if (target)
	{
		if (target_type == TYPE_USER)
		{
			userrec* u = (userrec*)target;
			s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+u->nick+" "+extname+" :"+extdata);
		}
		else if (target_type == TYPE_CHANNEL)
		{
			chanrec* c = (chanrec*)target;
			s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+c->name+" "+extname+" :"+extdata);
		}
	}
	if (target_type == TYPE_OTHER)
	{
		s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA * "+extname+" :"+extdata);
	}
}
예제 #6
0
void ModuleSpanningTree::ProtoSendMetaData(void* opaque, TargetTypeFlags target_type, void* target, const std::string &extname, const std::string &extdata)
{
	TreeSocket* s = (TreeSocket*)opaque;
	if (target)
	{
		if (target_type == TYPE_USER)
		{
			User* u = (User*)target;
			s->WriteLine(std::string(":")+ServerInstance->Config->GetSID()+" METADATA "+u->uuid+" "+extname+" :"+extdata);
		}
		else if (target_type == TYPE_CHANNEL)
		{
			Channel* c = (Channel*)target;
			s->WriteLine(std::string(":")+ServerInstance->Config->GetSID()+" METADATA "+c->name+" "+extname+" :"+extdata);
		}
	}
	if (target_type == TYPE_OTHER)
	{
		s->WriteLine(std::string(":")+ServerInstance->Config->GetSID()+" METADATA * "+extname+" :"+extdata);
	}
}
예제 #7
0
void ModuleSpanningTree::OnUserMessage(User* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
{
	/* Server origin */
	if (user == NULL)
		return;

	if (target_type == TYPE_USER)
	{
		// route private messages which are targetted at clients only to the server
		// which needs to receive them
		User* d = (User*)dest;
		if ((d->GetFd() < 0) && (IS_LOCAL(user)))
		{
			std::deque<std::string> params;
			params.clear();
			params.push_back(d->uuid);
			params.push_back(":"+text);
			Utils->DoOneToOne(user->uuid,"PRIVMSG",params,d->server);
		}
	}
	else if (target_type == TYPE_CHANNEL)
	{
		if (IS_LOCAL(user))
		{
			Channel *c = (Channel*)dest;
			if (c)
			{
				std::string cname = c->name;
				if (status)
					cname = status + cname;
				TreeServerList list;
				Utils->GetListOfServersForChannel(c,list,status,exempt_list);
				for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
				{
					TreeSocket* Sock = i->second->GetSocket();
					if (Sock)
						Sock->WriteLine(":"+std::string(user->uuid)+" PRIVMSG "+cname+" :"+text);
				}
			}
		}
	}
	else if (target_type == TYPE_SERVER)
	{
		if (IS_LOCAL(user))
		{
			char* target = (char*)dest;
			std::deque<std::string> par;
			par.push_back(target);
			par.push_back(":"+text);
			Utils->DoOneToMany(user->uuid,"PRIVMSG",par);
		}
	}
}
예제 #8
0
void SpanningTreeUtilities::SendChannelMessage(const std::string& prefix, Channel* target, const std::string& text, char status, const CUList& exempt_list, const char* message_type, TreeSocket* omit)
{
	CmdBuilder msg(prefix, message_type);
	if (status == 0)
		status = ' ';
	msg.push(status).push_raw(target->name).push_last(text);

	TreeSocketSet list;
	this->GetListOfServersForChannel(target, list, status, exempt_list);
	for (TreeSocketSet::iterator i = list.begin(); i != list.end(); ++i)
	{
		TreeSocket* Sock = *i;
		if (Sock != omit)
			Sock->WriteLine(msg);
	}
}
예제 #9
0
void ModuleSpanningTree::OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
{
	if (target_type == TYPE_USER)
	{
		userrec* d = (userrec*)dest;
		if ((d->GetFd() < 0) && (IS_LOCAL(user)))
		{
			std::deque<std::string> params;
			params.clear();
			params.push_back(d->nick);
			params.push_back(":"+text);
			Utils->DoOneToOne(user->nick,"NOTICE",params,d->server);
		}
	}
	else if (target_type == TYPE_CHANNEL)
	{
		if (IS_LOCAL(user))
		{
			chanrec *c = (chanrec*)dest;
			if (c)
			{
				std::string cname = c->name;
				if (status)
					cname = status + cname;
				TreeServerList list;
				Utils->GetListOfServersForChannel(c,list,status,exempt_list);
				for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
				{
					TreeSocket* Sock = i->second->GetSocket();
					if (Sock)
						Sock->WriteLine(":"+std::string(user->nick)+" NOTICE "+cname+" :"+text);
				}
			}
		}
	}
	else if (target_type == TYPE_SERVER)
	{
		if (IS_LOCAL(user))
		{
			char* target = (char*)dest;
			std::deque<std::string> par;
			par.push_back(target);
			par.push_back(":"+text);
			Utils->DoOneToMany(user->nick,"NOTICE",par);
		}
	}
}
예제 #10
0
파일: utils.cpp 프로젝트: krsnapc/inspircd
void SpanningTreeUtilities::SendChannelMessage(const std::string& prefix, Channel* target, const std::string& text, char status, const CUList& exempt_list, const char* message_type, TreeSocket* omit)
{
	std::string raw(":");
	raw.append(prefix).append(1, ' ').append(message_type).push_back(' ');
	if (status)
		raw.push_back(status);
	raw.append(target->name).append(" :").append(text);

	TreeSocketSet list;
	this->GetListOfServersForChannel(target, list, status, exempt_list);
	for (TreeSocketSet::iterator i = list.begin(); i != list.end(); ++i)
	{
		TreeSocket* Sock = *i;
		if (Sock != omit)
			Sock->WriteLine(raw);
	}
}
예제 #11
0
파일: utils.cpp 프로젝트: bandicot/inspircd
bool SpanningTreeUtilities::DoOneToMany(const std::string &prefix, const std::string &command, const parameterlist &params)
{
	std::string FullLine = ConstructLine(prefix, command, params);

	unsigned int items = this->TreeRoot->ChildCount();
	for (unsigned int x = 0; x < items; x++)
	{
		TreeServer* Route = this->TreeRoot->GetChild(x);
		if (Route && Route->GetSocket())
		{
			TreeSocket* Sock = Route->GetSocket();
			if (Sock)
				Sock->WriteLine(FullLine);
		}
	}
	return true;
}
예제 #12
0
파일: utils.cpp 프로젝트: bandicot/inspircd
bool SpanningTreeUtilities::DoOneToOne(const std::string& prefix, const std::string& command, const parameterlist& params, const std::string& target)
{
	TreeServer* Route = this->BestRouteTo(target);
	if (Route)
	{
		if (Route && Route->GetSocket())
		{
			TreeSocket* Sock = Route->GetSocket();
			if (Sock)
				Sock->WriteLine(ConstructLine(prefix, command, params));
		}
		return true;
	}
	else
	{
		return false;
	}
}
예제 #13
0
void ModuleSpanningTree::DoPingChecks(time_t curtime)
{
	for (unsigned int j = 0; j < Utils->TreeRoot->ChildCount(); j++)
	{
		TreeServer* serv = Utils->TreeRoot->GetChild(j);
		TreeSocket* sock = serv->GetSocket();
		if (sock)
		{
			if (curtime >= serv->NextPingTime())
			{
				if (serv->AnsweredLastPing())
				{
					sock->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" PING "+serv->GetName());
					serv->SetNextPingTime(curtime + 60);
					serv->LastPing = curtime;
					serv->Warned = false;
				}
				else
				{
					/* they didnt answer, boot them */
					sock->SendError("Ping timeout");
					sock->Squit(serv,"Ping timeout");
					ServerInstance->SE->DelFd(sock);
					sock->Close();
					return;
				}
			}
			else if ((Utils->PingWarnTime) && (!serv->Warned) && (curtime >= serv->NextPingTime() - (60 - Utils->PingWarnTime)) && (!serv->AnsweredLastPing()))
			{
				/* The server hasnt responded, send a warning to opers */
				ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", serv->GetName().c_str(), Utils->PingWarnTime);
				serv->Warned = true;
			}
		}
	}

	/* Cancel remote burst mode on any servers which still have it enabled due to latency/lack of data.
	 * This prevents lost REMOTECONNECT notices
	 */
	for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++)
		Utils->SetRemoteBursting(i->second, false);
}
예제 #14
0
파일: utils.cpp 프로젝트: bandicot/inspircd
bool SpanningTreeUtilities::DoOneToAllButSender(const std::string& prefix, const std::string& command, const parameterlist& params, const std::string& omit)
{
	TreeServer* omitroute = this->BestRouteTo(omit);
	std::string FullLine = ConstructLine(prefix, command, params);

	unsigned int items = this->TreeRoot->ChildCount();
	for (unsigned int x = 0; x < items; x++)
	{
		TreeServer* Route = this->TreeRoot->GetChild(x);
		// Send the line IF:
		// The route has a socket (its a direct connection)
		// The route isnt the one to be omitted
		// The route isnt the path to the one to be omitted
		if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route))
		{
			TreeSocket* Sock = Route->GetSocket();
			if (Sock)
				Sock->WriteLine(FullLine);
		}
	}
	return true;
}
예제 #15
0
void ModuleSpanningTree::DoPingChecks(time_t curtime)
{
	/*
	 * Cancel remote burst mode on any servers which still have it enabled due to latency/lack of data.
	 * This prevents lost REMOTECONNECT notices
	 */
	timeval t;
	gettimeofday(&t, NULL);
	long ts = (t.tv_sec * 1000) + (t.tv_usec / 1000);

	for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++)
	{
		TreeServer *s = i->second;

		// Fix for bug #792, do not ping servers that are not connected yet!
		// Remote servers have Socket == NULL and local connected servers have
		// Socket->LinkState == CONNECTED
		if (s->GetSocket() && s->GetSocket()->GetLinkState() != CONNECTED)
			continue;

		// Now do PING checks on all servers
		TreeServer *mts = Utils->BestRouteTo(s->GetID());

		if (mts)
		{
			// Only ping if this server needs one
			if (curtime >= s->NextPingTime())
			{
				// And if they answered the last
				if (s->AnsweredLastPing())
				{
					// They did, send a ping to them
					s->SetNextPingTime(curtime + Utils->PingFreq);
					TreeSocket *tsock = mts->GetSocket();

					// ... if we can find a proper route to them
					if (tsock)
					{
						tsock->WriteLine(std::string(":") + ServerInstance->Config->GetSID() + " PING " +
								ServerInstance->Config->GetSID() + " " + s->GetID());
						s->LastPingMsec = ts;
					}
				}
				else
				{
					// They didn't answer the last ping, if they are locally connected, get rid of them.
					TreeSocket *sock = s->GetSocket();
					if (sock)
					{
						sock->SendError("Ping timeout");
						sock->Squit(s,"Ping timeout");
						ServerInstance->SE->DelFd(sock);
						sock->Close();
						return;
					}
				}
			}

			// If warn on ping enabled and not warned and the difference is sufficient and they didn't answer the last ping...
			if ((Utils->PingWarnTime) && (!s->Warned) && (curtime >= s->NextPingTime() - (Utils->PingFreq - Utils->PingWarnTime)) && (!s->AnsweredLastPing()))
			{
				/* The server hasnt responded, send a warning to opers */
				ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", s->GetName().c_str(), Utils->PingWarnTime);
				s->Warned = true;
			}
		}
	}
}
예제 #16
0
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, Command* thiscmd, const parameterlist& parameters, User* user)
{
	const std::string& command = thiscmd->name;
	RouteDescriptor routing = thiscmd->GetRouting(user, parameters);

	std::string sent_cmd = command;
	parameterlist params;

	if (routing.type == ROUTE_TYPE_LOCALONLY)
	{
		return;
	}
	else if (routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		params.push_back("*");
		params.push_back(command);
		sent_cmd = "ENCAP";
	}
	else if (routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		TreeServer* sdest = FindServer(routing.serverdest);
		if (!sdest)
		{
			ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Trying to route ENCAP to nonexistant server %s",
				routing.serverdest.c_str());
			return;
		}
		params.push_back(sdest->GetID());
		params.push_back(command);
		sent_cmd = "ENCAP";
	}
	else
	{
		Module* srcmodule = thiscmd->creator;
		Version ver = srcmodule->GetVersion();

		if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator)
		{
			ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s",
				command.c_str(), srcmodule->ModuleSourceFile.c_str());
			return;
		}
	}

	std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd);

	params.push_back(output_text);

	if (routing.type == ROUTE_TYPE_MESSAGE)
	{
		char pfx = 0;
		std::string dest = routing.serverdest;
		if (ServerInstance->Modes->FindPrefix(dest[0]))
		{
			pfx = dest[0];
			dest = dest.substr(1);
		}
		if (dest[0] == '#')
		{
			Channel* c = ServerInstance->FindChan(dest);
			if (!c)
				return;
			TreeServerList list;
			// TODO OnBuildExemptList hook was here
			GetListOfServersForChannel(c,list,pfx, CUList());
			std::string data = ":" + user->uuid + " " + sent_cmd;
			for (unsigned int x = 0; x < params.size(); x++)
				data += " " + params[x];
			for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
			{
				TreeSocket* Sock = (*i)->GetSocket();
				if (origin && origin->GetSocket() == Sock)
					continue;
				if (Sock)
					Sock->WriteLine(data);
			}
		}
		else if (dest[0] == '$')
		{
			if (origin)
				DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName());
			else
				DoOneToMany(user->uuid, sent_cmd, params);
		}
		else
		{
			// user target?
			User* d = ServerInstance->FindNick(dest);
			if (!d)
				return;
			TreeServer* tsd = BestRouteTo(d->server);
			if (tsd == origin)
				// huh? no routing stuff around in a circle, please.
				return;
			DoOneToOne(user->uuid, sent_cmd, params, d->server);
		}
	}
	else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST)
	{
		if (origin)
			DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName());
		else
			DoOneToMany(user->uuid, sent_cmd, params);
	}
	else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST)
	{
		if (origin && routing.serverdest == origin->GetName())
			return;
		DoOneToOne(user->uuid, sent_cmd, params, routing.serverdest);
	}
}
예제 #17
0
/*
 * Yes, this function looks a little ugly.
 * However, in some circumstances we may not have a User, so we need to do things this way.
 * Returns 1 if colliding local client, 2 if colliding remote, 3 if colliding both.
 * Sends SAVEs as appropriate and forces nickchanges too.
 */
int SpanningTreeUtilities::DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid)
{
	/*
	 * Under old protocol rules, we would have had to kill both clients.
	 * Really, this sucks.
	 * These days, we have UID. And, so what we do is, force nick change client(s)
	 * involved according to timestamp rules.
	 *
	 * RULES:
	 *  user@ip equal:
	 *   Force nick change on OLDER timestamped client
	 *  user@ip differ:
	 *   Force nick change on NEWER timestamped client
	 *  TS EQUAL:
	 *   FNC both.
	 *
	 * This stops abusive use of collisions, simplifies problems with loops, and so on.
	 *   -- w00t
	 */
	bool bChangeLocal = true;
	bool bChangeRemote = true;

	/* for brevity, don't use the User - use defines to avoid any copy */
	#define localts u->age
	#define localident u->ident
	#define localip u->GetIPString()

	/* mmk. let's do this again. */
	if (remotets == localts)
	{
		/* equal. f**k them both! do nada, let the handler at the bottom figure this out. */
	}
	else
	{
		/* f**k. now it gets complex. */

		/* first, let's see if ident@host matches. */
		bool SamePerson = (localident == remoteident)
				&& (localip == remoteip);

		/*
		 * if ident@ip is equal, and theirs is newer, or
		 * ident@ip differ, and ours is newer
		 */
		if((SamePerson && remotets < localts) ||
		   (!SamePerson && remotets > localts))
		{
			/* remote needs to change */
			bChangeLocal = false;
		}
		else
		{
			/* ours needs to change */
			bChangeRemote = false;
		}
	}

	/*
	 * Cheat a little here. Instead of a dedicated command to change UID,
	 * use SAVE and accept the losing client with its UID (as we know the SAVE will
	 * not fail under any circumstances -- UIDs are netwide exclusive).
	 *
	 * This means that each side of a collide will generate one extra NICK back to where
	 * they have just linked (and where it got the SAVE from), however, it will
	 * be dropped harmlessly as it will come in as :928AAAB NICK 928AAAB, and we already
	 * have 928AAAB's nick set to that.
	 *   -- w00t
	 */

	if (bChangeLocal)
	{
		/*
		 * Local-side nick needs to change. Just in case we are hub, and
		 * this "local" nick is actually behind us, send an SAVE out.
		 */
		CmdBuilder params("SAVE");
		params.push_back(u->uuid);
		params.push_back(ConvToStr(u->age));
		params.Broadcast();

		u->ForceNickChange(u->uuid);

		if (!bChangeRemote)
			return 1;
	}
	if (bChangeRemote)
	{
		User *remote = ServerInstance->FindUUID(remoteuid);
		/*
		 * remote side needs to change. If this happens, we will modify
		 * the UID or halt the propagation of the nick change command,
		 * so other servers don't need to see the SAVE
		 */
		TreeSocket* sock = server->GetSocket();
		sock->WriteLine(":"+ServerInstance->Config->GetSID()+" SAVE "+remoteuid+" "+ ConvToStr(remotets));

		if (remote)
		{
			/* nick change collide. Force change their nick. */
			remote->ForceNickChange(remoteuid);
		}

		if (!bChangeLocal)
			return 2;
	}

	return 3;
}