ModResult ModuleSpanningTree::HandleSquit(const std::vector<std::string>& parameters, User* user) { TreeServer* s = Utils->FindServerMask(parameters[0]); if (s) { if (s == Utils->TreeRoot) { 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 (sock) { 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 SpanningTreeUtilities::DoOneToOne(const CmdBuilder& params, Server* server) { TreeServer* ts = static_cast<TreeServer*>(server); TreeSocket* sock = ts->GetSocket(); if (sock) sock->WriteLine(params); }
int ModuleSpanningTree::HandleSquit(const char** parameters, int pcnt, userrec* user) { TreeServer* s = Utils->FindServerMask(parameters[0]); if (s) { if (s == Utils->TreeRoot) { user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick,parameters[0]); return 1; } TreeSocket* sock = s->GetSocket(); if (sock) { ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick); sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost()); ServerInstance->SE->DelFd(sock); sock->Close(); } else { if (IS_LOCAL(user)) user->WriteServ("NOTICE %s :*** WARNING: Using SQUIT to split remote servers is deprecated. Please use RSQUIT instead.",user->nick); } } else { user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick,parameters[0]); } return 1; }
void ServernameResolver::OnLookupComplete(const DNS::Query *r) { const DNS::ResourceRecord &ans_record = r->answers[0]; /* Initiate the connection, now that we have an IP to use. * Passing a hostname directly to BufferedSocket causes it to * just bail and set its FD to -1. */ TreeServer* CheckDupe = Utils->FindServer(MyLink->Name.c_str()); if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */ { TreeSocket* newsocket = new TreeSocket(Utils, MyLink, myautoconnect, ans_record.rdata); if (newsocket->GetFd() > -1) { /* We're all OK */ } else { /* Something barfed, show the opers */ ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.", MyLink->Name.c_str(), newsocket->getError().c_str()); ServerInstance->GlobalCulls.AddItem(newsocket); } } }
void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) { bool ipvalid = true; if (InspIRCd::Match(ServerInstance->Config->ServerName, assign(x->Name))) { ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Not connecting to myself."); return; } DNS::QueryType start_type = DNS::QUERY_AAAA; if (strchr(x->IPAddr.c_str(),':')) { in6_addr n; if (inet_pton(AF_INET6, x->IPAddr.c_str(), &n) < 1) ipvalid = false; } else { in_addr n; if (inet_aton(x->IPAddr.c_str(),&n) < 1) ipvalid = false; } /* Do we already have an IP? If so, no need to resolve it. */ if (ipvalid) { /* Gave a hook, but it wasnt one we know */ TreeSocket* newsocket = new TreeSocket(x, y, x->IPAddr); if (newsocket->GetFd() > -1) { /* Handled automatically on success */ } else { ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.", x->Name.c_str(), newsocket->getError().c_str()); ServerInstance->GlobalCulls.AddItem(newsocket); } } else if (!DNS) { ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Hostname given and m_dns.so is not loaded, unable to resolve.", x->Name.c_str()); } else { ServernameResolver* snr = new ServernameResolver(*DNS, x->IPAddr, x, start_type, y); try { DNS->Process(snr); } catch (DNS::Exception& e) { delete snr; ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason()); ConnectServer(y, false); } } }
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; } } }
void ModuleSpanningTree::OnUnloadModule(Module* mod) { if (!Utils) return; ServerInstance->PI->SendMetaData(NULL, "modules", "-" + mod->ModuleSourceFile); // 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 && sock->GetIOHook() && sock->GetIOHook()->creator == mod) { sock->SendError("SSL module unloaded"); sock->Close(); } } for (SpanningTreeUtilities::TimeoutList::const_iterator i = Utils->timeoutlist.begin(); i != Utils->timeoutlist.end(); ++i) { TreeSocket* sock = i->first; if (sock->GetIOHook() && sock->GetIOHook()->creator == mod) sock->Close(); } }
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); } } }
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); }
void ModuleSpanningTree::ConnectServer(Link* x) { bool ipvalid = true; QueryType start_type = DNS_QUERY_A; #ifdef IPV6 start_type = DNS_QUERY_AAAA; if (strchr(x->IPAddr.c_str(),':')) { in6_addr n; if (inet_pton(AF_INET6, x->IPAddr.c_str(), &n) < 1) ipvalid = false; } else #endif { in_addr n; if (inet_aton(x->IPAddr.c_str(),&n) < 1) ipvalid = false; } /* Do we already have an IP? If so, no need to resolve it. */ if (ipvalid) { /* Gave a hook, but it wasnt one we know */ if ((!x->Hook.empty()) && (Utils->hooks.find(x->Hook.c_str()) == Utils->hooks.end())) return; TreeSocket* newsocket = new TreeSocket(Utils, ServerInstance, x->IPAddr,x->Port,false,x->Timeout ? x->Timeout : 10,x->Name.c_str(), x->Bind, x->Hook.empty() ? NULL : Utils->hooks[x->Hook.c_str()]); if (newsocket->GetFd() > -1) { /* Handled automatically on success */ } else { ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno)); delete newsocket; Utils->DoFailOver(x); } } else { try { bool cached; ServernameResolver* snr = new ServernameResolver((Module*)this, Utils, ServerInstance,x->IPAddr, *x, cached, start_type); ServerInstance->AddResolver(snr, cached); } catch (ModuleException& e) { ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason()); Utils->DoFailOver(x); } } }
CmdResult CommandSQuit::HandleServer(TreeServer* server, std::vector<std::string>& params) { TreeServer* quitting = Utils->FindServer(params[0]); if (!quitting) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Squit from unknown server"); return CMD_FAILURE; } TreeSocket* sock = server->GetSocket(); sock->Squit(quitting, params[1]); return CMD_SUCCESS; }
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); } }
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); } } }
bool SpanningTreeUtilities::DoOneToMany(const std::string &prefix, const std::string &command, const parameterlist ¶ms) { 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; }
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); } } }
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); } }
CullResult SpanningTreeUtilities::cull() { const TreeServer::ChildServers& children = TreeRoot->GetChildren(); while (!children.empty()) { TreeSocket* sock = children.front()->GetSocket(); sock->Close(); } for(std::map<TreeSocket*, std::pair<std::string, int> >::iterator i = timeoutlist.begin(); i != timeoutlist.end(); ++i) { TreeSocket* s = i->first; s->Close(); } TreeRoot->cull(); return classbase::cull(); }
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; } }
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); } } }
CmdResult CommandSQuit::HandleServer(TreeServer* server, std::vector<std::string>& params) { TreeServer* quitting = Utils->FindServer(params[0]); if (!quitting) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Squit from unknown server"); return CMD_FAILURE; } TreeSocket* sock = server->GetSocket(); sock->Squit(quitting, params[1]); // XXX: Return CMD_FAILURE when servers SQUIT themselves (i.e. :00S SQUIT 00S :Shutting down) // to avoid RouteCommand() being called. RouteCommand() requires a valid command source but we // do not have one because the server user is deleted when its TreeServer is destructed. // We generate a SQUIT in TreeSocket::Squit(), with our sid as the source and send it to the // remaining servers. return ((quitting == server) ? CMD_FAILURE : CMD_SUCCESS); }
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); }
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); } }
CullResult SpanningTreeUtilities::cull() { while (TreeRoot->ChildCount()) { TreeServer* child_server = TreeRoot->GetChild(0); if (child_server) { TreeSocket* sock = child_server->GetSocket(); sock->Close(); } } for(std::map<TreeSocket*, std::pair<std::string, int> >::iterator i = timeoutlist.begin(); i != timeoutlist.end(); ++i) { TreeSocket* s = i->first; s->Close(); } TreeRoot->cull(); return classbase::cull(); }
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); } }
void ModuleSpanningTree::DoConnectTimeout(time_t curtime) { SpanningTreeUtilities::TimeoutList::iterator i = Utils->timeoutlist.begin(); while (i != Utils->timeoutlist.end()) { TreeSocket* s = i->first; std::pair<std::string, unsigned int> p = i->second; SpanningTreeUtilities::TimeoutList::iterator me = i; i++; if (s->GetLinkState() == DYING) { Utils->timeoutlist.erase(me); s->Close(); } else if (curtime > s->age + p.second) { ServerInstance->SNO.WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002 (timeout of %u seconds)",p.first.c_str(),p.second); Utils->timeoutlist.erase(me); s->Close(); } } }
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; }
/* * Some server somewhere in the network introducing another server. * -- w */ CmdResult CommandServer::HandleServer(TreeServer* ParentOfThis, std::vector<std::string>& params) { std::string servername = params[0]; // password is not used for a remote server // hopcount is not used (ever) std::string sid = params[3]; std::string description = params[4]; TreeSocket* socket = ParentOfThis->GetSocket(); if (!InspIRCd::IsSID(sid)) { socket->SendError("Invalid format server ID: "+sid+"!"); return CMD_FAILURE; } TreeServer* CheckDupe = Utils->FindServer(servername); if (CheckDupe) { socket->SendError("Server "+servername+" already exists!"); ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+CheckDupe->GetName()+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, already exists. Closing link with " + ParentOfThis->GetName()); return CMD_FAILURE; } CheckDupe = Utils->FindServer(sid); if (CheckDupe) { socket->SendError("Server ID "+sid+" already exists! 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 \2"+servername+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, server ID already exists on the network. Closing link with " + ParentOfThis->GetName()); return CMD_FAILURE; } Link* lnk = Utils->FindLink(servername); TreeServer* Node = new TreeServer(servername, description, sid, ParentOfThis, ParentOfThis->GetSocket(), lnk ? lnk->Hidden : false); ParentOfThis->AddChild(Node); ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+ParentOfThis->GetName()+"\002 introduced server \002"+servername+"\002 ("+description+")"); return CMD_SUCCESS; }
void ModuleSpanningTree::DoConnectTimeout(time_t curtime) { std::vector<Link*> failovers; for (std::map<TreeSocket*, std::pair<std::string, int> >::iterator i = Utils->timeoutlist.begin(); i != Utils->timeoutlist.end(); i++) { TreeSocket* s = i->first; std::pair<std::string, int> p = i->second; if (curtime > s->age + p.second) { ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002 (timeout of %d seconds)",p.first.c_str(),p.second); ServerInstance->SE->DelFd(s); s->Close(); Link* MyLink = Utils->FindLink(p.first); if (MyLink) failovers.push_back(MyLink); } } /* Trigger failover for each timed out socket */ for (std::vector<Link*>::const_iterator n = failovers.begin(); n != failovers.end(); ++n) { Utils->DoFailOver(*n); } }
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(); } }
void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) { bool ipvalid = true; if (InspIRCd::Match(ServerInstance->Config->ServerName, x->Name, ascii_case_insensitive_map)) { ServerInstance->SNO.WriteToSnoMask('l', "CONNECT: Not connecting to myself."); return; } #ifndef _WIN32 if (x->IPAddr.find('/') != std::string::npos) { struct stat sb; if (stat(x->IPAddr.c_str(), &sb) == -1 || !S_ISSOCK(sb.st_mode)) ipvalid = false; } #endif if (x->IPAddr.find(':') != std::string::npos) { in6_addr n; if (inet_pton(AF_INET6, x->IPAddr.c_str(), &n) < 1) ipvalid = false; } else { in_addr n; if (inet_pton(AF_INET, x->IPAddr.c_str(),&n) < 1) ipvalid = false; } /* Do we already have an IP? If so, no need to resolve it. */ if (ipvalid) { // Create a TreeServer object that will start connecting immediately in the background TreeSocket* newsocket = new TreeSocket(x, y, x->IPAddr); if (newsocket->GetFd() > -1) { /* Handled automatically on success */ } else { ServerInstance->SNO.WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.", x->Name.c_str(), newsocket->getError().c_str()); ServerInstance->GlobalCulls.AddItem(newsocket); } } else if (!DNS) { ServerInstance->SNO.WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Hostname given and core_dns is not loaded, unable to resolve.", x->Name.c_str()); } else { // Guess start_type from bindip aftype DNS::QueryType start_type = DNS::QUERY_AAAA; irc::sockets::sockaddrs bind; if ((!x->Bind.empty()) && (irc::sockets::aptosa(x->Bind, 0, bind))) { if (bind.family() == AF_INET) start_type = DNS::QUERY_A; } ServernameResolver* snr = new ServernameResolver(*DNS, x->IPAddr, x, start_type, y); try { DNS->Process(snr); } catch (DNS::Exception& e) { delete snr; ServerInstance->SNO.WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason().c_str()); ConnectServer(y, false); } } }