X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_spanningtree%2Fmain.cpp;h=4a31d70076412e7ed1942a7bc05e55ddf0c0199d;hb=f087d825a88760d251b8f80b5d50bc98b40fa2ae;hp=96ceee539aed11e4cafe1c58cf0fbb688c9bdc4f;hpb=ab7bad9d878793f0e46185ee53d6064de5073fc3;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 96ceee539..4a31d7007 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -36,7 +36,7 @@ ModuleSpanningTree::ModuleSpanningTree(InspIRCd* Me) : Module(Me), max_local(0), max_global(0) { - ServerInstance->UseInterface("InspSocketHook"); + ServerInstance->Modules->UseInterface("InspSocketHook"); Utils = new SpanningTreeUtilities(Me, this); command_rconnect = new cmd_rconnect(ServerInstance, this, Utils); ServerInstance->AddCommand(command_rconnect); @@ -167,307 +167,6 @@ std::string ModuleSpanningTree::TimeToStr(time_t secs) + ConvToStr(secs) + "s"); } -const std::string ModuleSpanningTree::MapOperInfo(TreeServer* Current) -{ - time_t secs_up = ServerInstance->Time() - Current->age; - return (" [Up: " + TimeToStr(secs_up) + " Lag: "+ConvToStr(Current->rtt)+"ms]"); -} - -// WARNING: NOT THREAD SAFE - DONT GET ANY SMART IDEAS. -void ModuleSpanningTree::ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers) -{ - if (line < 128) - { - for (int t = 0; t < depth; t++) - { - matrix[line][t] = ' '; - } - // For Aligning, we need to work out exactly how deep this thing is, and produce - // a 'Spacer' String to compensate. - char spacer[40]; - memset(spacer,' ',40); - if ((40 - Current->GetName().length() - depth) > 1) { - spacer[40 - Current->GetName().length() - depth] = '\0'; - } - else - { - spacer[5] = '\0'; - } - float percent; - char text[128]; - /* Neat and tidy default values, as we're dealing with a matrix not a simple string */ - memset(text, 0, 128); - - if (ServerInstance->clientlist->size() == 0) { - // If there are no users, WHO THE HELL DID THE /MAP?!?!?! - percent = 0; - } - else - { - percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist->size()) * 100; - } - const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : ""; - snprintf(text, 126, "%s %s%5d [%5.2f%%]%s", Current->GetName().c_str(), spacer, Current->GetUserCount(), percent, operdata.c_str()); - totusers += Current->GetUserCount(); - totservers++; - strlcpy(&matrix[line][depth],text,126); - line++; - for (unsigned int q = 0; q < Current->ChildCount(); q++) - { - if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str())))) - { - if (*user->oper) - { - ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); - } - } - else - { - ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); - } - } - } -} - -int ModuleSpanningTree::HandleMotd(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 0) - { - if (match(ServerInstance->Config->ServerName, parameters[0])) - return 0; - - /* Remote MOTD, the server is within the 1st parameter */ - std::deque params; - params.push_back(parameters[0]); - /* Send it out remotely, generate no reply yet */ - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - params[0] = s->GetName(); - Utils->DoOneToOne(user->uuid, "MOTD", params, s->GetName()); - } - else - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); - return 1; - } - return 0; -} - -int ModuleSpanningTree::HandleAdmin(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 0) - { - if (match(ServerInstance->Config->ServerName, parameters[0])) - return 0; - - /* Remote ADMIN, the server is within the 1st parameter */ - std::deque params; - params.push_back(parameters[0]); - /* Send it out remotely, generate no reply yet */ - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - params[0] = s->GetName(); - Utils->DoOneToOne(user->uuid, "ADMIN", params, s->GetName()); - } - else - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); - return 1; - } - return 0; -} - -int ModuleSpanningTree::HandleModules(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 0) - { - if (match(ServerInstance->Config->ServerName, parameters[0])) - return 0; - - std::deque params; - params.push_back(parameters[0]); - TreeServer* s = Utils->FindServerMask(parameters[0]); - if (s) - { - params[0] = s->GetName(); - Utils->DoOneToOne(user->uuid, "MODULES", params, s->GetName()); - } - else - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]); - return 1; - } - return 0; -} - -int ModuleSpanningTree::HandleStats(const char** parameters, int pcnt, userrec* user) -{ - if (pcnt > 1) - { - if (match(ServerInstance->Config->ServerName, parameters[1])) - return 0; - - /* Remote STATS, the server is within the 2nd parameter */ - std::deque params; - params.push_back(parameters[0]); - params.push_back(parameters[1]); - /* Send it out remotely, generate no reply yet */ - - TreeServer* s = Utils->FindServerMask(parameters[1]); - if (s) - { - params[1] = s->GetName(); - Utils->DoOneToOne(user->uuid, "STATS", params, s->GetName()); - } - else - { - user->WriteServ( "402 %s %s :No such server", user->nick, parameters[1]); - } - return 1; - } - return 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. -void ModuleSpanningTree::HandleMap(const char** parameters, int pcnt, userrec* user) -{ - // This array represents a virtual screen which we will - // "scratch" draw to, as the console device of an irc - // client does not provide for a proper terminal. - float totusers = 0; - float totservers = 0; - char matrix[128][128]; - for (unsigned int t = 0; t < 128; t++) - { - matrix[t][0] = '\0'; - } - line = 0; - // The only recursive bit is called here. - ShowMap(Utils->TreeRoot,user,0,matrix,totusers,totservers); - // Process each line one by one. The algorithm has a limit of - // 128 servers (which is far more than a spanning tree should have - // anyway, so we're ok). This limit can be raised simply by making - // the character matrix deeper, 128 rows taking 10k of memory. - for (int l = 1; l < line; 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 (matrix[l][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. - matrix[l][first_nonspace] = '-'; - matrix[l][first_nonspace-1] = '`'; - int l2 = l - 1; - // Draw upwards until we hit the parent server, causing possibly - // other corners (`-) to become branches (|-) - while ((matrix[l2][first_nonspace-1] == ' ') || (matrix[l2][first_nonspace-1] == '`')) - { - matrix[l2][first_nonspace-1] = '|'; - l2--; - } - } - // dump the whole lot to the user. This is the easy bit, honest. - for (int t = 0; t < line; t++) - { - user->WriteServ("006 %s :%s",user->nick,&matrix[t][0]); - } - float avg_users = totusers / totservers; - user->WriteServ("270 %s :%.0f server%s and %.0f user%s, average %.2f users per server",user->nick,totservers,(totservers > 1 ? "s" : ""),totusers,(totusers > 1 ? "s" : ""),avg_users); - user->WriteServ("007 %s :End of /MAP",user->nick); - return; -} - -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; -} - -int ModuleSpanningTree::HandleTime(const char** parameters, int pcnt, userrec* user) -{ - if ((IS_LOCAL(user)) && (pcnt)) - { - TreeServer* found = Utils->FindServerMask(parameters[0]); - if (found) - { - // we dont' override for local server - if (found == Utils->TreeRoot) - return 0; - - std::deque params; - params.push_back(found->GetName()); - params.push_back(user->uuid); - Utils->DoOneToOne(ServerInstance->Config->GetSID(),"TIME",params,found->GetName()); - } - else - { - user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]); - } - } - return 1; -} - -int ModuleSpanningTree::HandleRemoteWhois(const char** parameters, int pcnt, userrec* user) -{ - if ((IS_LOCAL(user)) && (pcnt > 1)) - { - userrec* remote = ServerInstance->FindNick(parameters[1]); - if ((remote) && (remote->GetFd() < 0)) - { - std::deque params; - params.push_back(parameters[1]); - Utils->DoOneToOne(user->uuid,"IDLE",params,remote->server); - return 1; - } - else if (!remote) - { - user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]); - user->WriteServ("318 %s %s :End of /WHOIS list.",user->nick, parameters[1]); - return 1; - } - } - return 0; -} - void ModuleSpanningTree::DoPingChecks(time_t curtime) { for (unsigned int j = 0; j < Utils->TreeRoot->ChildCount(); j++) @@ -480,7 +179,7 @@ void ModuleSpanningTree::DoPingChecks(time_t curtime) { if (serv->AnsweredLastPing()) { - sock->WriteLine(std::string(":")+ServerInstance->Config->GetSID()+" PING "+serv->GetName()); + sock->WriteLine(std::string(":")+ServerInstance->Config->GetSID()+" PING "+serv->GetID()); serv->SetNextPingTime(curtime + Utils->PingFreq); serv->LastPing = curtime; timeval t; @@ -629,6 +328,15 @@ int ModuleSpanningTree::HandleVersion(const char** parameters, int pcnt, userrec */ void ModuleSpanningTree::RemoteMessage(userrec* user, const char* format, ...) { + /* This could cause an infinite loop, because DoOneToMany() will, on error, + * call TreeSocket::OnError(), which in turn will call this function to + * notify everyone of the error. So, drop any messages that are generated + * during the sending of another message. -Special */ + static bool SendingRemoteMessage = false; + if (SendingRemoteMessage) + return; + SendingRemoteMessage = true; + std::deque params; char text[MAXBUF]; va_list argsPtr; @@ -657,6 +365,8 @@ void ModuleSpanningTree::RemoteMessage(userrec* user, const char* format, ...) Utils->DoOneToMany(ServerInstance->Config->GetSID(), "PUSH", params); } } + + SendingRemoteMessage = false; } int ModuleSpanningTree::HandleConnect(const char** parameters, int pcnt, userrec* user) @@ -668,18 +378,18 @@ int ModuleSpanningTree::HandleConnect(const char** parameters, int pcnt, userrec TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str()); if (!CheckDupe) { - RemoteMessage(user, "*** CONNECT: Connecting to server: \002%s\002 (%s:%d)",user->nick,x->Name.c_str(),(x->HiddenFromStats ? "" : x->IPAddr.c_str()),x->Port); + RemoteMessage(user, "*** CONNECT: Connecting to server: \002%s\002 (%s:%d)",x->Name.c_str(),(x->HiddenFromStats ? "" : x->IPAddr.c_str()),x->Port); ConnectServer(&(*x)); return 1; } else { - RemoteMessage(user, "*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002",user->nick,x->Name.c_str(),CheckDupe->GetParent()->GetName().c_str()); + RemoteMessage(user, "*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002",x->Name.c_str(),CheckDupe->GetParent()->GetName().c_str()); return 1; } } } - RemoteMessage(user, "NOTICE %s :*** CONNECT: No server matching \002%s\002 could be found in the config file.",user->nick,parameters[0]); + RemoteMessage(user, "*** CONNECT: No server matching \002%s\002 could be found in the config file.",parameters[0]); return 1; } @@ -694,148 +404,6 @@ void ModuleSpanningTree::BroadcastTimeSync() } } -int ModuleSpanningTree::OnStats(char statschar, userrec* user, string_list &results) -{ - if ((statschar == 'c') || (statschar == 'n')) - { - for (unsigned int i = 0; i < Utils->LinkBlocks.size(); i++) - { - results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" "+statschar+" *@"+(Utils->LinkBlocks[i].HiddenFromStats ? "" : Utils->LinkBlocks[i].IPAddr)+" * "+Utils->LinkBlocks[i].Name.c_str()+" "+ConvToStr(Utils->LinkBlocks[i].Port)+" "+(Utils->LinkBlocks[i].Hook.empty() ? "plaintext" : Utils->LinkBlocks[i].Hook)+" "+(Utils->LinkBlocks[i].AutoConnect ? 'a' : '-')+'s'); - if (statschar == 'c') - results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+Utils->LinkBlocks[i].Name.c_str()); - } - results.push_back(std::string(ServerInstance->Config->ServerName)+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); - ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host); - return 1; - } - - if (statschar == 'p') - { - /* show all server ports, after showing client ports. -- w00t */ - - for (unsigned int i = 0; i < Utils->Bindings.size(); i++) - { - std::string ip = Utils->Bindings[i]->IP; - if (ip.empty()) - ip = "*"; - - std::string transport("plaintext"); - if (Utils->Bindings[i]->GetHook()) - transport = InspSocketNameRequest(this, Utils->Bindings[i]->GetHook()).Send(); - - results.push_back(ConvToStr(ServerInstance->Config->ServerName) + " 249 "+user->nick+" :" + ip + ":" + ConvToStr(Utils->Bindings[i]->port)+ - " (server, " + transport + ")"); - } - } - return 0; -} - -int ModuleSpanningTree::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) -{ - /* If the command doesnt appear to be valid, we dont want to mess with it. */ - if (!validated) - return 0; - - if (command == "CONNECT") - { - return this->HandleConnect(parameters,pcnt,user); - } - else if (command == "STATS") - { - return this->HandleStats(parameters,pcnt,user); - } - else if (command == "MOTD") - { - return this->HandleMotd(parameters,pcnt,user); - } - else if (command == "ADMIN") - { - return this->HandleAdmin(parameters,pcnt,user); - } - else if (command == "SQUIT") - { - return this->HandleSquit(parameters,pcnt,user); - } - else if (command == "MAP") - { - this->HandleMap(parameters,pcnt,user); - return 1; - } - else if ((command == "TIME") && (pcnt > 0)) - { - return this->HandleTime(parameters,pcnt,user); - } - else if (command == "LUSERS") - { - this->HandleLusers(parameters,pcnt,user); - return 1; - } - else if (command == "LINKS") - { - this->HandleLinks(parameters,pcnt,user); - return 1; - } - else if (command == "WHOIS") - { - if (pcnt > 1) - { - // remote whois - return this->HandleRemoteWhois(parameters,pcnt,user); - } - } - else if ((command == "VERSION") && (pcnt > 0)) - { - this->HandleVersion(parameters,pcnt,user); - return 1; - } - else if ((command == "MODULES") && (pcnt > 0)) - { - return this->HandleModules(parameters,pcnt,user); - } - return 0; -} - -void ModuleSpanningTree::OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line) -{ - if ((result == CMD_SUCCESS) && (ServerInstance->IsValidModuleCommand(command, pcnt, user))) - { - /* Safe, we know its non-null because IsValidModuleCommand returned true */ - command_t* thiscmd = ServerInstance->Parser->GetHandler(command); - // this bit of code cleverly routes all module commands - // to all remote severs *automatically* so that modules - // can just handle commands locally, without having - // to have any special provision in place for remote - // commands and linking protocols. - std::deque params; - params.clear(); - int n_translate = thiscmd->translation.size(); - TranslateType translate_to; - - for (int j = 0; j < pcnt; j++) - { - std::string target; - - /* Map all items to UUIDs where neccessary */ - if (j < n_translate) - { - /* We have a translation mapping for this index */ - translate_to = thiscmd->translation[j] != TR_END ? thiscmd->translation[j] : TR_TEXT; - } - else - translate_to = TR_TEXT; - - ServerInstance->Log(DEBUG,"TRANSLATION: %s - type is %d", parameters[j], translate_to); - ServerInstance->Parser->TranslateUIDs(translate_to, parameters[j], target); - - if (strchr(parameters[j],' ')) - params.push_back(":" + target); - else - params.push_back(target); - } - Utils->DoOneToMany(user->uuid, command, params); - } -} - void ModuleSpanningTree::OnGetServerDescription(const std::string &servername,std::string &description) { TreeServer* s = Utils->FindServer(servername); @@ -1042,19 +610,18 @@ void ModuleSpanningTree::OnUserPart(userrec* user, chanrec* channel, const std:: void ModuleSpanningTree::OnUserConnect(userrec* user) { - char agestr[MAXBUF]; if (IS_LOCAL(user)) { std::deque params; - snprintf(agestr,MAXBUF,"%lu",(unsigned long)user->age); params.push_back(user->uuid); - params.push_back(agestr); + params.push_back(ConvToStr(user->age)); params.push_back(user->nick); params.push_back(user->host); params.push_back(user->dhost); params.push_back(user->ident); params.push_back("+"+std::string(user->FormatModes())); params.push_back(user->GetIPString()); + params.push_back(ConvToStr(user->signon)); params.push_back(":"+std::string(user->fullname)); Utils->DoOneToMany(ServerInstance->Config->GetSID(), "UID", params); // User is Local, change needs to be reflected! @@ -1095,7 +662,12 @@ void ModuleSpanningTree::OnUserPostNick(userrec* user, const std::string &oldnic { std::deque params; params.push_back(user->nick); - user->age = ServerInstance->Time(true); + + /** IMPORTANT: We don't update the TS if the oldnick is just a case change of the newnick! + */ + if (irc::string(user->nick) != assign(oldnick)) + user->age = ServerInstance->Time(true); + params.push_back(ConvToStr(user->age)); Utils->DoOneToMany(user->uuid,"NICK",params); } @@ -1444,7 +1016,7 @@ ModuleSpanningTree::~ModuleSpanningTree() ServerInstance->Timers->DelTimer(RefreshTimer); - ServerInstance->DoneWithInterface("InspSocketHook"); + ServerInstance->Modules->DoneWithInterface("InspSocketHook"); } Version ModuleSpanningTree::GetVersion() @@ -1476,4 +1048,3 @@ Priority ModuleSpanningTree::Prioritize() } MODULE_INIT(ModuleSpanningTree) -