X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_spanningtree.cpp;h=20c81bd95af8d3086f682bc479394b82d2e3d638;hb=69c3a32784b8c638ea10c269c3f63ede86b8aaa0;hp=95e252cc48a654726e59d4e2251151e7667c4e03;hpb=92bcceabef0d9d13339d3ce349c41e17b190367b;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp index 95e252cc4..20c81bd95 100644 --- a/src/modules/m_spanningtree.cpp +++ b/src/modules/m_spanningtree.cpp @@ -80,6 +80,29 @@ class ModuleSpanningTree; */ typedef nspace::hash_map, irc::StrHashComp> server_hash; + +/** The Link class might as well be a struct, + * but this is C++ and we don't believe in structs (!). + * It holds the entire information of one + * tag from the main config file. We maintain a list + * of them, and populate the list on rehash/load. + */ +class Link : public classbase +{ + public: + irc::string Name; + std::string IPAddr; + int Port; + std::string SendPass; + std::string RecvPass; + unsigned long AutoConnect; + time_t NextConnectTime; + std::string EncryptionKey; + bool HiddenFromStats; + std::string FailOver; + int Timeout; +}; + /** Contains helper functions and variables for this module, * and keeps them out of the global namespace */ @@ -102,6 +125,9 @@ class SpanningTreeUtilities /** Announce TS changes to channels on merge */ bool AnnounceTSChange; + /** Synchronize timestamps between servers + */ + bool EnableTimeSync; /** Socket bindings for listening sockets */ std::vector Bindings; @@ -126,22 +152,22 @@ class SpanningTreeUtilities ~SpanningTreeUtilities(); /** Send a message from this server to one other local or remote */ - bool DoOneToOne(std::string prefix, std::string command, std::deque ¶ms, std::string target); + bool DoOneToOne(const std::string &prefix, const std::string &command, std::deque ¶ms, std::string target); /** Send a message from this server to all but one other, local or remote */ - bool DoOneToAllButSender(std::string prefix, std::string command, std::deque ¶ms, std::string omit); + bool DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque ¶ms, std::string omit); /** Send a message from this server to all but one other, local or remote */ bool DoOneToAllButSender(const char* prefix, const char* command, std::deque ¶ms, std::string omit); /** Send a message from this server to all others */ - bool DoOneToMany(std::string prefix, std::string command, std::deque ¶ms); + bool DoOneToMany(const std::string &prefix, const std::string &command, std::deque ¶ms); /** Send a message from this server to all others */ bool DoOneToMany(const char* prefix, const char* command, std::deque ¶ms); /** Send a message from this server to all others, without doing any processing on the command (e.g. send it as-is with colons and all) */ - bool DoOneToAllButSenderRaw(std::string data, std::string omit, std::string prefix, irc::string command, std::deque ¶ms); + bool DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque ¶ms); /** Read the spanningtree module's tags from the config file */ void ReadConfiguration(bool rebind); @@ -153,16 +179,16 @@ class SpanningTreeUtilities void GetListOfServersForChannel(chanrec* c, std::deque &list); /** Find a server by name */ - TreeServer* FindServer(std::string ServerName); + TreeServer* FindServer(const std::string &ServerName); /** Find a route to a server by name */ - TreeServer* BestRouteTo(std::string ServerName); + TreeServer* BestRouteTo(const std::string &ServerName); /** Find a server by glob mask */ - TreeServer* FindServerMask(std::string ServerName); + TreeServer* FindServerMask(const std::string &ServerName); /** Returns true if this is a server name we recognise */ - bool IsServer(std::string ServerName); + bool IsServer(const std::string &ServerName); /** Attempt to connect to the failover link of link x */ void DoFailOver(Link* x); @@ -225,7 +251,8 @@ class TreeServer : public classbase { Parent = NULL; VersionString = ""; - UserCount = OperCount = 0; + UserCount = ServerInstance->UserCount(); + OperCount = ServerInstance->OperCount(); VersionString = ServerInstance->GetVersionString(); Route = NULL; Socket = NULL; /* Fix by brain */ @@ -416,7 +443,7 @@ class TreeServer : public classbase return Parent; } - void SetVersion(std::string Version) + void SetVersion(const std::string &Version) { VersionString = Version; } @@ -491,34 +518,13 @@ class TreeServer : public classbase } }; -/** The Link class might as well be a struct, - * but this is C++ and we don't believe in structs (!). - * It holds the entire information of one - * tag from the main config file. We maintain a list - * of them, and populate the list on rehash/load. - */ -class Link : public classbase -{ - public: - irc::string Name; - std::string IPAddr; - int Port; - std::string SendPass; - std::string RecvPass; - unsigned long AutoConnect; - time_t NextConnectTime; - std::string EncryptionKey; - bool HiddenFromStats; - irc::string FailOver; -}; - /** Yay for fast searches! * This is hundreds of times faster than recursion * or even scanning a linked list, especially when * there are more than a few servers to deal with. * (read as: lots). */ -TreeServer* SpanningTreeUtilities::FindServer(std::string ServerName) +TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName) { server_hash::iterator iter; iter = serverlist.find(ServerName.c_str()); @@ -538,7 +544,7 @@ TreeServer* SpanningTreeUtilities::FindServer(std::string ServerName) * See the comments for the constructor of TreeServer * for more details. */ -TreeServer* SpanningTreeUtilities::BestRouteTo(std::string ServerName) +TreeServer* SpanningTreeUtilities::BestRouteTo(const std::string &ServerName) { if (ServerName.c_str() == TreeRoot->GetName()) return NULL; @@ -559,7 +565,7 @@ TreeServer* SpanningTreeUtilities::BestRouteTo(std::string ServerName) * and match each one until we get a hit. Yes its slow, * deal with it. */ -TreeServer* SpanningTreeUtilities::FindServerMask(std::string ServerName) +TreeServer* SpanningTreeUtilities::FindServerMask(const std::string &ServerName) { for (server_hash::iterator i = serverlist.begin(); i != serverlist.end(); i++) { @@ -570,7 +576,7 @@ TreeServer* SpanningTreeUtilities::FindServerMask(std::string ServerName) } /* A convenient wrapper that returns true if a server exists */ -bool SpanningTreeUtilities::IsServer(std::string ServerName) +bool SpanningTreeUtilities::IsServer(const std::string &ServerName) { return (FindServer(ServerName) != NULL); } @@ -898,7 +904,7 @@ class TreeSocket : public InspSocket return result; } - bool Capab(std::deque params) + bool Capab(const std::deque ¶ms) { if (params.size() < 1) { @@ -1051,10 +1057,13 @@ class TreeSocket : public InspSocket * does some validation first and passes on the SQUIT to all * other remaining servers. */ - void Squit(TreeServer* Current,std::string reason) + void Squit(TreeServer* Current, const std::string &reason) { if ((Current) && (Current != Utils->TreeRoot)) { + Event rmode((char*)Current->GetName().c_str(), (Module*)Utils->Creator, "lost_server"); + rmode.Send(Instance); + std::deque params; params.push_back(Current->GetName()); params.push_back(":"+reason); @@ -1083,7 +1092,7 @@ class TreeSocket : public InspSocket } /** FMODE command - server mode with timestamp checks */ - bool ForceMode(std::string source, std::deque ¶ms) + bool ForceMode(const std::string &source, std::deque ¶ms) { /* Chances are this is a 1.0 FMODE without TS */ if (params.size() < 3) @@ -1471,7 +1480,7 @@ class TreeSocket : public InspSocket } /** FTOPIC command */ - bool ForceTopic(std::string source, std::deque ¶ms) + bool ForceTopic(const std::string &source, std::deque ¶ms) { if (params.size() != 4) return true; @@ -1515,7 +1524,7 @@ class TreeSocket : public InspSocket } /** FJOIN, similar to TS6 SJOIN, but not quite. */ - bool ForceJoin(std::string source, std::deque ¶ms) + bool ForceJoin(const std::string &source, std::deque ¶ms) { /* 1.1 FJOIN works as follows: * @@ -1586,7 +1595,7 @@ class TreeSocket : public InspSocket /* default TS is a high value, which if we dont have this * channel will let the other side apply their modes. */ - time_t ourTS = time(NULL)+600; + time_t ourTS = Instance->Time(true)+600; /* Does this channel exist? if it does, get its REAL timestamp */ if (chan) @@ -1608,7 +1617,7 @@ class TreeSocket : public InspSocket /* Lower the TS here */ if (Utils->AnnounceTSChange && chan) chan->WriteChannelWithServ(Instance->Config->ServerName, - "TS for %s changed from %lu to %lu", chan->name, ourTS, TS); + "NOTICE %s :TS for %s changed from %lu to %lu", chan->name, chan->name, ourTS, TS); ourTS = TS; param_list.push_back(channel); @@ -1793,7 +1802,7 @@ class TreeSocket : public InspSocket } /** NICK command */ - bool IntroduceClient(std::string source, std::deque ¶ms) + bool IntroduceClient(const std::string &source, std::deque ¶ms) { if (params.size() < 8) return true; @@ -1873,6 +1882,8 @@ class TreeSocket : public InspSocket */ void SendFJoins(TreeServer* Current, chanrec* c) { + std::string buffer; + Instance->Log(DEBUG,"Sending FJOINs to other server for %s",c->name); char list[MAXBUF]; std::string individual_halfops = std::string(":")+this->Instance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age); @@ -1883,8 +1894,6 @@ class TreeSocket : public InspSocket char* ptr = list + dlen; CUList *ulist = c->GetUsers(); - std::vector specific_halfop; - std::vector specific_voice; std::string modes = ""; std::string params = ""; @@ -1900,7 +1909,8 @@ class TreeSocket : public InspSocket if (curlen > (480-NICKMAX)) { - this->WriteLine(list); + buffer.append(list).append("\r\n"); + dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age); ptr = list + dlen; ptrlen = 0; @@ -1909,64 +1919,83 @@ class TreeSocket : public InspSocket } if (numusers) - this->WriteLine(list); + buffer.append(list).append("\r\n"); - for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++) - { + for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++) + { modes.append("b"); - params.append(b->data).append(" "); - } - this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age)+" +"+c->ChanModes(true)+modes+" "+params); + params.append(" ").append(b->data); + + if (params.length() >= MAXMODES) + { + /* Wrap at MAXMODES */ + buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n"); + modes = ""; + params = ""; + } + } + + buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(c->ChanModes(true)); + + /* Only send these if there are any */ + if (!modes.empty()) + buffer.append("\r\n").append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params); + + this->WriteLine(buffer); } /** Send G, Q, Z and E lines */ void SendXLines(TreeServer* Current) { char data[MAXBUF]; + std::string buffer; std::string n = this->Instance->Config->ServerName; const char* sn = n.c_str(); int iterations = 0; /* Yes, these arent too nice looking, but they get the job done */ for (std::vector::iterator i = Instance->XLines->zlines.begin(); i != Instance->XLines->zlines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - this->WriteLine(data); + snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); + buffer.append(data); } for (std::vector::iterator i = Instance->XLines->qlines.begin(); i != Instance->XLines->qlines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - this->WriteLine(data); + snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); + buffer.append(data); } for (std::vector::iterator i = Instance->XLines->glines.begin(); i != Instance->XLines->glines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE G %s %s %lu %lu :%s",sn,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - this->WriteLine(data); + snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); + buffer.append(data); } for (std::vector::iterator i = Instance->XLines->elines.begin(); i != Instance->XLines->elines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE E %s %s %lu %lu :%s",sn,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - this->WriteLine(data); + snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); + buffer.append(data); } for (std::vector::iterator i = Instance->XLines->pzlines.begin(); i != Instance->XLines->pzlines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - this->WriteLine(data); + snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); + buffer.append(data); } for (std::vector::iterator i = Instance->XLines->pqlines.begin(); i != Instance->XLines->pqlines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - this->WriteLine(data); + snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); + buffer.append(data); } for (std::vector::iterator i = Instance->XLines->pglines.begin(); i != Instance->XLines->pglines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE G %s %s %lu %lu :%s",sn,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - this->WriteLine(data); + snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); + buffer.append(data); } for (std::vector::iterator i = Instance->XLines->pelines.begin(); i != Instance->XLines->pelines.end(); i++, iterations++) { - snprintf(data,MAXBUF,":%s ADDLINE E %s %s %lu %lu :%s",sn,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); - this->WriteLine(data); + snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason); + buffer.append(data); } + + if (!buffer.empty()) + this->WriteLine(buffer); } /** Send channel modes and topics */ @@ -2000,6 +2029,7 @@ class TreeSocket : public InspSocket { char data[MAXBUF]; std::deque list; + std::string dataline; int iterations = 0; for (user_hash::iterator u = this->Instance->clientlist.begin(); u != this->Instance->clientlist.end(); u++, iterations++) { @@ -2009,11 +2039,13 @@ class TreeSocket : public InspSocket this->WriteLine(data); if (*u->second->oper) { - this->WriteLine(":"+std::string(u->second->nick)+" OPERTYPE "+std::string(u->second->oper)); + snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->nick, u->second->oper); + this->WriteLine(data); } if (*u->second->awaymsg) { - this->WriteLine(":"+std::string(u->second->nick)+" AWAY :"+std::string(u->second->awaymsg)); + snprintf(data,MAXBUF,":%s AWAY :%s", u->second->nick, u->second->awaymsg); + this->WriteLine(data); } FOREACH_MOD_I(this->Instance,I_OnSyncUser,OnSyncUser(u->second,(Module*)Utils->Creator,(void*)this)); list.clear(); @@ -2033,7 +2065,7 @@ class TreeSocket : public InspSocket */ void DoBurst(TreeServer* s) { - std::string burst = "BURST "+ConvToStr(time(NULL)); + std::string burst = "BURST "+ConvToStr(Instance->Time(true)); std::string endburst = "ENDBURST"; // Because by the end of the netburst, it could be gone! std::string name = s->GetName(); @@ -2075,6 +2107,10 @@ class TreeSocket : public InspSocket { std::string ret = in_buffer.substr(0,in_buffer.find("\n")-1); in_buffer = in_buffer.substr(in_buffer.find("\n")+1,in_buffer.length()-in_buffer.find("\n")); + /* Use rfind here not find, as theres more + * chance of the \r being near the end of the + * string, not the start. + */ if (ret.find("\r") != std::string::npos) ret = in_buffer.substr(0,in_buffer.find("\r")-1); /* Process this one, abort if it @@ -2094,14 +2130,22 @@ class TreeSocket : public InspSocket { ctx_in->Decrypt(out, result, nbytes, 0); for (int t = 0; t < nbytes; t++) - if (result[t] == '\7') result[t] = 0; + { + if (result[t] == '\7') + { + /* We only need to stick a \0 on the + * first \7, the rest will be lost + */ + result[t] = 0; + break; + } + } ret = result; } } } if (!this->ProcessLine(ret)) { - Instance->Log(DEBUG,"ProcessLine says no!"); return false; } } @@ -2132,7 +2176,8 @@ class TreeSocket : public InspSocket to64frombits((unsigned char*)result64,(unsigned char*)result,ll); line = result64; } - return this->Write(line + "\r\n"); + line.append("\r\n"); + return this->Write(line); } /* Handle ERROR command */ @@ -2146,7 +2191,7 @@ class TreeSocket : public InspSocket } /** remote MOTD. leet, huh? */ - bool Motd(std::string prefix, std::deque ¶ms) + bool Motd(const std::string &prefix, std::deque ¶ms) { if (params.size() > 0) { @@ -2194,7 +2239,7 @@ class TreeSocket : public InspSocket } /** remote ADMIN. leet, huh? */ - bool Admin(std::string prefix, std::deque ¶ms) + bool Admin(const std::string &prefix, std::deque ¶ms) { if (params.size() > 0) { @@ -2234,7 +2279,7 @@ class TreeSocket : public InspSocket return true; } - bool Stats(std::string prefix, std::deque ¶ms) + bool Stats(const std::string &prefix, std::deque ¶ms) { /* Get the reply to a STATS query if it matches this servername, * and send it back as a load of PUSH queries @@ -2274,7 +2319,7 @@ class TreeSocket : public InspSocket /** Because the core won't let users or even SERVERS set +o, * we use the OPERTYPE command to do this. */ - bool OperType(std::string prefix, std::deque ¶ms) + bool OperType(const std::string &prefix, std::deque ¶ms) { if (params.size() != 1) { @@ -2295,7 +2340,7 @@ class TreeSocket : public InspSocket /** Because Andy insists that services-compatible servers must * implement SVSNICK and SVSJOIN, that's exactly what we do :p */ - bool ForceNick(std::string prefix, std::deque ¶ms) + bool ForceNick(const std::string &prefix, std::deque ¶ms) { if (params.size() < 3) return true; @@ -2323,7 +2368,7 @@ class TreeSocket : public InspSocket return true; } - bool ServiceJoin(std::string prefix, std::deque ¶ms) + bool ServiceJoin(const std::string &prefix, std::deque ¶ms) { if (params.size() < 2) return true; @@ -2338,7 +2383,7 @@ class TreeSocket : public InspSocket return true; } - bool RemoteRehash(std::string prefix, std::deque ¶ms) + bool RemoteRehash(const std::string &prefix, std::deque ¶ms) { if (params.size() < 1) return false; @@ -2356,7 +2401,7 @@ class TreeSocket : public InspSocket return true; } - bool RemoteKill(std::string prefix, std::deque ¶ms) + bool RemoteKill(const std::string &prefix, std::deque ¶ms) { if (params.size() != 2) return true; @@ -2386,7 +2431,7 @@ class TreeSocket : public InspSocket return true; } - bool LocalPong(std::string prefix, std::deque ¶ms) + bool LocalPong(const std::string &prefix, std::deque ¶ms) { if (params.size() < 1) return true; @@ -2427,7 +2472,7 @@ class TreeSocket : public InspSocket return true; } - bool MetaData(std::string prefix, std::deque ¶ms) + bool MetaData(const std::string &prefix, std::deque ¶ms) { if (params.size() < 3) return true; @@ -2463,7 +2508,7 @@ class TreeSocket : public InspSocket return true; } - bool ServerVersion(std::string prefix, std::deque ¶ms) + bool ServerVersion(const std::string &prefix, std::deque ¶ms) { if (params.size() < 1) return true; @@ -2479,7 +2524,7 @@ class TreeSocket : public InspSocket return true; } - bool ChangeHost(std::string prefix, std::deque ¶ms) + bool ChangeHost(const std::string &prefix, std::deque ¶ms) { if (params.size() < 1) return true; @@ -2494,7 +2539,7 @@ class TreeSocket : public InspSocket return true; } - bool AddLine(std::string prefix, std::deque ¶ms) + bool AddLine(const std::string &prefix, std::deque ¶ms) { if (params.size() < 6) return true; @@ -2551,7 +2596,7 @@ class TreeSocket : public InspSocket return true; } - bool ChangeName(std::string prefix, std::deque ¶ms) + bool ChangeName(const std::string &prefix, std::deque ¶ms) { if (params.size() < 1) return true; @@ -2567,7 +2612,7 @@ class TreeSocket : public InspSocket return true; } - bool Whois(std::string prefix, std::deque ¶ms) + bool Whois(const std::string &prefix, std::deque ¶ms) { if (params.size() < 1) return true; @@ -2589,7 +2634,7 @@ class TreeSocket : public InspSocket char idle[MAXBUF]; snprintf(signon,MAXBUF,"%lu",(unsigned long)x->signon); - snprintf(idle,MAXBUF,"%lu",(unsigned long)abs((x->idle_lastmsg)-time(NULL))); + snprintf(idle,MAXBUF,"%lu",(unsigned long)abs((x->idle_lastmsg)-Instance->Time(true))); std::deque par; par.push_back(prefix); par.push_back(signon); @@ -2626,7 +2671,7 @@ class TreeSocket : public InspSocket return true; } - bool Push(std::string prefix, std::deque ¶ms) + bool Push(const std::string &prefix, std::deque ¶ms) { if (params.size() < 2) return true; @@ -2649,7 +2694,46 @@ class TreeSocket : public InspSocket return true; } - bool Time(std::string prefix, std::deque ¶ms) + bool HandleSetTime(const std::string &prefix, std::deque ¶ms) + { + if (!params.size() || !Utils->EnableTimeSync) + return true; + + bool force = false; + + if ((params.size() == 2) && (params[1] == "FORCE")) + force = true; + + time_t rts = atoi(params[0].c_str()); + time_t us = Instance->Time(true); + + if (rts == us) + { + Instance->Log(DEBUG, "Timestamp from %s is equal", prefix.c_str()); + + Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix); + } + else if (force || (rts < us)) + { + int old = Instance->SetTimeDelta(rts - us); + Instance->Log(DEBUG, "%s TS (diff %d) from %s applied (old delta was %d)", (force) ? "Forced" : "Lower", rts - us, prefix.c_str(), old); + + Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix); + } + else + { + Instance->Log(DEBUG, "Higher TS (diff %d) from %s overridden", us - rts, prefix.c_str()); + + std::deque oparams; + oparams.push_back(ConvToStr(us)); + + Utils->DoOneToMany(prefix, "TIMESET", oparams); + } + + return true; + } + + bool Time(const std::string &prefix, std::deque ¶ms) { // :source.server TIME remote.server sendernick // :remote.server TIME source.server sendernick TS @@ -2661,9 +2745,7 @@ class TreeSocket : public InspSocket userrec* u = this->Instance->FindNick(params[1]); if (u) { - char curtime[256]; - snprintf(curtime,256,"%lu",(unsigned long)time(NULL)); - params.push_back(curtime); + params.push_back(ConvToStr(Instance->Time(false))); params[0] = prefix; Utils->DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]); } @@ -2699,7 +2781,7 @@ class TreeSocket : public InspSocket return true; } - bool LocalPing(std::string prefix, std::deque ¶ms) + bool LocalPing(const std::string &prefix, std::deque ¶ms) { if (params.size() < 1) return true; @@ -2729,7 +2811,7 @@ class TreeSocket : public InspSocket } } - bool RemoveStatus(std::string prefix, std::deque ¶ms) + bool RemoveStatus(const std::string &prefix, std::deque ¶ms) { if (params.size() < 1) return true; @@ -2787,7 +2869,7 @@ class TreeSocket : public InspSocket return true; } - bool RemoteServer(std::string prefix, std::deque ¶ms) + bool RemoteServer(const std::string &prefix, std::deque ¶ms) { if (params.size() < 4) return false; @@ -2922,7 +3004,7 @@ class TreeSocket : public InspSocket return false; } - void Split(std::string line, std::deque &n) + void Split(const std::string &line, std::deque &n) { n.clear(); irc::tokenstream tokens(line); @@ -2932,7 +3014,7 @@ class TreeSocket : public InspSocket return; } - bool ProcessLine(std::string line) + bool ProcessLine(std::string &line) { std::deque params; irc::string command; @@ -3034,20 +3116,40 @@ class TreeSocket : public InspSocket } else if (command == "BURST") { - if (params.size()) + if (params.size() && Utils->EnableTimeSync) { - /* If a time stamp is provided, try and check syncronization */ - time_t THEM = atoi(params[0].c_str()); - long delta = THEM-time(NULL); + /* If a time stamp is provided, apply synchronization */ + bool force = false; + time_t them = atoi(params[0].c_str()); + time_t us = Instance->Time(true); + int delta = them - us; + + if ((params.size() == 2) && (params[1] == "FORCE")) + force = true; + if ((delta < -600) || (delta > 600)) { this->Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than ten minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta)); this->WriteLine("ERROR :Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than ten minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!"); return false; } - else if ((delta < -60) || (delta > 60)) + + if (us == them) { - this->Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds, please consider synching your clocks.",abs(delta)); + this->Instance->Log(DEBUG, "Timestamps are equal; pat yourself on the back"); + } + else if (force || (us > them)) + { + this->Instance->Log(DEBUG, "Remote server has lower TS (%d seconds)", them - us); + this->Instance->SetTimeDelta(them - us); + // Send this new timestamp to any other servers + Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params); + } + else + { + // Override the timestamp + this->Instance->Log(DEBUG, "We have a higher timestamp (by %d seconds), not updating delta", us - them); + this->WriteLine(":" + Utils->TreeRoot->GetName() + " TIMESET " + ConvToStr(us)); } } this->LinkState = CONNECTED; @@ -3256,6 +3358,10 @@ class TreeSocket : public InspSocket { return this->Push(prefix,params); } + else if (command == "TIMESET") + { + return this->HandleSetTime(prefix, params); + } else if (command == "TIME") { return this->Time(prefix,params); @@ -3306,6 +3412,10 @@ class TreeSocket : public InspSocket sourceserv = this->InboundServerName; } this->Instance->SNO->WriteToSnoMask('l',"Received end of netburst from \2%s\2",sourceserv.c_str()); + + Event rmode((char*)sourceserv.c_str(), (Module*)Utils->Creator, "new_server"); + rmode.Send(Instance); + return true; } else @@ -3426,7 +3536,9 @@ class TreeSocket : public InspSocket { Squit(s,"Remote host closed the connection"); } - this->Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' failed.",quitserver.c_str()); + + if (quitserver != "") + this->Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' failed.",quitserver.c_str()); } virtual int OnIncomingConnection(int newsock, char* ip) @@ -3473,7 +3585,7 @@ class ServernameResolver : public Resolver Link MyLink; SpanningTreeUtilities* Utils; public: - ServernameResolver(SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x) : Resolver(Instance, hostname, DNS_QUERY_FORWARD), MyLink(x), Utils(Util) + ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x) : Resolver(Instance, hostname, DNS_QUERY_FORWARD, me), MyLink(x), Utils(Util) { /* Nothing in here, folks */ } @@ -3487,7 +3599,7 @@ class ServernameResolver : public Resolver 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(this->Utils, ServerInstance, result,MyLink.Port,false,10,MyLink.Name.c_str()); + TreeSocket* newsocket = new TreeSocket(this->Utils, ServerInstance, result,MyLink.Port,false,MyLink.Timeout ? MyLink.Timeout : 10,MyLink.Name.c_str()); if (newsocket->GetFd() > -1) { /* We're all OK */ @@ -3518,7 +3630,7 @@ class SecurityIPResolver : public Resolver Link MyLink; SpanningTreeUtilities* Utils; public: - SecurityIPResolver(SpanningTreeUtilities* U, InspIRCd* Instance, const std::string &hostname, Link x) : Resolver(Instance, hostname, DNS_QUERY_FORWARD), MyLink(x), Utils(U) + SecurityIPResolver(Module* me, SpanningTreeUtilities* U, InspIRCd* Instance, const std::string &hostname, Link x) : Resolver(Instance, hostname, DNS_QUERY_FORWARD, me), MyLink(x), Utils(U) { } @@ -3563,6 +3675,7 @@ SpanningTreeUtilities::~SpanningTreeUtilities() DELETE(sock); } } + delete TreeRoot; } void SpanningTreeUtilities::AddThisServer(TreeServer* server, std::deque &list) @@ -3593,7 +3706,7 @@ void SpanningTreeUtilities::GetListOfServersForChannel(chanrec* c, std::deque ¶ms) +bool SpanningTreeUtilities::DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque ¶ms) { TreeServer* omitroute = this->BestRouteTo(omit); if ((command == "NOTICE") || (command == "PRIVMSG")) @@ -3661,7 +3774,7 @@ bool SpanningTreeUtilities::DoOneToAllButSenderRaw(std::string data, std::string return true; } -bool SpanningTreeUtilities::DoOneToAllButSender(std::string prefix, std::string command, std::deque ¶ms, std::string omit) +bool SpanningTreeUtilities::DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque ¶ms, std::string omit) { TreeServer* omitroute = this->BestRouteTo(omit); std::string FullLine = ":" + prefix + " " + command; @@ -3688,7 +3801,7 @@ bool SpanningTreeUtilities::DoOneToAllButSender(std::string prefix, std::string return true; } -bool SpanningTreeUtilities::DoOneToMany(std::string prefix, std::string command, std::deque ¶ms) +bool SpanningTreeUtilities::DoOneToMany(const std::string &prefix, const std::string &command, std::deque ¶ms) { std::string FullLine = ":" + prefix + " " + command; unsigned int words = params.size(); @@ -3724,7 +3837,7 @@ bool SpanningTreeUtilities::DoOneToAllButSender(const char* prefix, const char* return this->DoOneToAllButSender(spfx, scmd, params, omit); } -bool SpanningTreeUtilities::DoOneToOne(std::string prefix, std::string command, std::deque ¶ms, std::string target) +bool SpanningTreeUtilities::DoOneToOne(const std::string &prefix, const std::string &command, std::deque ¶ms, std::string target) { TreeServer* Route = this->BestRouteTo(target); if (Route) @@ -3758,33 +3871,38 @@ void SpanningTreeUtilities::ReadConfiguration(bool rebind) { std::string Type = Conf->ReadValue("bind","type",j); std::string IP = Conf->ReadValue("bind","address",j); - int Port = Conf->ReadInteger("bind","port",j,true); + std::string Port = Conf->ReadValue("bind","port",j); if (Type == "servers") { - ServerInstance->Log(DEBUG,"m_spanningtree: Binding server port %s:%d", IP.c_str(), Port); - if (IP == "*") + irc::portparser portrange(Port); + int portno = -1; + while ((portno = portrange.GetToken())) { - IP = ""; - } - TreeSocket* listener = new TreeSocket(this, ServerInstance, IP.c_str(),Port,true,10); - if (listener->GetState() == I_LISTENING) - { - ServerInstance->Log(DEFAULT,"m_spanningtree: Binding server port %s:%d successful!", IP.c_str(), Port); - Bindings.push_back(listener); - } - else - { - ServerInstance->Log(DEFAULT,"m_spanningtree: Warning: Failed to bind server port %d",Port); - listener->Close(); - DELETE(listener); + ServerInstance->Log(DEBUG,"m_spanningtree: Binding server port %s:%d", IP.c_str(), portno); + if (IP == "*") + IP = ""; + + TreeSocket* listener = new TreeSocket(this, ServerInstance, IP.c_str(), portno, true, 10); + if (listener->GetState() == I_LISTENING) + { + ServerInstance->Log(DEFAULT,"m_spanningtree: Binding server port %s:%d successful!", IP.c_str(), portno); + Bindings.push_back(listener); + } + else + { + ServerInstance->Log(DEFAULT,"m_spanningtree: Warning: Failed to bind server port %s:%d",IP.c_str(), portno); + listener->Close(); + DELETE(listener); + } + ServerInstance->Log(DEBUG,"Done with this binding"); } - ServerInstance->Log(DEBUG,"Done with this binding"); } } } FlatLinks = Conf->ReadFlag("options","flatlinks",0); HideULines = Conf->ReadFlag("options","hideulines",0); AnnounceTSChange = Conf->ReadFlag("options","announcets",0); + EnableTimeSync = !(Conf->ReadFlag("options","notimesync",0)); LinkBlocks.clear(); ValidIPs.clear(); for (int j =0; j < Conf->Enumerate("link"); j++) @@ -3800,6 +3918,7 @@ void SpanningTreeUtilities::ReadConfiguration(bool rebind) L.AutoConnect = Conf->ReadInteger("link","autoconnect",j,true); L.EncryptionKey = Conf->ReadValue("link","encryptionkey",j); L.HiddenFromStats = Conf->ReadFlag("link","hidden",j); + L.Timeout = Conf->ReadInteger("link","timeout",j,true); L.NextConnectTime = time(NULL) + L.AutoConnect; /* Bugfix by brain, do not allow people to enter bad configurations */ if (L.Name != ServerInstance->Config->ServerName) @@ -3817,7 +3936,7 @@ void SpanningTreeUtilities::ReadConfiguration(bool rebind) { try { - SecurityIPResolver* sr = new SecurityIPResolver(this, ServerInstance, L.IPAddr, L); + SecurityIPResolver* sr = new SecurityIPResolver((Module*)this->Creator, this, ServerInstance, L.IPAddr, L); ServerInstance->AddResolver(sr); } catch (ModuleException& e) @@ -3861,7 +3980,19 @@ void SpanningTreeUtilities::ReadConfiguration(bool rebind) DELETE(Conf); } - +/** To create a timer which recurs every second, we inherit from InspTimer. + * InspTimer is only one-shot however, so at the end of each Tick() we simply + * insert another of ourselves into the pending queue :) + */ +class TimeSyncTimer : public InspTimer +{ + private: + InspIRCd *Instance; + ModuleSpanningTree *Module; + public: + TimeSyncTimer(InspIRCd *Instance, ModuleSpanningTree *Mod); + virtual void Tick(time_t TIME); +}; class ModuleSpanningTree : public Module { @@ -3873,6 +4004,7 @@ class ModuleSpanningTree : public Module SpanningTreeUtilities* Utils; public: + TimeSyncTimer *SyncTimer; ModuleSpanningTree(InspIRCd* Me) : Module::Module(Me), max_local(0), max_global(0) @@ -3881,6 +4013,14 @@ class ModuleSpanningTree : public Module command_rconnect = new cmd_rconnect(ServerInstance, this, Utils); ServerInstance->AddCommand(command_rconnect); + + if (Utils->EnableTimeSync) + { + SyncTimer = new TimeSyncTimer(ServerInstance, this); + ServerInstance->Timers->AddTimer(SyncTimer); + } + else + SyncTimer = NULL; } void ShowLinks(TreeServer* Current, userrec* user, int hops) @@ -4256,7 +4396,7 @@ class ModuleSpanningTree : public Module /* Do we already have an IP? If so, no need to resolve it. */ if (insp_aton(x->IPAddr.c_str(), &binip) > 0) { - TreeSocket* newsocket = new TreeSocket(Utils, ServerInstance, x->IPAddr,x->Port,false,10,x->Name.c_str()); + TreeSocket* newsocket = new TreeSocket(Utils, ServerInstance, x->IPAddr,x->Port,false,x->Timeout ? x->Timeout : 10,x->Name.c_str()); if (newsocket->GetFd() > -1) { /* Handled automatically on success */ @@ -4272,7 +4412,7 @@ class ModuleSpanningTree : public Module { try { - ServernameResolver* snr = new ServernameResolver(Utils, ServerInstance,x->IPAddr, *x); + ServernameResolver* snr = new ServernameResolver((Module*)this, Utils, ServerInstance,x->IPAddr, *x); ServerInstance->AddResolver(snr); } catch (ModuleException& e) @@ -4375,6 +4515,13 @@ class ModuleSpanningTree : public Module return 1; } + void BroadcastTimeSync() + { + std::deque params; + params.push_back(ConvToStr(ServerInstance->Time(true))); + Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params); + } + virtual int OnStats(char statschar, userrec* user, string_list &results) { if (statschar == 'c') @@ -4789,26 +4936,38 @@ class ModuleSpanningTree : public Module void OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason) { - if (IS_LOCAL(source)) + if (!source) { - char type[8]; - snprintf(type,8,"%cLINE",linetype); - std::string stype = type; - if (adding) - { - char sduration[MAXBUF]; - snprintf(sduration,MAXBUF,"%ld",duration); - std::deque params; - params.push_back(host); - params.push_back(sduration); - params.push_back(":"+reason); - Utils->DoOneToMany(source->nick,stype,params); - } - else + /* Server-set lines */ + char data[MAXBUF]; + snprintf(data,MAXBUF,"%c %s %s %lu %lu :%s", linetype, host.c_str(), ServerInstance->Config->ServerName, ServerInstance->Time(false), duration, reason.c_str()); + std::deque params; + params.push_back(data); + Utils->DoOneToMany(ServerInstance->Config->ServerName, "ADDLINE", params); + } + else + { + if (IS_LOCAL(source)) { - std::deque params; - params.push_back(host); - Utils->DoOneToMany(source->nick,stype,params); + char type[8]; + snprintf(type,8,"%cLINE",linetype); + std::string stype = type; + if (adding) + { + char sduration[MAXBUF]; + snprintf(sduration,MAXBUF,"%ld",duration); + std::deque params; + params.push_back(host); + params.push_back(sduration); + params.push_back(":"+reason); + Utils->DoOneToMany(source->nick,stype,params); + } + else + { + std::deque params; + params.push_back(host); + Utils->DoOneToMany(source->nick,stype,params); + } } } } @@ -4953,7 +5112,7 @@ class ModuleSpanningTree : public Module return; (*params)[1] = ":" + (*params)[1]; params->insert(params->begin() + 1,ServerInstance->Config->ServerName); - params->insert(params->begin() + 1,ConvToStr(ServerInstance->Time())); + params->insert(params->begin() + 1,ConvToStr(ServerInstance->Time(true))); Utils->DoOneToMany(ServerInstance->Config->ServerName,"FTOPIC",*params); } else if (event->GetEventID() == "send_mode") @@ -4978,6 +5137,19 @@ class ModuleSpanningTree : public Module params->insert(params->begin() + 1,ConvToStr(ourTS)); Utils->DoOneToMany(ServerInstance->Config->ServerName,"FMODE",*params); } + else if (event->GetEventID() == "send_push") + { + if (params->size() < 2) + return; + + userrec *a = ServerInstance->FindNick((*params)[0]); + + if (!a) + return; + + (*params)[1] = ":" + (*params)[1]; + Utils->DoOneToOne(ServerInstance->Config->ServerName, "PUSH", *params, a->server); + } } virtual ~ModuleSpanningTree() @@ -4985,6 +5157,8 @@ class ModuleSpanningTree : public Module ServerInstance->Log(DEBUG,"Performing unload of spanningtree!"); /* This will also free the listeners */ delete Utils; + if (SyncTimer) + ServerInstance->Timers->DelTimer(SyncTimer); } virtual Version GetVersion() @@ -5016,6 +5190,17 @@ class ModuleSpanningTree : public Module } }; +TimeSyncTimer::TimeSyncTimer(InspIRCd *Inst, ModuleSpanningTree *Mod) : InspTimer(43200, Inst->Time()), Instance(Inst), Module(Mod) +{ +} + +void TimeSyncTimer::Tick(time_t TIME) +{ + Module->BroadcastTimeSync(); + Module->SyncTimer = new TimeSyncTimer(Instance, Module); + Instance->Timers->AddTimer(Module->SyncTimer); +} + void SpanningTreeUtilities::DoFailOver(Link* x) { if (x->FailOver.length()) @@ -5050,7 +5235,6 @@ Link* SpanningTreeUtilities::FindLink(const std::string& name) return NULL; } - class ModuleSpanningTreeFactory : public ModuleFactory { public: