diff --git a/include/llarp/path.hpp b/include/llarp/path.hpp index 83d9f0079..8217b5f87 100644 --- a/include/llarp/path.hpp +++ b/include/llarp/path.hpp @@ -326,6 +326,9 @@ namespace llarp RouterID Endpoint() const; + bool + IsEndpoint(const RouterID& router, const PathID_t& path) const; + const PathID_t& RXID() const; @@ -343,6 +346,7 @@ namespace llarp DataHandlerFunc m_DataHandler; DropHandlerFunc m_DropHandler; CheckForDeadFunc m_CheckForDead; + llarp_time_t m_LastRecvMessage = 0; llarp_time_t m_LastLatencyTestTime = 0; uint64_t m_LastLatencyTestID = 0; }; diff --git a/include/llarp/service/Intro.hpp b/include/llarp/service/Intro.hpp index 524ca8f12..f01d992f3 100644 --- a/include/llarp/service/Intro.hpp +++ b/include/llarp/service/Intro.hpp @@ -63,7 +63,9 @@ namespace llarp bool operator<(const Introduction& other) const { - return expiresAt < other.expiresAt || pathID < other.pathID; + return expiresAt < other.expiresAt || pathID < other.pathID + || router < other.router || version < other.version + || latency < other.latency; } bool @@ -79,6 +81,15 @@ namespace llarp { return !(*this == other); } + + struct Hash + { + size_t + operator()(const Introduction& i) const + { + return *i.router.data_l() ^ *i.pathID.data_l(); + } + }; }; } // namespace service } // namespace llarp diff --git a/include/llarp/service/endpoint.hpp b/include/llarp/service/endpoint.hpp index f8280319d..a4942dc8a 100644 --- a/include/llarp/service/endpoint.hpp +++ b/include/llarp/service/endpoint.hpp @@ -194,8 +194,11 @@ namespace llarp ShiftIntroduction(){}; virtual void UpdateIntroSet(){}; - virtual void - MarkCurrentIntroBad(){}; + virtual bool + MarkCurrentIntroBad(llarp_time_t now) + { + return true; + }; private: void @@ -227,14 +230,17 @@ namespace llarp ShiftIntroduction(); /// mark the current remote intro as bad - void - MarkCurrentIntroBad(); + bool + MarkCurrentIntroBad(llarp_time_t now); /// tick internal state /// return true to remove otherwise don't remove bool Tick(llarp_time_t now); + bool + CheckPathIsDead(path::Path* p, llarp_time_t dlt); + void AsyncGenIntro(llarp_buffer_t payload, ProtocolType t); @@ -264,7 +270,8 @@ namespace llarp uint64_t m_UpdateIntrosetTX = 0; IntroSet currentIntroSet; - std::set< Introduction > m_BadIntros; + std::unordered_map< Introduction, llarp_time_t, Introduction::Hash > + m_BadIntros; llarp_time_t lastShift = 0; }; diff --git a/llarp/path.cpp b/llarp/path.cpp index a1d3b9d78..18a8f61d2 100644 --- a/llarp/path.cpp +++ b/llarp/path.cpp @@ -427,7 +427,8 @@ namespace llarp SendRoutingMessage(&latency, r); } // check to see if this path is dead - if(_status == ePathEstablished) + if(_status == ePathEstablished + && (now > m_LastRecvMessage && now - m_LastRecvMessage > 1000)) { if(m_CheckForDead) { @@ -590,7 +591,13 @@ namespace llarp Path::HandleHiddenServiceFrame(const llarp::service::ProtocolFrame* frame) { if(m_DataHandler) - return m_DataHandler(this, frame); + { + if(m_DataHandler(this, frame)) + { + m_LastRecvMessage = llarp_time_now_ms(); + return true; + } + } return false; } diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 6cdbcfc4f..9ab896120 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -722,8 +722,11 @@ namespace llarp { llarp::LogWarn(Name(), " message ", seq, " dropped by endpoint ", p->Endpoint(), " via ", dst); - MarkCurrentIntroBad(); - UpdateIntroSet(); + if(MarkCurrentIntroBad(llarp_time_now_ms())) + llarp::LogInfo(Name(), " switched intros to ", remoteIntro.router, + " via ", remoteIntro.pathID); + else + UpdateIntroSet(); } return true; } @@ -778,7 +781,7 @@ namespace llarp } bool - Endpoint::CheckPathIsDead(path::Path*, llarp_time_t latency) + Endpoint::CheckPathIsDead(path::Path* p, llarp_time_t latency) { if(latency >= m_MinPathLatency) { @@ -985,32 +988,35 @@ namespace llarp return true; } // namespace service - void - Endpoint::OutboundContext::MarkCurrentIntroBad() + bool + Endpoint::OutboundContext::MarkCurrentIntroBad(llarp_time_t now) { - auto now = llarp_time_now_ms(); bool shifted = false; + bool success = false; // insert bad intro - m_BadIntros.insert(remoteIntro); + m_BadIntros.insert(std::make_pair(remoteIntro, now)); // shift off current intro for(const auto& intro : currentIntroSet.I) { - if(m_BadIntros.count(intro) == 0 && !intro.ExpiresSoon(now)) + if(m_BadIntros.find(intro) == m_BadIntros.end() + && !intro.ExpiresSoon(now)) { shifted = intro.router != remoteIntro.router; remoteIntro = intro; + success = true; break; } } // don't rebuild paths rapidly if(now - lastShift < MIN_SHIFT_INTERVAL) - return; + return success; // rebuild path if shifted if(shifted) { lastShift = now; ManualRebuild(1); } + return success; } void @@ -1025,7 +1031,7 @@ namespace llarp m_Endpoint->EnsureRouterIsKnown(intro.router); if(intro.ExpiresSoon(now)) continue; - if(m_BadIntros.count(intro) == 0 && remoteIntro != intro) + if(m_BadIntros.find(intro) == m_BadIntros.end() && remoteIntro != intro) { shifted = intro.router != remoteIntro.router; remoteIntro = intro; @@ -1172,7 +1178,10 @@ namespace llarp auto now = llarp_time_now_ms(); if(remoteIntro.ExpiresSoon(now)) { - MarkCurrentIntroBad(); + if(!MarkCurrentIntroBad(now)) + { + llarp::LogWarn("no good path yet, your message may drop"); + } } routing::PathTransferMessage transfer(msg, remoteIntro.pathID); if(!path->SendRoutingMessage(&transfer, m_Endpoint->Router())) @@ -1220,13 +1229,17 @@ namespace llarp { if(remoteIntro.ExpiresSoon(now)) { - MarkCurrentIntroBad(); + if(!MarkCurrentIntroBad(now)) + { + // TODO: log? + } } - m_Endpoint->EnsureRouterIsKnown(remoteIntro.router); + if(!remoteIntro.router.IsZero()) + m_Endpoint->EnsureRouterIsKnown(remoteIntro.router); auto itr = m_BadIntros.begin(); while(itr != m_BadIntros.end()) { - if(itr->IsExpired(now)) + if(now - itr->second > DEFAULT_PATH_LIFETIME) itr = m_BadIntros.erase(itr); else ++itr; @@ -1294,7 +1307,11 @@ namespace llarp if(remoteIntro.ExpiresSoon(now)) { // shift intro - MarkCurrentIntroBad(); + if(!MarkCurrentIntroBad(now)) + { + llarp::LogError("dropping message, no path after shifting intros"); + return; + } } auto path = m_PathSet->GetNewestPathByRouter(remoteIntro.router);