From 51446f032477cacc4d6b3be25ee6abab746b50ab Mon Sep 17 00:00:00 2001 From: Vlad Solomenchuk Date: Fri, 8 Mar 2024 10:23:51 -0800 Subject: [PATCH 01/29] fix FS::HashedStorage::Init exceptions in ios simulator. --- libi2pd/FS.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index d38bcc2f..a02c0818 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -9,6 +9,11 @@ #include #include +#if defined(MAC_OSX) +#include +#include +#endif + #ifdef _WIN32 #include #include @@ -251,8 +256,22 @@ namespace fs { auto p = root + i2p::fs::dirSep + prefix1 + chars[i]; if (boost::filesystem::exists(p)) continue; - if (boost::filesystem::create_directory(p)) +#ifdef TARGET_OS_SIMULATOR + // ios simulator fs says it is case sensitive, but it is not + boost::system::error_code ec; + if (boost::filesystem::create_directory(p, ec)) + continue; + switch (ec.value()) { + case boost::system::errc::file_exists: + case boost::system::errc::success: + continue; + default: + throw boost::system::system_error( ec, __func__ ); + } +#else + if (boost::filesystem::create_directory(p)) continue; /* ^ throws exception on failure */ +#endif return false; } return true; From 2d06c0cbe6162d7dcc1dc4f685af3e9e60ed1160 Mon Sep 17 00:00:00 2001 From: Vort Date: Sat, 9 Mar 2024 19:05:02 +0200 Subject: [PATCH 02/29] add expiration for messages in SSU2 send queue --- libi2pd/I2NPProtocol.h | 11 ++++++++--- libi2pd/SSU2Session.cpp | 32 ++++++++++++++++++++------------ libi2pd/SSU2Session.h | 1 - 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index b1e2d170..5d5754c8 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -152,6 +152,7 @@ namespace tunnel const size_t I2NP_MAX_MESSAGE_SIZE = 62708; const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096; const size_t I2NP_MAX_MEDIUM_MESSAGE_SIZE = 16384; + const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT = 2000000; // in microseconds const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT) const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds @@ -161,9 +162,10 @@ namespace tunnel size_t len, offset, maxLen; std::shared_ptr from; std::function onDrop; - - I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2), - offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header + uint64_t localExpiration; // monotonic microseconds + + I2NPMessage (): buf (nullptr), len (I2NP_HEADER_SIZE + 2), + offset(2), maxLen (0), from (nullptr), localExpiration(0) {}; // reserve 2 bytes for NTCP header // header accessors uint8_t * GetHeader () { return GetBuffer (); }; @@ -173,6 +175,7 @@ namespace tunnel void SetMsgID (uint32_t msgID) { htobe32buf (GetHeader () + I2NP_HEADER_MSGID_OFFSET, msgID); }; uint32_t GetMsgID () const { return bufbe32toh (GetHeader () + I2NP_HEADER_MSGID_OFFSET); }; void SetExpiration (uint64_t expiration) { htobe64buf (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET, expiration); }; + void SetLocalExpiration (uint64_t expiration) { localExpiration = expiration; }; uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); }; void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); }; uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); }; @@ -264,6 +267,8 @@ namespace tunnel void RenewI2NPMessageHeader (); bool IsExpired () const; bool IsExpired (uint64_t ts) const; // in milliseconds + bool IsLocalExpired (uint64_t mts) const { return mts > localExpiration; }; // monotonic microseconds + bool IsLocalSemiExpired (uint64_t mts) const { return mts > localExpiration - I2NP_MESSAGE_EXPIRATION_TIMEOUT / 2; }; // monotonic microseconds void Drop () { if (onDrop) { onDrop (); onDrop = nullptr; }; } }; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 2c499753..a51b54c4 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -353,25 +353,32 @@ namespace transport void SSU2Session::PostI2NPMessages (std::vector > msgs) { if (m_State == eSSU2SessionStateTerminated) return; - bool isSemiFull = m_SendQueue.size () > SSU2_MAX_OUTGOING_QUEUE_SIZE/2; + uint64_t mts = i2p::util::GetMonotonicMicroseconds (); + uint64_t localExpiration = mts + I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT; + bool isSemiFull = false; + if (m_SendQueue.size ()) + { + isSemiFull = m_SendQueue.front ()->IsLocalSemiExpired (mts); + if (isSemiFull) + { + LogPrint (eLogWarning, "SSU2: Outgoing messages queue to ", + GetIdentHashBase64 (), " is semi-full (", m_SendQueue.size (), ")"); + } + } for (auto it: msgs) + { if (isSemiFull && it->onDrop) it->Drop (); // drop earlier because we can handle it else + { + it->SetLocalExpiration (localExpiration); m_SendQueue.push_back (std::move (it)); + } + } SendQueue (); if (m_SendQueue.size () > 0) // windows is full - { - if (m_SendQueue.size () <= SSU2_MAX_OUTGOING_QUEUE_SIZE) - Resend (i2p::util::GetMillisecondsSinceEpoch ()); - else - { - LogPrint (eLogWarning, "SSU2: Outgoing messages queue size to ", - GetIdentHashBase64(), " exceeds ", SSU2_MAX_OUTGOING_QUEUE_SIZE); - RequestTermination (eSSU2TerminationReasonTimeout); - } - } + Resend (i2p::util::GetMillisecondsSinceEpoch ()); SetSendQueueSize (m_SendQueue.size ()); } @@ -380,6 +387,7 @@ namespace transport if (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { auto ts = i2p::util::GetMillisecondsSinceEpoch (); + uint64_t mts = i2p::util::GetMonotonicMicroseconds (); auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); size_t ackBlockSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); bool ackBlockSent = false; @@ -387,7 +395,7 @@ namespace transport while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { auto msg = m_SendQueue.front (); - if (!msg || msg->IsExpired (ts)) + if (!msg || msg->IsExpired (ts) || msg->IsLocalExpired (mts)) { // drop null or expired message if (msg) msg->Drop (); diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index ed17a6f4..347c3ef9 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -47,7 +47,6 @@ namespace transport const size_t SSU2_MIN_RTO = 100; // in milliseconds const size_t SSU2_MAX_RTO = 2500; // in milliseconds const float SSU2_kAPPA = 1.8; - const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages const int SSU2_MAX_NUM_ACNT = 255; // acnt, acks or nacks const int SSU2_MAX_NUM_ACK_PACKETS = 511; // ackthrough + acnt + 1 range const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send From 217aa0c8827d29220dbf6743dc2127d2e91b999e Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Mar 2024 11:11:38 -0400 Subject: [PATCH 03/29] fixed #2038. don't add comma for missing param --- daemon/I2PControl.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index da2443fd..e2ce7be4 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2022, The PurpleI2P Project +* Copyright (c) 2013-2024, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -338,10 +338,11 @@ namespace client { for (auto it = params.begin (); it != params.end (); it++) { - if (it != params.begin ()) results << ","; LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first); auto it1 = m_RouterManagerHandlers.find (it->first); - if (it1 != m_RouterManagerHandlers.end ()) { + if (it1 != m_RouterManagerHandlers.end ()) + { + if (it != params.begin ()) results << ","; (this->*(it1->second))(results); } else LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first); From 59beb5e4e48fa0ae5d8437be581017f6d21227b8 Mon Sep 17 00:00:00 2001 From: Vlad Solomenchuk Date: Mon, 11 Mar 2024 11:29:41 -0700 Subject: [PATCH 04/29] fix TARGET_OS_SIMULATOR check --- libi2pd/FS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index a02c0818..4d48fc47 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -256,7 +256,7 @@ namespace fs { auto p = root + i2p::fs::dirSep + prefix1 + chars[i]; if (boost::filesystem::exists(p)) continue; -#ifdef TARGET_OS_SIMULATOR +#if TARGET_OS_SIMULATOR // ios simulator fs says it is case sensitive, but it is not boost::system::error_code ec; if (boost::filesystem::create_directory(p, ec)) From 08cc256c54f97c17f469ed9ca9f6c376f8da4907 Mon Sep 17 00:00:00 2001 From: Vort Date: Wed, 13 Mar 2024 16:41:01 +0200 Subject: [PATCH 05/29] fix typo in message expiration check --- libi2pd/I2NPProtocol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 5d5754c8..f38f79ee 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -268,7 +268,7 @@ namespace tunnel bool IsExpired () const; bool IsExpired (uint64_t ts) const; // in milliseconds bool IsLocalExpired (uint64_t mts) const { return mts > localExpiration; }; // monotonic microseconds - bool IsLocalSemiExpired (uint64_t mts) const { return mts > localExpiration - I2NP_MESSAGE_EXPIRATION_TIMEOUT / 2; }; // monotonic microseconds + bool IsLocalSemiExpired (uint64_t mts) const { return mts > localExpiration - I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT / 2; }; // monotonic microseconds void Drop () { if (onDrop) { onDrop (); onDrop = nullptr; }; } }; From 530a078535e304e5b6e759e72835aae5a5203ad9 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Mar 2024 13:56:10 -0400 Subject: [PATCH 06/29] don't request temination if session was not established --- libi2pd/SSU2Session.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index a51b54c4..e2341304 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -294,8 +294,10 @@ namespace transport { m_TerminationReason = reason; SendTermination (); + m_State = eSSU2SessionStateClosing; } - m_State = eSSU2SessionStateClosing; + else + Done (); } void SSU2Session::Established () From 0236769134be393cc2cd5a9dcebf79c02001384d Mon Sep 17 00:00:00 2001 From: Vort Date: Thu, 14 Mar 2024 16:34:40 +0200 Subject: [PATCH 07/29] lower SSU2 resend traffic spikes --- libi2pd/SSU2.h | 4 ++-- libi2pd/SSU2Session.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 60e70e7a..16dd7a20 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -21,8 +21,8 @@ namespace transport { const int SSU2_TERMINATION_CHECK_TIMEOUT = 25; // in seconds const int SSU2_CLEANUP_INTERVAL = 72; // in seconds - const int SSU2_RESEND_CHECK_TIMEOUT = 400; // in milliseconds - const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 100; // in milliseconds + const int SSU2_RESEND_CHECK_TIMEOUT = 40; // in milliseconds + const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 10; // in milliseconds const int SSU2_RESEND_CHECK_MORE_TIMEOUT = 10; // in milliseconds const size_t SSU2_MAX_RESEND_PACKETS = 128; // packets to resend at the time const uint64_t SSU2_SOCKET_MIN_BUFFER_SIZE = 128 * 1024; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index e2341304..7ab34d52 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -537,7 +537,7 @@ namespace transport if (m_SentPackets.empty ()) return 0; std::map > resentPackets; for (auto it = m_SentPackets.begin (); it != m_SentPackets.end (); ) - if (ts >= it->second->sendTime + it->second->numResends*m_RTO) + if (ts >= it->second->sendTime + (it->second->numResends + 1) * m_RTO) { if (it->second->numResends > SSU2_MAX_NUM_RESENDS) { From d74033dd2b7929c2d082f01df665761b4c831266 Mon Sep 17 00:00:00 2001 From: Vort Date: Fri, 15 Mar 2024 09:06:33 +0200 Subject: [PATCH 08/29] tune RTT calculations --- libi2pd/SSU2Session.cpp | 7 +++++-- libi2pd/SSU2Session.h | 7 +++++-- libi2pd/Streaming.cpp | 4 ++-- libi2pd/Streaming.h | 5 +++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 7ab34d52..0d1f9911 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -85,7 +85,7 @@ namespace transport m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0), m_IsDataReceived (false), m_WindowSize (SSU2_MIN_WINDOW_SIZE), - m_RTT (SSU2_RESEND_INTERVAL), m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0), + m_RTT (SSU2_UNKNOWN_RTT), m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0), m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size { @@ -1753,7 +1753,10 @@ namespace transport if (ts > it1->second->sendTime) { auto rtt = ts - it1->second->sendTime; - m_RTT = std::round ((m_RTT*m_SendPacketNum + rtt)/(m_SendPacketNum + 1.0)); + if (m_RTT != SSU2_UNKNOWN_RTT) + m_RTT = SSU2_RTT_EWMA_ALPHA * rtt + (1.0 - SSU2_RTT_EWMA_ALPHA) * m_RTT; + else + m_RTT = rtt; m_RTO = m_RTT*SSU2_kAPPA; if (m_RTO < SSU2_MIN_RTO) m_RTO = SSU2_MIN_RTO; if (m_RTO > SSU2_MAX_RTO) m_RTO = SSU2_MAX_RTO; diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 347c3ef9..6b09f469 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -36,7 +36,6 @@ namespace transport const size_t SSU2_MAX_PACKET_SIZE = 1500; const size_t SSU2_MIN_PACKET_SIZE = 1280; const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in milliseconds - const int SSU2_RESEND_INTERVAL = 300; // in milliseconds const int SSU2_MAX_NUM_RESENDS = 5; const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds const int SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS = 5000; // how many msgID we store for duplicates check @@ -45,7 +44,10 @@ namespace transport const size_t SSU2_MIN_WINDOW_SIZE = 16; // in packets const size_t SSU2_MAX_WINDOW_SIZE = 256; // in packets const size_t SSU2_MIN_RTO = 100; // in milliseconds + const size_t SSU2_INITIAL_RTO = 540; // in milliseconds const size_t SSU2_MAX_RTO = 2500; // in milliseconds + const double SSU2_UNKNOWN_RTT = -1; + const double SSU2_RTT_EWMA_ALPHA = 0.125; const float SSU2_kAPPA = 1.8; const int SSU2_MAX_NUM_ACNT = 255; // acnt, acks or nacks const int SSU2_MAX_NUM_ACK_PACKETS = 511; // ackthrough + acnt + 1 range @@ -356,7 +358,8 @@ namespace transport std::list > m_SendQueue; i2p::I2NPMessagesHandler m_Handler; bool m_IsDataReceived; - size_t m_WindowSize, m_RTT, m_RTO; + double m_RTT; + size_t m_WindowSize, m_RTO; uint32_t m_RelayTag; // between Bob and Charlie OnEstablished m_OnEstablished; // callback from Established boost::asio::deadline_timer m_ConnectTimer; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index f6518163..30fbaf12 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -434,7 +434,7 @@ namespace stream rtt = 1; } if (seqn) - m_RTT = std::round (RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * rtt); + m_RTT = RTT_EWMA_ALPHA * rtt + (1.0 - RTT_EWMA_ALPHA) * m_RTT; else m_RTT = rtt; m_RTO = m_RTT*1.5; // TODO: implement it better @@ -457,7 +457,7 @@ namespace stream if (!seqn && m_RoutingSession) // first message confirmed m_RoutingSession->SetSharedRoutingPath ( std::make_shared ( - i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, m_RTT, 0, 0})); + i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, (int)m_RTT, 0, 0})); } else break; diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 1980b6fd..d67cf37a 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -57,7 +57,7 @@ namespace stream const int MIN_WINDOW_SIZE = 1; const int MAX_WINDOW_SIZE = 128; const int WINDOW_SIZE_DROP_FRACTION = 10; // 1/10 - const double RTT_EWMA_ALPHA = 0.5; + const double RTT_EWMA_ALPHA = 0.125; const int INITIAL_RTT = 8000; // in milliseconds const int INITIAL_RTO = 9000; // in milliseconds const int MIN_SEND_ACK_TIMEOUT = 2; // in milliseconds @@ -254,7 +254,8 @@ namespace stream uint16_t m_Port; SendBufferQueue m_SendBuffer; - int m_WindowSize, m_RTT, m_RTO, m_AckDelay; + double m_RTT; + int m_WindowSize, m_RTO, m_AckDelay; uint64_t m_LastWindowSizeIncreaseTime; int m_NumResendAttempts; size_t m_MTU; From f2085ecc8de1347cf2b91b2b2f63b9d32a018376 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 15 Mar 2024 19:17:25 -0400 Subject: [PATCH 09/29] fixed warning --- libi2pd/SSU2Session.cpp | 6 +++--- libi2pd/Streaming.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 0d1f9911..903b671a 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -84,9 +84,9 @@ namespace transport m_Server (server), m_Address (addr), m_RemoteTransports (0), m_RemotePeerTestTransports (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0), - m_IsDataReceived (false), m_WindowSize (SSU2_MIN_WINDOW_SIZE), - m_RTT (SSU2_UNKNOWN_RTT), m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0), - m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), + m_IsDataReceived (false), m_RTT (SSU2_UNKNOWN_RTT), m_WindowSize (SSU2_MIN_WINDOW_SIZE), + m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0),m_ConnectTimer (server.GetService ()), + m_TerminationReason (eSSU2TerminationReasonNormalClose), m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size { m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 30fbaf12..f91bb552 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -72,7 +72,7 @@ namespace stream m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), - m_WindowSize (MIN_WINDOW_SIZE), m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), + m_RTT (INITIAL_RTT), m_WindowSize (MIN_WINDOW_SIZE), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) { @@ -84,8 +84,8 @@ namespace stream m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), - m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_WindowSize (MIN_WINDOW_SIZE), - m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), + m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), + m_WindowSize (MIN_WINDOW_SIZE), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) { RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); From 161ff3579b41446abefb77f1df714d9a08fde74f Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 15 Mar 2024 20:12:47 -0400 Subject: [PATCH 10/29] don't delete new session with same router hash from sessions-by-hash table --- libi2pd/SSU2.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 812f49d3..a41619d6 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -436,7 +436,11 @@ namespace transport { auto ident = it->second->GetRemoteIdentity (); if (ident) - m_SessionsByRouterHash.erase (ident->GetIdentHash ()); + { + auto it1 = m_SessionsByRouterHash.find (ident->GetIdentHash ()); + if (it1 != m_SessionsByRouterHash.end () && it->second == it1->second) + m_SessionsByRouterHash.erase (it1); + } if (m_LastSession == it->second) m_LastSession = nullptr; m_Sessions.erase (it); From e7ff15c573064395578a5735efb69cf87b4f5f08 Mon Sep 17 00:00:00 2001 From: Vort Date: Sat, 16 Mar 2024 19:29:47 +0200 Subject: [PATCH 11/29] exclude resent stream packets from RTT calculations --- libi2pd/Streaming.cpp | 20 +++++++++++--------- libi2pd/Streaming.h | 3 ++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index f91bb552..aad39db8 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -427,17 +427,18 @@ namespace stream } } auto sentPacket = *it; - uint64_t rtt = ts - sentPacket->sendTime; - if(ts < sentPacket->sendTime) - { - LogPrint(eLogError, "Streaming: Packet ", seqn, "sent from the future, sendTime=", sentPacket->sendTime); - rtt = 1; - } - if (seqn) + int64_t rtt = (int64_t)ts - (int64_t)sentPacket->sendTime; + if (rtt < 0) + LogPrint (eLogError, "Streaming: Packet ", seqn, "sent from the future, sendTime=", sentPacket->sendTime); + bool rttUpdated = true; + if (!seqn) + m_RTT = rtt < 0 ? 1 : rtt; + else if (!sentPacket->resent && rtt >= 0) m_RTT = RTT_EWMA_ALPHA * rtt + (1.0 - RTT_EWMA_ALPHA) * m_RTT; else - m_RTT = rtt; - m_RTO = m_RTT*1.5; // TODO: implement it better + rttUpdated = false; + if (rttUpdated) + m_RTO = m_RTT * 1.5; // TODO: implement it better LogPrint (eLogDebug, "Streaming: Packet ", seqn, " acknowledged rtt=", rtt, " sentTime=", sentPacket->sendTime); m_SentPackets.erase (it++); m_LocalDestination.DeletePacket (sentPacket); @@ -989,6 +990,7 @@ namespace stream { if (ts >= it->sendTime + m_RTO) { + it->resent = true; it->sendTime = ts; packets.push_back (it); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index d67cf37a..9865ba95 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -71,8 +71,9 @@ namespace stream size_t len, offset; uint8_t buf[MAX_PACKET_SIZE]; uint64_t sendTime; + bool resent; - Packet (): len (0), offset (0), sendTime (0) {}; + Packet (): len (0), offset (0), sendTime (0), resent (false) {}; uint8_t * GetBuffer () { return buf + offset; }; size_t GetLength () const { return len - offset; }; From 25592a00b6a1f9af1e97be3856f8d4c9cf3abf3c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 17 Mar 2024 11:42:44 -0400 Subject: [PATCH 12/29] use C++17 for newer versions of clang for BSD --- Makefile.bsd | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.bsd b/Makefile.bsd index 00543193..89229e97 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -6,7 +6,13 @@ CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misl ## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove ## -std=c++11. If you want to remove this variable please do so in a way that allows setting ## custom FLAGS to work at build-time. -NEEDED_CXXFLAGS = -std=c++11 +CXXVER := $(shell $(CXX) -dumpversion) +ifneq ($(shell expr match $(CXX) 'clang'),5) + NEEDED_CXXFLAGS = -std=c++11 +else ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 + NEEDED_CXXFLAGS = -std=c++11 +else # newer versions support C++17 + NEEDED_CXXFLAGS = -std=c++17 DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1 INCFLAGS = -I/usr/include/ -I/usr/local/include/ LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib From 4def0b6ea5001ce9fa8cf7d6a7833596df7ce04a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 17 Mar 2024 11:46:02 -0400 Subject: [PATCH 13/29] use C++17 for newer versions of clang for BSD --- Makefile.bsd | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.bsd b/Makefile.bsd index 89229e97..36a5b3bc 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -13,6 +13,7 @@ else ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 NEEDED_CXXFLAGS = -std=c++11 else # newer versions support C++17 NEEDED_CXXFLAGS = -std=c++17 +endif DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1 INCFLAGS = -I/usr/include/ -I/usr/local/include/ LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib From b2aa34baa6480831bbd4b0f9c1f9e51b79667a83 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 17 Mar 2024 11:49:14 -0400 Subject: [PATCH 14/29] use C++17 for newer versions of clang for BSD --- Makefile.bsd | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile.bsd b/Makefile.bsd index 36a5b3bc..14449381 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -7,9 +7,7 @@ CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misl ## -std=c++11. If you want to remove this variable please do so in a way that allows setting ## custom FLAGS to work at build-time. CXXVER := $(shell $(CXX) -dumpversion) -ifneq ($(shell expr match $(CXX) 'clang'),5) - NEEDED_CXXFLAGS = -std=c++11 -else ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 +ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1 NEEDED_CXXFLAGS = -std=c++11 else # newer versions support C++17 NEEDED_CXXFLAGS = -std=c++17 From cf77be0eeb403155a1b3c440f3709add13e6f001 Mon Sep 17 00:00:00 2001 From: Vort Date: Tue, 19 Mar 2024 06:37:21 +0200 Subject: [PATCH 15/29] add lower limit for stream RTO --- libi2pd/Streaming.cpp | 4 ++-- libi2pd/Streaming.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index aad39db8..bc165478 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -438,7 +438,7 @@ namespace stream else rttUpdated = false; if (rttUpdated) - m_RTO = m_RTT * 1.5; // TODO: implement it better + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5)); // TODO: implement it better LogPrint (eLogDebug, "Streaming: Packet ", seqn, " acknowledged rtt=", rtt, " sentTime=", sentPacket->sendTime); m_SentPackets.erase (it++); m_LocalDestination.DeletePacket (sentPacket); @@ -882,7 +882,7 @@ namespace stream m_CurrentOutboundTunnel = routingPath->outboundTunnel; m_CurrentRemoteLease = routingPath->remoteLease; m_RTT = routingPath->rtt; - m_RTO = m_RTT*1.5; // TODO: implement it better + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5)); // TODO: implement it better } } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 9865ba95..35f642bc 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -58,6 +58,7 @@ namespace stream const int MAX_WINDOW_SIZE = 128; const int WINDOW_SIZE_DROP_FRACTION = 10; // 1/10 const double RTT_EWMA_ALPHA = 0.125; + const int MIN_RTO = 20; // in milliseconds const int INITIAL_RTT = 8000; // in milliseconds const int INITIAL_RTO = 9000; // in milliseconds const int MIN_SEND_ACK_TIMEOUT = 2; // in milliseconds From 83f0b9c0418d6f96950dd7f2c85505b77d360b58 Mon Sep 17 00:00:00 2001 From: Vort Date: Tue, 19 Mar 2024 08:28:34 +0200 Subject: [PATCH 16/29] extract single RTT sample from stream ACK --- libi2pd/Streaming.cpp | 50 +++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index bc165478..a190f1fb 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -404,6 +404,8 @@ namespace stream LogPrint (eLogError, "Streaming: Unexpected ackThrough=", ackThrough, " > seqn=", m_SequenceNumber); return; } + int rttSample = INT_MAX; + bool firstRttSample = false; int nackCount = packet->GetNACKCount (); for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();) { @@ -430,39 +432,45 @@ namespace stream int64_t rtt = (int64_t)ts - (int64_t)sentPacket->sendTime; if (rtt < 0) LogPrint (eLogError, "Streaming: Packet ", seqn, "sent from the future, sendTime=", sentPacket->sendTime); - bool rttUpdated = true; if (!seqn) - m_RTT = rtt < 0 ? 1 : rtt; + { + firstRttSample = true; + rttSample = rtt < 0 ? 1 : rtt; + } else if (!sentPacket->resent && rtt >= 0) - m_RTT = RTT_EWMA_ALPHA * rtt + (1.0 - RTT_EWMA_ALPHA) * m_RTT; - else - rttUpdated = false; - if (rttUpdated) - m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5)); // TODO: implement it better + rttSample = std::min (rttSample, (int)rtt); LogPrint (eLogDebug, "Streaming: Packet ", seqn, " acknowledged rtt=", rtt, " sentTime=", sentPacket->sendTime); m_SentPackets.erase (it++); m_LocalDestination.DeletePacket (sentPacket); acknowledged = true; if (m_WindowSize < WINDOW_SIZE) m_WindowSize++; // slow start - else - { - // linear growth - if (ts > m_LastWindowSizeIncreaseTime + m_RTT) - { - m_WindowSize++; - if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; - m_LastWindowSizeIncreaseTime = ts; - } - } - if (!seqn && m_RoutingSession) // first message confirmed - m_RoutingSession->SetSharedRoutingPath ( - std::make_shared ( - i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, (int)m_RTT, 0, 0})); } else break; } + if (rttSample != INT_MAX) + { + if (firstRttSample) + m_RTT = rttSample; + else + m_RTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_RTT; + m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5)); // TODO: implement it better + } + if (acknowledged && m_WindowSize >= WINDOW_SIZE) + { + // linear growth + if (ts > m_LastWindowSizeIncreaseTime + m_RTT) + { + m_WindowSize++; + if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; + m_LastWindowSizeIncreaseTime = ts; + } + } + if (firstRttSample && m_RoutingSession) + m_RoutingSession->SetSharedRoutingPath ( + std::make_shared ( + i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, (int)m_RTT, 0, 0})); if (m_SentPackets.empty ()) m_ResendTimer.cancel (); if (acknowledged) From 4f8f3a386f6d278f598d65327c789dc008dd1299 Mon Sep 17 00:00:00 2001 From: Vort Date: Tue, 19 Mar 2024 08:43:49 +0200 Subject: [PATCH 17/29] restart stream resend timer after updating initial RTO --- libi2pd/Streaming.cpp | 13 ++++++++++--- libi2pd/Streaming.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index a190f1fb..575d5b5c 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -68,7 +68,8 @@ namespace stream Stream::Stream (boost::asio::io_service& service, StreamingDestination& local, std::shared_ptr remote, int port): m_Service (service), - m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), + m_SendStreamID (0), m_SequenceNumber (0), + m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), @@ -81,7 +82,8 @@ namespace stream } Stream::Stream (boost::asio::io_service& service, StreamingDestination& local): - m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), + m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), + m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), @@ -437,7 +439,7 @@ namespace stream firstRttSample = true; rttSample = rtt < 0 ? 1 : rtt; } - else if (!sentPacket->resent && rtt >= 0) + else if (!sentPacket->resent && seqn > m_TunnelsChangeSequenceNumber && rtt >= 0) rttSample = std::min (rttSample, (int)rtt); LogPrint (eLogDebug, "Streaming: Packet ", seqn, " acknowledged rtt=", rtt, " sentTime=", sentPacket->sendTime); m_SentPackets.erase (it++); @@ -455,7 +457,10 @@ namespace stream m_RTT = rttSample; else m_RTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_RTT; + bool wasInitial = m_RTO == INITIAL_RTO; m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5)); // TODO: implement it better + if (wasInitial) + ScheduleResend (); } if (acknowledged && m_WindowSize >= WINDOW_SIZE) { @@ -1016,6 +1021,7 @@ namespace stream if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; break; case 2: + m_TunnelsChangeSequenceNumber = m_SequenceNumber; m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time #if (__cplusplus >= 201703L) // C++ 17 or higher [[fallthrough]]; @@ -1028,6 +1034,7 @@ namespace stream break; case 3: // pick another outbound tunnel + m_TunnelsChangeSequenceNumber = m_SequenceNumber; if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); LogPrint (eLogWarning, "Streaming: Another outbound tunnel has been selected for stream with sSID=", m_SendStreamID); diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 35f642bc..7e12b8cb 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -238,6 +238,7 @@ namespace stream boost::asio::io_service& m_Service; uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber; + uint32_t m_TunnelsChangeSequenceNumber; int32_t m_LastReceivedSequenceNumber; StreamStatus m_Status; bool m_IsAckSendScheduled; From a703d318939a3430e0d4e5c8205379ae288524cc Mon Sep 17 00:00:00 2001 From: Vort Date: Tue, 19 Mar 2024 10:48:42 +0200 Subject: [PATCH 18/29] don't double initial RTO --- libi2pd/Streaming.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 575d5b5c..322285c3 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1013,7 +1013,8 @@ namespace stream if (packets.size () > 0) { m_NumResendAttempts++; - m_RTO *= 2; + if (m_RTO != INITIAL_RTO) + m_RTO *= 2; switch (m_NumResendAttempts) { case 1: // congestion avoidance From a30d1972e553ee64163b42af3221f43ab0bf925a Mon Sep 17 00:00:00 2001 From: r4sas Date: Fri, 22 Mar 2024 23:18:32 +0300 Subject: [PATCH 19/29] [win] update status code Signed-off-by: r4sas --- Win32/Win32App.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index 9f750c4c..742ad30d 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2022, The PurpleI2P Project +* Copyright (c) 2013-2024, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -145,7 +145,7 @@ namespace win32 s << bytes << " Bytes\n"; } - static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing) + static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing, RouterError error) { switch (status) { @@ -158,18 +158,24 @@ namespace win32 }; if (testing) s << " (Test)"; - if (i2p::context.GetError () != eRouterErrorNone) + if (error != eRouterErrorNone) { - switch (i2p::context.GetError ()) + switch (error) { case eRouterErrorClockSkew: - s << " - Clock skew"; + s << " - " << tr("Clock skew"); break; case eRouterErrorOffline: - s << " - Offline"; + s << " - " << tr("Offline"); break; case eRouterErrorSymmetricNAT: - s << " - Symmetric NAT"; + s << " - " << tr("Symmetric NAT"); + break; + case eRouterErrorFullConeNAT: + s << " - " << tr("Full cone NAT"); + break; + case eRouterErrorNoDescriptors: + s << " - " << tr("No Descriptors"); break; default: ; } @@ -180,11 +186,11 @@ namespace win32 { s << "\n"; s << "Status: "; - ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting ()); + ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting(), i2p::context.GetError ()); if (i2p::context.SupportsV6 ()) { s << " / "; - ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6 ()); + ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6(), i2p::context.GetErrorV6 ()); } s << "; "; s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n"; From ac9d92c681996e87c2db9da73a2920b934045f97 Mon Sep 17 00:00:00 2001 From: Vort Date: Tue, 26 Mar 2024 09:41:49 +0200 Subject: [PATCH 20/29] select maximum SSU2 queue size depending on RTT value --- libi2pd/I2NPProtocol.h | 13 +++++++------ libi2pd/SSU2Session.cpp | 20 ++++++++++++++------ libi2pd/SSU2Session.h | 2 ++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index f38f79ee..f110100e 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -152,7 +152,9 @@ namespace tunnel const size_t I2NP_MAX_MESSAGE_SIZE = 62708; const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096; const size_t I2NP_MAX_MEDIUM_MESSAGE_SIZE = 16384; - const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT = 2000000; // in microseconds + const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_FACTOR = 3; // multiples of RTT + const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MIN = 200000; // in microseconds + const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX = 2000000; // in microseconds const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT) const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds @@ -162,10 +164,10 @@ namespace tunnel size_t len, offset, maxLen; std::shared_ptr from; std::function onDrop; - uint64_t localExpiration; // monotonic microseconds + uint64_t enqueueTime; // monotonic microseconds I2NPMessage (): buf (nullptr), len (I2NP_HEADER_SIZE + 2), - offset(2), maxLen (0), from (nullptr), localExpiration(0) {}; // reserve 2 bytes for NTCP header + offset(2), maxLen (0), from (nullptr), enqueueTime (0) {}; // reserve 2 bytes for NTCP header // header accessors uint8_t * GetHeader () { return GetBuffer (); }; @@ -175,8 +177,9 @@ namespace tunnel void SetMsgID (uint32_t msgID) { htobe32buf (GetHeader () + I2NP_HEADER_MSGID_OFFSET, msgID); }; uint32_t GetMsgID () const { return bufbe32toh (GetHeader () + I2NP_HEADER_MSGID_OFFSET); }; void SetExpiration (uint64_t expiration) { htobe64buf (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET, expiration); }; - void SetLocalExpiration (uint64_t expiration) { localExpiration = expiration; }; + void SetEnqueueTime (uint64_t mts) { enqueueTime = mts; }; uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); }; + uint64_t GetEnqueueTime () const { return enqueueTime; }; void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); }; uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); }; void UpdateSize () { SetSize (GetPayloadLength ()); }; @@ -267,8 +270,6 @@ namespace tunnel void RenewI2NPMessageHeader (); bool IsExpired () const; bool IsExpired (uint64_t ts) const; // in milliseconds - bool IsLocalExpired (uint64_t mts) const { return mts > localExpiration; }; // monotonic microseconds - bool IsLocalSemiExpired (uint64_t mts) const { return mts > localExpiration - I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT / 2; }; // monotonic microseconds void Drop () { if (onDrop) { onDrop (); onDrop = nullptr; }; } }; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 903b671a..42a26c5c 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -84,7 +84,10 @@ namespace transport m_Server (server), m_Address (addr), m_RemoteTransports (0), m_RemotePeerTestTransports (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0), - m_IsDataReceived (false), m_RTT (SSU2_UNKNOWN_RTT), m_WindowSize (SSU2_MIN_WINDOW_SIZE), + m_IsDataReceived (false), m_RTT (SSU2_UNKNOWN_RTT), + m_MsgLocalExpirationTimeout (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX), + m_MsgLocalSemiExpirationTimeout (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX / 2), + m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0),m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size @@ -356,15 +359,16 @@ namespace transport { if (m_State == eSSU2SessionStateTerminated) return; uint64_t mts = i2p::util::GetMonotonicMicroseconds (); - uint64_t localExpiration = mts + I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT; bool isSemiFull = false; if (m_SendQueue.size ()) { - isSemiFull = m_SendQueue.front ()->IsLocalSemiExpired (mts); + int64_t queueLag = (int64_t)mts - (int64_t)m_SendQueue.front ()->GetEnqueueTime (); + isSemiFull = queueLag > m_MsgLocalSemiExpirationTimeout; if (isSemiFull) { LogPrint (eLogWarning, "SSU2: Outgoing messages queue to ", - GetIdentHashBase64 (), " is semi-full (", m_SendQueue.size (), ")"); + i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), + " is semi-full (size = ", m_SendQueue.size (), ", lag = ", queueLag / 1000, ", rtt = ", (int)m_RTT, ")"); } } for (auto it: msgs) @@ -373,7 +377,7 @@ namespace transport it->Drop (); // drop earlier because we can handle it else { - it->SetLocalExpiration (localExpiration); + it->SetEnqueueTime (mts); m_SendQueue.push_back (std::move (it)); } } @@ -397,7 +401,7 @@ namespace transport while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) { auto msg = m_SendQueue.front (); - if (!msg || msg->IsExpired (ts) || msg->IsLocalExpired (mts)) + if (!msg || msg->IsExpired (ts) || msg->GetEnqueueTime() + m_MsgLocalExpirationTimeout < mts) { // drop null or expired message if (msg) msg->Drop (); @@ -1758,6 +1762,10 @@ namespace transport else m_RTT = rtt; m_RTO = m_RTT*SSU2_kAPPA; + m_MsgLocalExpirationTimeout = std::max (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MIN, + std::min (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX, + (unsigned int)(m_RTT * 1000 * I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_FACTOR))); + m_MsgLocalSemiExpirationTimeout = m_MsgLocalExpirationTimeout / 2; if (m_RTO < SSU2_MIN_RTO) m_RTO = SSU2_MIN_RTO; if (m_RTO > SSU2_MAX_RTO) m_RTO = SSU2_MAX_RTO; } diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h index 6b09f469..6505b233 100644 --- a/libi2pd/SSU2Session.h +++ b/libi2pd/SSU2Session.h @@ -359,6 +359,8 @@ namespace transport i2p::I2NPMessagesHandler m_Handler; bool m_IsDataReceived; double m_RTT; + int m_MsgLocalExpirationTimeout; + int m_MsgLocalSemiExpirationTimeout; size_t m_WindowSize, m_RTO; uint32_t m_RelayTag; // between Bob and Charlie OnEstablished m_OnEstablished; // callback from Established From 85be76b01a6a37460a6868bd6a5ce75e58820be4 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 1 Apr 2024 08:41:58 -0400 Subject: [PATCH 21/29] check if LeaseSet was submitted recently. Fixed typo --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 2 +- libi2pd/Garlic.cpp | 4 ++-- libi2pd/Garlic.h | 2 +- libi2pd/Streaming.cpp | 14 +++++++++----- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index b4730d0e..a51f047e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -863,7 +863,7 @@ namespace garlic payloadLen += msg->GetPayloadLength () + 13; if (m_Destination) payloadLen += 32; } - if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT) + if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASESET_CONFIRMATION_TIMEOUT) { // resubmit non-confirmed LeaseSet SetLeaseSetUpdateStatus (eLeaseSetUpdated); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index dd66af60..d5ea6730 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -80,7 +80,7 @@ namespace garlic void GarlicRoutingSession::CleanupUnconfirmedLeaseSet (uint64_t ts) { - if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT) + if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASESET_CONFIRMATION_TIMEOUT) { if (GetOwner ()) GetOwner ()->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); @@ -232,7 +232,7 @@ namespace garlic if (GetOwner ()) { // resubmit non-confirmed LeaseSet - if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT) + if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASESET_CONFIRMATION_TIMEOUT) { SetLeaseSetUpdateStatus (eLeaseSetUpdated); SetSharedRoutingPath (nullptr); // invalidate path since leaseset was not confirmed diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 83e3b050..2c40f74a 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -50,7 +50,7 @@ namespace garlic const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds - const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds + const int LEASESET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 322285c3..ab4b6e48 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -950,10 +950,10 @@ namespace stream if (m_RoutingSession->IsLeaseSetNonConfirmed ()) { auto ts = i2p::util::GetMillisecondsSinceEpoch (); - if (ts > m_RoutingSession->GetLeaseSetSubmissionTime () + i2p::garlic::LEASET_CONFIRMATION_TIMEOUT) + if (ts > m_RoutingSession->GetLeaseSetSubmissionTime () + i2p::garlic::LEASESET_CONFIRMATION_TIMEOUT) { // LeaseSet was not confirmed, should try other tunnels - LogPrint (eLogWarning, "Streaming: LeaseSet was not confirmed in ", i2p::garlic::LEASET_CONFIRMATION_TIMEOUT, " milliseconds. Trying to resubmit"); + LogPrint (eLogWarning, "Streaming: LeaseSet was not confirmed in ", i2p::garlic::LEASESET_CONFIRMATION_TIMEOUT, " milliseconds. Trying to resubmit"); m_RoutingSession->SetSharedRoutingPath (nullptr); m_CurrentOutboundTunnel = nullptr; m_CurrentRemoteLease = nullptr; @@ -1074,9 +1074,13 @@ namespace stream { if (m_RoutingSession && m_RoutingSession->IsLeaseSetNonConfirmed ()) { - // seems something went wrong and we should re-select tunnels - m_CurrentOutboundTunnel = nullptr; - m_CurrentRemoteLease = nullptr; + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + if (ts > m_RoutingSession->GetLeaseSetSubmissionTime () + i2p::garlic::LEASESET_CONFIRMATION_TIMEOUT) + { + // seems something went wrong and we should re-select tunnels + m_CurrentOutboundTunnel = nullptr; + m_CurrentRemoteLease = nullptr; + } } SendQuickAck (); } From 75df8d3c7bc843082c5dffa82553f1342b831a50 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 2 Apr 2024 11:30:38 -0400 Subject: [PATCH 22/29] drop ack Through to last packet if Number of NACKs exceeds 255 --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index ab4b6e48..eeff2767 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -702,7 +702,7 @@ namespace stream if (numNacks + (seqn - nextSeqn) >= 256) { LogPrint (eLogError, "Streaming: Number of NACKs exceeds 256. seqn=", seqn, " nextSeqn=", nextSeqn); - htobe32buf (packet + 12, nextSeqn); // change ack Through + htobe32buf (packet + 12, nextSeqn - 1); // change ack Through back break; } for (uint32_t i = nextSeqn; i < seqn; i++) From 4f1cb74f755cbc3b880e5e9547a74215afaa3077 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 2 Apr 2024 18:49:16 -0400 Subject: [PATCH 23/29] request choking delay if too many NACKs. Drop window size to 1 if choking delay received --- libi2pd/Streaming.cpp | 17 ++++++++++++++--- libi2pd/Streaming.h | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index eeff2767..b53cce0a 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -289,6 +289,8 @@ namespace stream m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer, shared_from_this (), std::placeholders::_1)); } + if (delayRequested >= DELAY_CHOKING) + m_WindowSize = 1; } optionData += 2; } @@ -691,6 +693,7 @@ namespace stream htobe32buf (packet + size, lastReceivedSeqn); size += 4; // ack Through uint8_t numNacks = 0; + bool choking = false; if (lastReceivedSeqn > m_LastReceivedSequenceNumber) { // fill NACKs @@ -703,6 +706,7 @@ namespace stream { LogPrint (eLogError, "Streaming: Number of NACKs exceeds 256. seqn=", seqn, " nextSeqn=", nextSeqn); htobe32buf (packet + 12, nextSeqn - 1); // change ack Through back + choking = true; break; } for (uint32_t i = nextSeqn; i < seqn; i++) @@ -724,10 +728,17 @@ namespace stream size++; // NACK count } packet[size] = 0; - size++; // resend delay - htobuf16 (packet + size, 0); // no flags set + size++; // resend delay + htobuf16 (packet + size, choking ? PACKET_FLAG_DELAY_REQUESTED : 0); // no flags set or delay size += 2; // flags - htobuf16 (packet + size, 0); // no options + if (choking) + { + htobuf16 (packet + size, 2); // 2 bytes delay interval + htobuf16 (packet + size + 2, DELAY_CHOKING); // set choking interval + size += 2; + } + else + htobuf16 (packet + size, 0); // no options size += 2; // options size p.len = size; diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 7e12b8cb..7a521002 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -66,6 +66,7 @@ namespace stream const size_t MAX_PENDING_INCOMING_BACKLOG = 128; const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int MAX_RECEIVE_TIMEOUT = 20; // in seconds + const uint16_t DELAY_CHOKING = 60000; // in milliseconds struct Packet { From c49dd712debfe492356ddc68308fbaf950835ffc Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 6 Apr 2024 08:53:54 -0400 Subject: [PATCH 24/29] 2.51.0 --- ChangeLog | 61 +++++++++++++++++++++++++++++++++++++++ contrib/rpm/i2pd-git.spec | 5 +++- contrib/rpm/i2pd.spec | 5 +++- debian/changelog | 6 ++++ libi2pd/version.h | 6 ++-- 5 files changed, 78 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6534a9b5..d898a86b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,67 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.51.0] - 2024-04-06 +### Added +- Non-blocking mode for UDP sockets +- Set SSU2 socket buffer size based on bandwidth limit +- Encrypted tunnel tests +- Support for multiple UDP server tunnels on one destination +- Publish medium congestion indication +- Local domain sockets for SOCKS proxy upstream +- Tunnel status "declined" in web console +- SAM error reply "Incompatible crypto" if remote destination has incompatible crypto +- Reduce amount of traffic by handling local message drops +- Keep SSU2 socket open even if it fails to bind +- Lower SSU2 resend traffic spikes +- Expiration for messages in SSU2 send queue +- Use EWMA for stream RTT estimation +- Request choking delay if too many NACKs in stream +- Allow 0ms latency for tunnel +- Randomize tunnels selection for tests +### Changed +- Upstream SOCKS proxy from SOCKS4 to SOCKS5 +- Transit tunnels limit to 4 bytes. Default value to 10K +- Reply CANT_REACH_PEER if connect to ourselves in SAM +- Don't send already expired I2NP messages +- Use monotonic timer to measure tunnel test latency +- Standard NTCP2 frame doesn't exceed 16K +- Always send request through tunnels in case of restricted routes +- Don't delete connected routers from NetDb +- Send lookup reply directly to reply tunnel gateway if possible +- Reduce unreachable router ban interval to 8 minutes +- Don't request banned routers / don't try to connect to unreachable router +- Consider 'M' routers as low bandwidth +- Limit minimal received SSU2 packet size to 40 bytes +- Bob picks peer test session only if Charlie's address supports peer testing +- Reject peer test msg 2 if peer testing is not supported +- Don't request termination if SSU2 session was not established +- Set maximum SSU2 queue size depending on RTT value +- New streaming RTT calculation algorithm +- Don't double initial RTO for streams when changing tunnels +- Restore failed tunnel if test or data for inbound tunnel received +- Don't fail last remaining tunnel in pool +- Publish LeasetSet again if local destination was not ready or no tunnels +- Make more attempts to pick high bandwidth hop for client tunnel +- Reduced SSU2 session termination timeout to 165 seconds +- Reseeds list +### Fixed +- ECIESx25519 symmetric key tagset early expiration +- Encrypted LeaseSet lookup +- Outbound tunnel build fails if it's endpoint is the same as reply tunnel gateway +- I2PControl RouterManager returns invalid JSON when unknown params are passed +- Mix of data between different UDP sessions on the same server +- TARGET_OS_SIMULATOR check +- Handling of "reservedrange" param +- New NTCP2 session gets teminated upon termination of old one +- New SSU2 session gets teminated upon termination of old one +- Peer test to non-supporting router +- Streaming ackThrough off 1 if number of NACKs exceeds 255 +- Race condition in ECIESx25519 tags table +- Good tunnel becomes failed +- Crash when packet comes to terminated stream +- Stream hangs during LeaseSet update + ## [2.50.2] - 2024-01-06 ###Fixed - Crash with OpenSSL 3.2.0 diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 0bc46eab..e43d751b 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.50.2 +Version: 2.51.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -144,6 +144,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Sat Apr 06 2024 orignal - 2.51.0 +- update to 2.51.0 + * Sat Jan 06 2024 orignal - 2.50.2 - update to 2.50.2 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 1de4076e..9e270708 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.50.2 +Version: 2.51.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -142,6 +142,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Sat Apr 06 2024 orignal - 2.51.0 +- update to 2.51.0 + * Sat Jan 06 2024 orignal - 2.50.2 - update to 2.50.2 diff --git a/debian/changelog b/debian/changelog index 56ab7c16..da9606b4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.51.0-1) unstable; urgency=medium + + * updated to version 2.51.0/0.9.62 + + -- orignal Sat, 06 Apr 2024 16:00:00 +0000 + i2pd (2.50.2) unstable; urgency=medium * updated to version 2.50.2/0.9.61 diff --git a/libi2pd/version.h b/libi2pd/version.h index 7b9e20c8..e05e6f3a 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -18,8 +18,8 @@ #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 50 -#define I2PD_VERSION_MICRO 2 +#define I2PD_VERSION_MINOR 51 +#define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #ifdef GITVER #define I2PD_VERSION XSTRINGIZE(GITVER) @@ -33,7 +33,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 61 +#define I2P_VERSION_MICRO 62 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) From 89064b6fb483cb59d350c6b671c2e590e89b5990 Mon Sep 17 00:00:00 2001 From: r4sas Date: Sat, 6 Apr 2024 20:03:16 +0000 Subject: [PATCH 25/29] 2.51.0 Signed-off-by: r4sas --- ChangeLog | 12 ++++++------ debian/changelog | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index d898a86b..f7be41ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,7 +6,7 @@ - Non-blocking mode for UDP sockets - Set SSU2 socket buffer size based on bandwidth limit - Encrypted tunnel tests -- Support for multiple UDP server tunnels on one destination +- Support for multiple UDP server tunnels on one destination - Publish medium congestion indication - Local domain sockets for SOCKS proxy upstream - Tunnel status "declined" in web console @@ -21,7 +21,7 @@ - Randomize tunnels selection for tests ### Changed - Upstream SOCKS proxy from SOCKS4 to SOCKS5 -- Transit tunnels limit to 4 bytes. Default value to 10K +- Transit tunnels limit to 4 bytes. Default value to 10K - Reply CANT_REACH_PEER if connect to ourselves in SAM - Don't send already expired I2NP messages - Use monotonic timer to measure tunnel test latency @@ -34,8 +34,8 @@ - Consider 'M' routers as low bandwidth - Limit minimal received SSU2 packet size to 40 bytes - Bob picks peer test session only if Charlie's address supports peer testing -- Reject peer test msg 2 if peer testing is not supported -- Don't request termination if SSU2 session was not established +- Reject peer test msg 2 if peer testing is not supported +- Don't request termination if SSU2 session was not established - Set maximum SSU2 queue size depending on RTT value - New streaming RTT calculation algorithm - Don't double initial RTO for streams when changing tunnels @@ -48,10 +48,10 @@ ### Fixed - ECIESx25519 symmetric key tagset early expiration - Encrypted LeaseSet lookup -- Outbound tunnel build fails if it's endpoint is the same as reply tunnel gateway +- Outbound tunnel build fails if it's endpoint is the same as reply tunnel gateway - I2PControl RouterManager returns invalid JSON when unknown params are passed - Mix of data between different UDP sessions on the same server -- TARGET_OS_SIMULATOR check +- TARGET_OS_SIMULATOR check - Handling of "reservedrange" param - New NTCP2 session gets teminated upon termination of old one - New SSU2 session gets teminated upon termination of old one diff --git a/debian/changelog b/debian/changelog index da9606b4..9a410c14 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,11 +4,11 @@ i2pd (2.51.0-1) unstable; urgency=medium -- orignal Sat, 06 Apr 2024 16:00:00 +0000 -i2pd (2.50.2) unstable; urgency=medium +i2pd (2.50.2-1) unstable; urgency=medium * updated to version 2.50.2/0.9.61 --- orignal Sat, 06 Jan 2024 16:00:00 +0000 + -- orignal Sat, 06 Jan 2024 16:00:00 +0000 i2pd (2.50.1-1) unstable; urgency=medium From 1b5f67e185428305a9989dd821fd74f53abe70e5 Mon Sep 17 00:00:00 2001 From: r4sas Date: Sat, 6 Apr 2024 20:38:58 +0000 Subject: [PATCH 26/29] [FS] misc: bump year Signed-off-by: r4sas --- libi2pd/FS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index 4d48fc47..233f5766 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2022, The PurpleI2P Project +* Copyright (c) 2013-2024, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * From df3dc1f5741b60119d76d9f28d6516a9a5ac6ec9 Mon Sep 17 00:00:00 2001 From: Vort Date: Sun, 7 Apr 2024 16:47:06 +0300 Subject: [PATCH 27/29] change tunnels during stream resend attempts 5 and 6 --- libi2pd/Streaming.cpp | 45 ++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index b53cce0a..f76b0821 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1024,34 +1024,31 @@ namespace stream if (packets.size () > 0) { m_NumResendAttempts++; - if (m_RTO != INITIAL_RTO) + if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO) + { + // congestion avoidance m_RTO *= 2; - switch (m_NumResendAttempts) + m_WindowSize -= (m_WindowSize + WINDOW_SIZE_DROP_FRACTION) / WINDOW_SIZE_DROP_FRACTION; // adjustment >= 1 + if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; + } + else { - case 1: // congestion avoidance - m_WindowSize -= (m_WindowSize + WINDOW_SIZE_DROP_FRACTION) / WINDOW_SIZE_DROP_FRACTION; // adjustment >= 1 - if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; - break; - case 2: - m_TunnelsChangeSequenceNumber = m_SequenceNumber; - m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time -#if (__cplusplus >= 201703L) // C++ 17 or higher - [[fallthrough]]; -#endif - // no break here - case 4: - if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); - UpdateCurrentRemoteLease (); // pick another lease - LogPrint (eLogWarning, "Streaming: Another remote lease has been selected for stream with rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); - break; - case 3: + m_TunnelsChangeSequenceNumber = m_SequenceNumber; + m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change + if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); + if (m_NumResendAttempts & 1) + { // pick another outbound tunnel - m_TunnelsChangeSequenceNumber = m_SequenceNumber; - if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); - LogPrint (eLogWarning, "Streaming: Another outbound tunnel has been selected for stream with sSID=", m_SendStreamID); - break; - default: ; + LogPrint (eLogWarning, "Streaming: Resend #", m_NumResendAttempts, + ", another outbound tunnel has been selected for stream with sSID=", m_SendStreamID); + } + else + { + UpdateCurrentRemoteLease (); // pick another lease + LogPrint (eLogWarning, "Streaming: Resend #", m_NumResendAttempts, + ", another remote lease has been selected for stream with rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); + } } SendPackets (packets); } From 57e46ba0cf7ccf3ed72a8da0b6fb4e2f49f6366c Mon Sep 17 00:00:00 2001 From: Vort Date: Sun, 7 Apr 2024 21:24:56 +0300 Subject: [PATCH 28/29] reset stream RTO if outbound tunnel was changed --- libi2pd/Streaming.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index f76b0821..14fc6407 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -916,20 +916,32 @@ namespace stream UpdateCurrentRemoteLease (true); if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD) { + bool freshTunnel = false; if (!m_CurrentOutboundTunnel) { auto leaseRouter = i2p::data::netdb.FindRouter (m_CurrentRemoteLease->tunnelGateway); m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (nullptr, leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports); + freshTunnel = true; } else if (!m_CurrentOutboundTunnel->IsEstablished ()) + { + auto oldOutboundTunnel = m_CurrentOutboundTunnel; m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel); + if (m_CurrentOutboundTunnel && oldOutboundTunnel->GetEndpointIdentHash() != m_CurrentOutboundTunnel->GetEndpointIdentHash()) + freshTunnel = true; + } if (!m_CurrentOutboundTunnel) { LogPrint (eLogError, "Streaming: No outbound tunnels in the pool, sSID=", m_SendStreamID); m_CurrentRemoteLease = nullptr; return; } + if (freshTunnel) + { + m_RTO = INITIAL_RTO; + m_TunnelsChangeSequenceNumber = m_SequenceNumber; // should be determined more precisely + } std::vector msgs; for (const auto& it: packets) From b2e21a4f1213e7b0d6a58e0125b76337754b0adf Mon Sep 17 00:00:00 2001 From: Vort Date: Mon, 8 Apr 2024 12:35:50 +0300 Subject: [PATCH 29/29] increase maximum stream resend attempts to 9 --- libi2pd/Streaming.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 7a521002..e27deb9c 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -52,7 +52,7 @@ namespace stream const size_t STREAMING_MTU_RATCHETS = 1812; const size_t MAX_PACKET_SIZE = 4096; const size_t COMPRESSION_THRESHOLD_SIZE = 66; - const int MAX_NUM_RESEND_ATTEMPTS = 6; + const int MAX_NUM_RESEND_ATTEMPTS = 9; const int WINDOW_SIZE = 6; // in messages const int MIN_WINDOW_SIZE = 1; const int MAX_WINDOW_SIZE = 128;