diff options
-rw-r--r-- | include/inspircd.h | 16 | ||||
-rw-r--r-- | src/channels.cpp | 1 | ||||
-rw-r--r-- | src/inspircd.cpp | 13 | ||||
-rw-r--r-- | src/modules/m_spanningtree.cpp | 127 | ||||
-rw-r--r-- | src/users.cpp | 1 |
5 files changed, 140 insertions, 18 deletions
diff --git a/include/inspircd.h b/include/inspircd.h index 568c6a6a5..ea3194ff2 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -339,6 +339,11 @@ class InspIRCd : public classbase */ FileLogger* Logger; + /** Time offset in seconds + * This offset is added to all calls to Time(). Use SetTimeDelta() to update + */ + int time_delta; + public: /** List of server names we've seen. */ @@ -424,9 +429,18 @@ class InspIRCd : public classbase /** Get the current time * Because this only calls time() once every time around the mainloop, * it is much faster than calling time() directly. + * @param delta True to use the delta as an offset, false otherwise * @return The current time as an epoch value (time_t) */ - time_t Time(); + time_t Time(bool delta = false); + + /** Set the time offset in seconds + * This offset is added to Time() to offset the system time by the specified + * number of seconds. + * @param delta The number of seconds to offset + * @return The old time delta + */ + int SetTimeDelta(int delta); /** Process a user whos socket has been flagged as active * @param cu The user to process diff --git a/src/channels.cpp b/src/channels.cpp index 9ef1180c6..bf6eccdb6 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -30,6 +30,7 @@ chanrec::chanrec(InspIRCd* Instance) : ServerInstance(Instance) created = topicset = limit = 0; internal_userlist.clear(); memset(&modes,0,64); + age = ServerInstance->Time(true); } void chanrec::SetMode(char mode,bool mode_on) diff --git a/src/inspircd.cpp b/src/inspircd.cpp index dc4986755..cd99e63b6 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -193,6 +193,7 @@ InspIRCd::InspIRCd(int argc, char** argv) this->SNO = new SnomaskManager(this); this->Start(); this->TIME = this->OLDTIME = this->startup_time = time(NULL); + this->time_delta = 0; this->next_call = this->TIME + 3; srand(this->TIME); this->Log(DEBUG,"*** InspIRCd starting up!"); @@ -804,11 +805,21 @@ int InspIRCd::GetModuleCount() return this->ModCount; } -time_t InspIRCd::Time() +time_t InspIRCd::Time(bool delta) { + if (delta) + return TIME + time_delta; return TIME; } +int InspIRCd::SetTimeDelta(int delta) +{ + int old = time_delta; + time_delta += delta; + this->Log(DEBUG, "Time delta set to %d (was %d)", time_delta, old); + return old; +} + bool FileLogger::Readable() { return false; diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp index c53d2a01a..c5c6bc061 100644 --- a/src/modules/m_spanningtree.cpp +++ b/src/modules/m_spanningtree.cpp @@ -1592,7 +1592,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) @@ -2062,7 +2062,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(); @@ -2631,7 +2631,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<std::string> par; par.push_back(prefix); par.push_back(signon); @@ -2691,6 +2691,45 @@ class TreeSocket : public InspSocket return true; } + bool HandleSetTime(const std::string &prefix, std::deque<std::string> ¶ms) + { + if (!params.size()) + 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<std::string> oparams; + oparams.push_back(ConvToStr(us)); + + Utils->DoOneToMany(prefix, "TIMESET", oparams); + } + + return true; + } + bool Time(const std::string &prefix, std::deque<std::string> ¶ms) { // :source.server TIME remote.server sendernick @@ -2703,9 +2742,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(true))); params[0] = prefix; Utils->DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]); } @@ -3078,18 +3115,38 @@ class TreeSocket : public InspSocket { if (params.size()) { - /* 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->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 { - this->Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds, please consider synching your clocks.",abs(delta)); + // 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; @@ -3298,6 +3355,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); @@ -3423,8 +3484,7 @@ class TreeSocket : public InspSocket } else { - if (!prefix.empty()) - Instance->Log(DEBUG,"Command with unknown origin '%s'",prefix.c_str()); + Instance->Log(DEBUG,"Command with unknown origin '%s'",prefix.c_str()); return true; } } @@ -3912,7 +3972,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 { @@ -3924,6 +3996,7 @@ class ModuleSpanningTree : public Module SpanningTreeUtilities* Utils; public: + TimeSyncTimer *SyncTimer; ModuleSpanningTree(InspIRCd* Me) : Module::Module(Me), max_local(0), max_global(0) @@ -3932,6 +4005,9 @@ class ModuleSpanningTree : public Module command_rconnect = new cmd_rconnect(ServerInstance, this, Utils); ServerInstance->AddCommand(command_rconnect); + + SyncTimer = new TimeSyncTimer(ServerInstance, this); + ServerInstance->Timers->AddTimer(SyncTimer); } void ShowLinks(TreeServer* Current, userrec* user, int hops) @@ -4426,6 +4502,13 @@ class ModuleSpanningTree : public Module return 1; } + void BroadcastTimeSync() + { + std::deque<std::string> 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') @@ -5004,7 +5087,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") @@ -5049,6 +5132,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() @@ -5080,6 +5165,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()) @@ -5114,7 +5210,6 @@ Link* SpanningTreeUtilities::FindLink(const std::string& name) return NULL; } - class ModuleSpanningTreeFactory : public ModuleFactory { public: diff --git a/src/users.cpp b/src/users.cpp index a79f0a61d..0b0e5f58b 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -293,6 +293,7 @@ userrec::userrec(InspIRCd* Instance) : ServerInstance(Instance) *password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = 0; server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName); reset_due = ServerInstance->Time(); + age = ServerInstance->Time(true); lines_in = lastping = signon = idle_lastmsg = nping = registered = 0; ChannelCount = timeout = flood = bytes_in = bytes_out = cmds_in = cmds_out = 0; haspassed = dns_done = false; |