diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 64e5d085..35bad171 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -367,9 +367,11 @@ namespace client HandleDataMessage (payload, len); break; case eI2NPDeliveryStatus: - // try tunnel test first - if (!m_Pool || !m_Pool->ProcessDeliveryStatus (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET), bufbe64toh (payload + DELIVERY_STATUS_TIMESTAMP_OFFSET))) - HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET)); + HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET)); + break; + case eI2NPTunnelTest: + if (m_Pool) + m_Pool->ProcessTunnelTest (bufbe32toh (payload + TUNNEL_TEST_MSGID_OFFSET), bufbe64toh (payload + TUNNEL_TEST_TIMESTAMP_OFFSET)); break; case eI2NPDatabaseStore: HandleDatabaseStoreMessage (payload, len); diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index da6da638..e687f39c 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -115,6 +115,17 @@ namespace i2p return newMsg; } + std::shared_ptr CreateTunnelTestMsg (uint32_t msgID) + { + auto m = NewI2NPShortMessage (); + uint8_t * buf = m->GetPayload (); + htobe32buf (buf + TUNNEL_TEST_MSGID_OFFSET, msgID); + htobe64buf (buf + TUNNEL_TEST_TIMESTAMP_OFFSET, i2p::util::GetSteadyMicroseconds ()); + m->len += TUNNEL_TEST_SIZE; + m->FillI2NPMessageHeader (eI2NPTunnelTest); + return m; + } + std::shared_ptr CreateDeliveryStatusMsg (uint32_t msgID) { auto m = NewI2NPShortMessage (); @@ -870,6 +881,10 @@ namespace i2p i2p::context.ProcessDeliveryStatusMessage (msg); break; } + case eI2NPTunnelTest: + if (msg->from && msg->from->GetTunnelPool ()) + msg->from->GetTunnelPool ()->ProcessTunnelTest (msg); + break; case eI2NPVariableTunnelBuild: case eI2NPTunnelBuild: case eI2NPShortTunnelBuild: diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 36facbe3..b1e2d170 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -48,6 +48,11 @@ namespace i2p const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4; const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8; + // TunnelTest + const size_t TUNNEL_TEST_MSGID_OFFSET = 0; + const size_t TUNNEL_TEST_TIMESTAMP_OFFSET = TUNNEL_TEST_MSGID_OFFSET + 4; + const size_t TUNNEL_TEST_SIZE = TUNNEL_TEST_TIMESTAMP_OFFSET + 8; + // DatabaseStore const size_t DATABASE_STORE_KEY_OFFSET = 0; const size_t DATABASE_STORE_TYPE_OFFSET = DATABASE_STORE_KEY_OFFSET + 32; @@ -116,7 +121,8 @@ namespace i2p eI2NPVariableTunnelBuild = 23, eI2NPVariableTunnelBuildReply = 24, eI2NPShortTunnelBuild = 25, - eI2NPShortTunnelBuildReply = 26 + eI2NPShortTunnelBuildReply = 26, + eI2NPTunnelTest = 231 }; const uint8_t TUNNEL_BUILD_RECORD_GATEWAY_FLAG = 0x80; @@ -279,6 +285,7 @@ namespace tunnel std::shared_ptr CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from = nullptr); std::shared_ptr CopyI2NPMessage (std::shared_ptr msg); + std::shared_ptr CreateTunnelTestMsg (uint32_t msgID); std::shared_ptr CreateDeliveryStatusMsg (uint32_t msgID); std::shared_ptr CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID, bool exploratory = false, std::set * excludedPeers = nullptr); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 2c1dc979..bf683b8e 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1152,13 +1152,13 @@ namespace i2p bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) { - if (typeID == eI2NPDeliveryStatus) + if (typeID == eI2NPTunnelTest) { // try tunnel test auto pool = GetTunnelPool (); - if (pool && pool->ProcessDeliveryStatus (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET), bufbe64toh (payload + DELIVERY_STATUS_TIMESTAMP_OFFSET))) + if (pool && pool->ProcessTunnelTest (bufbe32toh (payload + TUNNEL_TEST_MSGID_OFFSET), bufbe64toh (payload + TUNNEL_TEST_TIMESTAMP_OFFSET))) return true; - } + } auto msg = CreateI2NPMessage (typeID, payload, len, msgID); if (!msg) return false; i2p::HandleI2NPMessage (msg); diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp index 99507398..27e3a619 100644 --- a/libi2pd/Timestamp.cpp +++ b/libi2pd/Timestamp.cpp @@ -232,6 +232,12 @@ namespace util return GetLocalHoursSinceEpoch () + g_TimeOffset/3600; } + uint64_t GetSteadyMicroseconds() + { + return std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()).count(); + } + void GetCurrentDate (char * date) { GetDateString (GetSecondsSinceEpoch (), date); diff --git a/libi2pd/Timestamp.h b/libi2pd/Timestamp.h index ff777257..6a925079 100644 --- a/libi2pd/Timestamp.h +++ b/libi2pd/Timestamp.h @@ -24,6 +24,8 @@ namespace util uint32_t GetMinutesSinceEpoch (); uint32_t GetHoursSinceEpoch (); + uint64_t GetSteadyMicroseconds(); + void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes void GetDateString (uint64_t timestamp, char * date); // timestamp is seconds since epoch, returns date as YYYYMMDD string, 9 bytes void AdjustTimeOffset (int64_t offset); // in seconds from current diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index 6311b4f2..f9369672 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -109,9 +109,9 @@ namespace tunnel void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out) override; /** @brief add latency sample */ - void AddLatencySample(const int ms) { m_Latency = LatencyIsKnown() ? (m_Latency + ms) >> 1 : ms; } + void AddLatencySample(const int us) { m_Latency = LatencyIsKnown() ? (m_Latency + us) >> 1 : us; } /** @brief get this tunnel's estimated latency */ - int GetMeanLatency() const { return m_Latency; } + int GetMeanLatency() const { return (m_Latency + 500) / 1000; } /** @brief return true if this tunnel's latency fits in range [lowerbound, upperbound] */ bool LatencyFitsRange(int lowerbound, int upperbound) const; @@ -130,7 +130,7 @@ namespace tunnel TunnelState m_State; i2p::data::RouterInfo::CompatibleTransports m_FarEndTransports; bool m_IsRecreated; // if tunnel is replaced by new, or new tunnel requested to replace - int m_Latency; // in milliseconds + int m_Latency; // in microseconds }; class OutboundTunnel: public Tunnel diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index f576b62d..4f93ce52 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -399,7 +399,7 @@ namespace tunnel std::unique_lock l(m_TestsMutex); m_Tests[msgID] = it; } - auto msg = CreateDeliveryStatusMsg (msgID); + auto msg = CreateTunnelTestMsg (msgID); auto outbound = it.first; auto s = shared_from_this (); msg->onDrop = [msgID, outbound, s]() @@ -452,16 +452,23 @@ namespace tunnel buf += 4; uint64_t timestamp = bufbe64toh (buf); - if (!ProcessDeliveryStatus (msgID, timestamp)) - { - if (m_LocalDestination) - m_LocalDestination->ProcessDeliveryStatusMessage (msg); - else - LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped"); - } + if (m_LocalDestination) + m_LocalDestination->ProcessDeliveryStatusMessage (msg); + else + LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped"); + } + + void TunnelPool::ProcessTunnelTest (std::shared_ptr msg) + { + const uint8_t * buf = msg->GetPayload (); + uint32_t msgID = bufbe32toh (buf); + buf += 4; + uint64_t timestamp = bufbe64toh (buf); + + ProcessTunnelTest (msgID, timestamp); } - bool TunnelPool::ProcessDeliveryStatus (uint32_t msgID, uint64_t timestamp) + bool TunnelPool::ProcessTunnelTest (uint32_t msgID, uint64_t timestamp) { decltype(m_Tests)::mapped_type test; bool found = false; @@ -477,9 +484,9 @@ namespace tunnel } if (found) { - int dlt = (int)((int64_t)i2p::util::GetMillisecondsSinceEpoch () - (int64_t)timestamp); - LogPrint (eLogDebug, "Tunnels: Test of ", msgID, " successful. ", dlt, " milliseconds"); - if (dlt < 0) + int dlt = (int)((int64_t)i2p::util::GetSteadyMicroseconds () - (int64_t)timestamp); + LogPrint (eLogDebug, "Tunnels: Test of ", msgID, " successful. ", dlt, " microseconds"); + if (dlt < 0) // should not happen dlt = 0; int numHops = 0; if (test.first) numHops += test.first->GetNumHops (); @@ -493,7 +500,7 @@ namespace tunnel int latency = 0; if (numHops) latency = dlt*test.first->GetNumHops ()/numHops; if (!latency) latency = dlt/2; - test.first->AddLatencySample(latency); + test.first->AddLatencySample (latency); } if (test.second) { @@ -503,7 +510,7 @@ namespace tunnel int latency = 0; if (numHops) latency = dlt*test.second->GetNumHops ()/numHops; if (!latency) latency = dlt/2; - test.second->AddLatencySample(latency); + test.second->AddLatencySample (latency); } } return found; diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index da48378c..e76453be 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -85,7 +85,8 @@ namespace tunnel void ManageTunnels (uint64_t ts); void ProcessGarlicMessage (std::shared_ptr msg); void ProcessDeliveryStatus (std::shared_ptr msg); - bool ProcessDeliveryStatus (uint32_t msgID, uint64_t timestamp); + void ProcessTunnelTest (std::shared_ptr msg); + bool ProcessTunnelTest (uint32_t msgID, uint64_t timestamp); bool IsExploratory () const; bool IsActive () const { return m_IsActive; };