bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid) { // Check if the server name is not in use by a server that's already fully connected TreeServer* CheckDupe = Utils->FindServer(sname); if (CheckDupe) { std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : "<ourself>"; SendError("Server "+sname+" already exists on server "+pname+"!"); ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname); return false; } // Check if the id is not in use by a server that's already fully connected ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Looking for dupe SID %s", sid.c_str()); CheckDupe = Utils->FindServerID(sid); if (CheckDupe) { this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with <server:id> so they do not conflict."); ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+ "' already exists on server "+CheckDupe->GetName()); return false; } return true; }
bool SpanningTreeProtocolInterface::SendEncapsulatedData(const std::string& targetmask, const std::string& cmd, const parameterlist& params, User* source) { if (!source) source = ServerInstance->FakeClient; CmdBuilder encap(source, "ENCAP"); // Are there any wildcards in the target string? if (targetmask.find_first_of("*?") != std::string::npos) { // Yes, send the target string as-is; servers will decide whether or not it matches them encap.push(targetmask).push(cmd).insert(params).Broadcast(); } else { // No wildcards which means the target string has to be the name of a known server TreeServer* server = Utils->FindServer(targetmask); if (!server) return false; // Use the SID of the target in the message instead of the server name encap.push(server->GetID()).push(cmd).insert(params).Unicast(server->ServerUser); } return true; }
bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid) { /* Check for fully initialized instances of the server by name */ TreeServer* CheckDupe = Utils->FindServer(sname); if (CheckDupe) { std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : "<ourself>"; SendError("Server "+sname+" already exists on server "+pname+"!"); ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname); return false; } /* Check for fully initialized instances of the server by id */ ServerInstance->Logs->Log("m_spanningtree",DEBUG,"Looking for dupe SID %s", sid.c_str()); CheckDupe = Utils->FindServerID(sid); if (CheckDupe) { this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with <server:id> so they do not conflict."); ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+ "' already exists on server "+CheckDupe->GetName()); return false; } return true; }
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; } } }
/** send all users and their oper state/modes */ void TreeSocket::SendUsers() { char data[MAXBUF]; std::string dataline; for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++) { if (u->second->registered == REG_ALL) { TreeServer* theirserver = Utils->FindServer(u->second->server); if (theirserver) { snprintf(data,MAXBUF,":%s UID %s %lu %s %s %s %s %s %lu +%s :%s", theirserver->GetID().c_str(), /* Prefix: SID */ u->second->uuid.c_str(), /* 0: UUID */ (unsigned long)u->second->age, /* 1: TS */ u->second->nick.c_str(), /* 2: Nick */ u->second->host.c_str(), /* 3: Displayed Host */ u->second->dhost.c_str(), /* 4: Real host */ u->second->ident.c_str(), /* 5: Ident */ u->second->GetIPString().c_str(), /* 6: IP string */ (unsigned long)u->second->signon, /* 7: Signon time for WHOWAS */ u->second->FormatModes(true), /* 8...n: Modes and params */ u->second->fullname.c_str()); /* size-1: GECOS */ this->WriteLine(data); if (u->second->IsOper()) { snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->uuid.c_str(), u->second->oper->name.c_str()); this->WriteLine(data); } if (u->second->IsAway()) { snprintf(data,MAXBUF,":%s AWAY %ld :%s", u->second->uuid.c_str(), (long)u->second->awaytime, u->second->awaymsg.c_str()); this->WriteLine(data); } } for(Extensible::ExtensibleStore::const_iterator i = u->second->GetExtList().begin(); i != u->second->GetExtList().end(); i++) { ExtensionItem* item = i->first; std::string value = item->serialize(FORMAT_NETWORK, u->second, i->second); if (!value.empty()) Utils->Creator->ProtoSendMetaData(this, u->second, item->name, value); } FOREACH_MOD(I_OnSyncUser,OnSyncUser(u->second,Utils->Creator,this)); } } }
/** send all users and their oper state/modes */ void TreeSocket::SendUsers(TreeServer* Current) { char data[MAXBUF]; std::deque<std::string> list; std::string dataline; for (user_hash::iterator u = this->ServerInstance->Users->clientlist->begin(); u != this->ServerInstance->Users->clientlist->end(); u++) { if (u->second->registered == REG_ALL) { TreeServer* theirserver = Utils->FindServer(u->second->server); if (theirserver) { snprintf(data,MAXBUF,":%s UID %s %lu %s %s %s %s %s %lu +%s :%s", theirserver->GetID().c_str(), /* Prefix: SID */ u->second->uuid.c_str(), /* 0: UUID */ (unsigned long)u->second->age, /* 1: TS */ u->second->nick.c_str(), /* 2: Nick */ u->second->host.c_str(), /* 3: Displayed Host */ u->second->dhost.c_str(), /* 4: Real host */ u->second->ident.c_str(), /* 5: Ident */ u->second->GetIPString(), /* 6: IP string */ (unsigned long)u->second->signon, /* 7: Signon time for WHOWAS */ u->second->FormatModes(true), /* 8...n: Modes and params */ u->second->fullname.c_str()); /* size-1: GECOS */ this->WriteLine(data); if (IS_OPER(u->second)) { snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->uuid.c_str(), u->second->oper.c_str()); this->WriteLine(data); } if (IS_AWAY(u->second)) { snprintf(data,MAXBUF,":%s AWAY :%s", u->second->uuid.c_str(), u->second->awaymsg.c_str()); this->WriteLine(data); } } FOREACH_MOD_I(this->ServerInstance,I_OnSyncUser,OnSyncUser(u->second,(Module*)Utils->Creator,(void*)this)); list.clear(); u->second->GetExtList(list); for (unsigned int j = 0; j < list.size(); j++) { FOREACH_MOD_I(this->ServerInstance,I_OnSyncUserMetaData,OnSyncUserMetaData(u->second,(Module*)Utils->Creator,(void*)this,list[j])); } } } }
bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params) { if ((cmd == "METADATA") && (params.size() >= 3)) { // :20D METADATA #channel extname :extdata return InsertCurrentChannelTS(params); } else if ((cmd == "FTOPIC") && (params.size() >= 4)) { // :20D FTOPIC #channel 100 Attila :topic text return InsertCurrentChannelTS(params); } else if ((cmd == "PING") || (cmd == "PONG")) { if (params.size() == 1) { // If it's a PING with 1 parameter, reply with a PONG now, if it's a PONG with 1 parameter (weird), do nothing if (cmd[1] == 'I') this->WriteData(":" + ServerInstance->Config->GetSID() + " PONG " + params[0] + newline); // Don't process this message further return false; } // :20D PING 20D 22D // :20D PONG 20D 22D // Drop the first parameter params.erase(params.begin()); // If the target is a server name, translate it to a SID if (!InspIRCd::IsSID(params[0])) { TreeServer* server = Utils->FindServer(params[0]); if (!server) { // We've no idea what this is, log and stop processing ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Received a " + cmd + " with an unknown target: \"" + params[0] + "\", command dropped"); return false; } params[0] = server->GetID(); } } return true; // Passthru }
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const parameterlist& parameters, User* user) { const std::string& command = thiscmd->name; RouteDescriptor routing = thiscmd->GetRouting(user, parameters); if (routing.type == ROUTE_TYPE_LOCALONLY) return; const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST)); CmdBuilder params(user, encap ? "ENCAP" : command.c_str()); if (routing.type == ROUTE_TYPE_OPT_BCAST) { params.push('*'); params.push_back(command); } else if (routing.type == ROUTE_TYPE_OPT_UCAST) { TreeServer* sdest = FindServer(routing.serverdest); if (!sdest) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Trying to route ENCAP to nonexistant server %s", routing.serverdest.c_str()); return; } params.push_back(sdest->GetID()); params.push_back(command); } else { Module* srcmodule = thiscmd->creator; Version ver = srcmodule->GetVersion(); if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator) { ServerInstance->Logs->Log(MODNAME, 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; // TODO OnBuildExemptList hook was here CUList exempts; SendChannelMessage(user->uuid, c, parameters[1], pfx, exempts, command.c_str(), origin ? origin->GetSocket() : NULL); } else if (dest[0] == '$') { params.Forward(origin); } 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; params.Unicast(d); } } else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST) { params.Forward(origin); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { if (origin && routing.serverdest == origin->GetName()) return; params.Unicast(routing.serverdest); } }
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); } }
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const CommandBase::Params& parameters, User* user) { const std::string& command = thiscmd->name; RouteDescriptor routing = thiscmd->GetRouting(user, parameters); if (routing.type == ROUTE_TYPE_LOCALONLY) return; const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST)); CmdBuilder params(user, encap ? "ENCAP" : command.c_str()); params.push_tags(parameters.GetTags()); TreeServer* sdest = NULL; if (routing.type == ROUTE_TYPE_OPT_BCAST) { params.push('*'); params.push_back(command); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { sdest = static_cast<TreeServer*>(routing.server); if (!sdest) { // Assume the command handler already validated routing.serverdest and have only returned success if the target is something that the // user executing the command is allowed to look up e.g. target is not an uuid if user is local. sdest = FindRouteTarget(routing.serverdest); if (!sdest) { ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Trying to route %s%s to nonexistent server %s", (encap ? "ENCAP " : ""), command.c_str(), routing.serverdest.c_str()); return; } } if (encap) { params.push_back(sdest->GetID()); params.push_back(command); } } else { Module* srcmodule = thiscmd->creator; Version ver = srcmodule->GetVersion(); if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator) { ServerInstance->Logs.Log(MODNAME, 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.erase(dest.begin()); } if (dest[0] == '#') { Channel* c = ServerInstance->FindChan(dest); if (!c) return; // TODO OnBuildExemptList hook was here CUList exempts; std::string message; if (parameters.size() >= 2) message.assign(parameters[1]); SendChannelMessage(user->uuid, c, message, pfx, parameters.GetTags(), exempts, command.c_str(), origin ? origin->GetSocket() : NULL); } else if (dest[0] == '$') { params.Forward(origin); } else { // user target? User* d = ServerInstance->FindNick(dest); if (!d || IS_LOCAL(d)) return; TreeServer* tsd = TreeServer::Get(d)->GetRoute(); if (tsd == origin) // huh? no routing stuff around in a circle, please. return; params.Unicast(d); } } else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST) { params.Forward(origin); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { params.Unicast(sdest->ServerUser); } }
bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params) { if ((cmd == "METADATA") && (params.size() >= 3) && (params[0][0] == '#')) { // :20D METADATA #channel extname :extdata return InsertCurrentChannelTS(params); } else if ((cmd == "FTOPIC") && (params.size() >= 4)) { // :20D FTOPIC #channel 100 Attila :topic text return InsertCurrentChannelTS(params); } else if ((cmd == "PING") || (cmd == "PONG")) { if (params.size() == 1) { // If it's a PING with 1 parameter, reply with a PONG now, if it's a PONG with 1 parameter (weird), do nothing if (cmd[1] == 'I') this->WriteData(":" + ServerInstance->Config->GetSID() + " PONG " + params[0] + newline); // Don't process this message further return false; } // :20D PING 20D 22D // :20D PONG 20D 22D // Drop the first parameter params.erase(params.begin()); // If the target is a server name, translate it to a SID if (!InspIRCd::IsSID(params[0])) { TreeServer* server = Utils->FindServer(params[0]); if (!server) { // We've no idea what this is, log and stop processing ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Received a " + cmd + " with an unknown target: \"" + params[0] + "\", command dropped"); return false; } params[0] = server->GetID(); } } else if ((cmd == "GLINE") || (cmd == "KLINE") || (cmd == "ELINE") || (cmd == "ZLINE") || (cmd == "QLINE")) { // Fix undocumented protocol usage: translate GLINE, ZLINE, etc. into ADDLINE or DELLINE if ((params.size() != 1) && (params.size() != 3)) return false; parameterlist p; p.push_back(cmd.substr(0, 1)); p.push_back(params[0]); if (params.size() == 3) { cmd = "ADDLINE"; p.push_back(who->nick); p.push_back(ConvToStr(ServerInstance->Time())); p.push_back(ConvToStr(InspIRCd::Duration(params[1]))); p.push_back(params[2]); } else cmd = "DELLINE"; params.swap(p); } else if (cmd == "SVSMODE") { cmd = "MODE"; } else if (cmd == "OPERQUIT") { // Translate OPERQUIT into METADATA if (params.empty()) return false; cmd = "METADATA"; params.insert(params.begin(), who->uuid); params.insert(params.begin()+1, "operquit"); who = MyRoot->ServerUser; } else if ((cmd == "TOPIC") && (params.size() >= 2)) { // :20DAAAAAC TOPIC #chan :new topic cmd = "FTOPIC"; if (!InsertCurrentChannelTS(params)) return false; params.insert(params.begin()+2, ConvToStr(ServerInstance->Time())); } else if (cmd == "MODENOTICE") { // MODENOTICE is always supported by 2.0 but it's optional in 2.2. params.insert(params.begin(), "*"); params.insert(params.begin()+1, cmd); cmd = "ENCAP"; } else if (cmd == "RULES") { return false; } else if (cmd == "INVITE") { // :20D INVITE 22DAAABBB #chan // :20D INVITE 22DAAABBB #chan 123456789 // Insert channel timestamp after the channel name; the 3rd parameter, if there, is the invite expiration time return InsertCurrentChannelTS(params, 1, 2); } else if (cmd == "VERSION") { // :20D VERSION :InspIRCd-2.0 // change to // :20D SINFO version :InspIRCd-2.0 cmd = "SINFO"; params.insert(params.begin(), "version"); } else if (cmd == "JOIN") { // 2.0 allows and forwards legacy JOINs but we don't, so translate them to FJOINs before processing if ((params.size() != 1) || (IS_SERVER(who))) return false; // Huh? cmd = "FJOIN"; Channel* chan = ServerInstance->FindChan(params[0]); params.push_back(ConvToStr(chan ? chan->age : ServerInstance->Time())); params.push_back("+"); params.push_back(","); params.back().append(who->uuid); who = TreeServer::Get(who)->ServerUser; } else if ((cmd == "FMODE") && (params.size() >= 2)) { // Translate user mode changes with timestamp to MODE if (params[0][0] != '#') { User* user = ServerInstance->FindUUID(params[0]); if (!user) return false; // Emulate the old nonsensical behavior if (user->age < ServerCommand::ExtractTS(params[1])) return false; cmd = "MODE"; params.erase(params.begin()+1); } } return true; // Passthru }
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; } } } }