Beispiel #1
0
ModResult ModuleSpanningTree::HandleSquit(const std::vector<std::string>& parameters, User* user)
{
	TreeServer* s = Utils->FindServerMask(parameters[0]);
	if (s)
	{
		if (s->IsRoot())
		{
			user->WriteNotice("*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (" + parameters[0] + " matches local server name)");
			return MOD_RES_DENY;
		}

		TreeSocket* sock = s->GetSocket();

		if (s->IsLocal())
		{
			ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0].c_str(),user->nick.c_str());
			sock->Squit(s,"Server quit by " + user->GetFullRealHost());
			ServerInstance->SE->DelFd(sock);
			sock->Close();
		}
		else
		{
			user->WriteNotice("*** SQUIT may not be used to remove remote servers. Please use RSQUIT instead.");
		}
	}
	else
	{
		 user->WriteNotice("*** SQUIT: The server \002" + parameters[0] + "\002 does not exist on the network.");
	}
	return MOD_RES_DENY;
}
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
	 */
	long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);

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

		// Skip myself
		if (s->IsRoot())
			continue;

		// Do not ping servers that are not fully connected yet!
		// Servers which are connected to us have IsLocal() == true and if they're fully connected
		// then Socket->LinkState == CONNECTED. Servers that are linked to another server are always fully connected.
		if (s->IsLocal() && s->GetSocket()->GetLinkState() != CONNECTED)
			continue;

		// Now do PING checks on all servers
		// 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);
				s->GetSocket()->WriteLine(CmdBuilder("PING").push(s->GetID()));
				s->LastPingMsec = ts;
			}
			else
			{
				// They didn't answer the last ping, if they are locally connected, get rid of them.
				if (s->IsLocal())
				{
					TreeSocket* sock = s->GetSocket();
					sock->SendError("Ping timeout");
					sock->Close();
					goto restart;
				}
			}
		}

		// 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;
		}
	}
}
Beispiel #3
0
void ModuleSpanningTree::OnUnloadModule(Module* mod)
{
	if (!Utils)
		return;
	ServerInstance->PI->SendMetaData("modules", "-" + mod->ModuleSourceFile);

	if (mod == this)
	{
		// We are being unloaded, inform modules about all servers splitting which cannot be done later when the servers are actually disconnected
		const server_hash& servers = Utils->serverlist;
		for (server_hash::const_iterator i = servers.begin(); i != servers.end(); ++i)
		{
			TreeServer* server = i->second;
			if (!server->IsRoot())
				FOREACH_MOD_CUSTOM(GetEventProvider(), ServerEventListener, OnServerSplit, (server));
		}
		return;
	}

	// Some other module is being unloaded. If it provides an IOHook we use, we must close that server connection now.

restart:
	// Close all connections which use an IO hook provided by this module
	const TreeServer::ChildServers& list = Utils->TreeRoot->GetChildren();
	for (TreeServer::ChildServers::const_iterator i = list.begin(); i != list.end(); ++i)
	{
		TreeSocket* sock = (*i)->GetSocket();
		if (sock->GetModHook(mod))
		{
			sock->SendError("SSL module unloaded");
			sock->Close();
			// XXX: The list we're iterating is modified by TreeServer::SQuit() which is called by Close()
			goto restart;
		}
	}

	for (SpanningTreeUtilities::TimeoutList::const_iterator i = Utils->timeoutlist.begin(); i != Utils->timeoutlist.end(); ++i)
	{
		TreeSocket* sock = i->first;
		if (sock->GetModHook(mod))
			sock->Close();
	}
}
Beispiel #4
0
// Ok, prepare to be confused.
// After much mulling over how to approach this, it struck me that
// the 'usual' way of doing a /MAP isnt the best way. Instead of
// keeping track of a ton of ascii characters, and line by line
// under recursion working out where to place them using multiplications
// and divisons, we instead render the map onto a backplane of characters
// (a character matrix), then draw the branches as a series of "L" shapes
// from the nodes. This is not only friendlier on CPU it uses less stack.
CmdResult CommandMap::Handle(const std::vector<std::string>& parameters, User* user)
{
	if (parameters.size() > 0)
	{
		/* Remote MAP, the server is within the 1st parameter */
		TreeServer* s = Utils->FindServerMask(parameters[0]);
		if (!s)
		{
			user->WriteNumeric(ERR_NOSUCHSERVER, "%s :No such server", parameters[0].c_str());
			return CMD_FAILURE;
		}

		if (!s->IsRoot())
			return CMD_SUCCESS;
	}

	// These arrays represent a virtual screen which we will
	// "scratch" draw to, as the console device of an irc
	// client does not provide for a proper terminal.
	int totusers = ServerInstance->Users->clientlist->size();
	int totservers = Utils->serverlist.size();
	int maxnamew = 0;
	int line = 0;
	char* names = new char[totservers * 100];
	char* stats = new char[totservers * 50];

	// The only recursive bit is called here.
	ShowMap(Utils->TreeRoot,user,0,line,names,maxnamew,stats);

	// Process each line one by one.
	for (int l = 1; l < line; l++)
	{
		char* myname = names + 100 * l;
		// scan across the line looking for the start of the
		// servername (the recursive part of the algorithm has placed
		// the servers at indented positions depending on what they
		// are related to)
		int first_nonspace = 0;

		while (myname[first_nonspace] == ' ')
		{
			first_nonspace++;
		}

		first_nonspace--;

		// Draw the `- (corner) section: this may be overwritten by
		// another L shape passing along the same vertical pane, becoming
		// a |- (branch) section instead.

		myname[first_nonspace] = '-';
		myname[first_nonspace-1] = '`';
		int l2 = l - 1;

		// Draw upwards until we hit the parent server, causing possibly
		// other corners (`-) to become branches (|-)
		while ((names[l2 * 100 + first_nonspace-1] == ' ') || (names[l2 * 100 + first_nonspace-1] == '`'))
		{
			names[l2 * 100 + first_nonspace-1] = '|';
			l2--;
		}
	}

	float avg_users = totusers * 1.0 / line;

	for (int t = 0; t < line; t++)
	{
		// terminate the string at maxnamew characters
		names[100 * t + maxnamew] = '\0';
		user->SendText(":%s %03d %s :%s %s", ServerInstance->Config->ServerName.c_str(),
			RPL_MAP, user->nick.c_str(), names + 100 * t, stats + 50 * t);
	}
	user->SendText(":%s %03d %s :%d server%s and %d user%s, average %.2f users per server",
		ServerInstance->Config->ServerName.c_str(), RPL_MAPUSERS, user->nick.c_str(),
		line, (line > 1 ? "s" : ""), totusers, (totusers > 1 ? "s" : ""), avg_users);
	user->SendText(":%s %03d %s :End of /MAP", ServerInstance->Config->ServerName.c_str(),
		RPL_ENDMAP, user->nick.c_str());

	delete[] names;
	delete[] stats;

	return CMD_SUCCESS;
}