diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 0d626234..b6f6d131 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -426,7 +426,8 @@ namespace garlic } GarlicDestination::GarlicDestination (): m_NumTags (32), // 32 tags by default - m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0) // 0 means standard + m_PayloadBuffer (nullptr), m_LastIncomingSessionTimestamp (0), + m_NumRatchetInboundTags (0) // 0 means standard { } @@ -539,9 +540,17 @@ namespace garlic else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) { // otherwise ECIESx25519 - auto session = std::make_shared (this, false); // incoming - if (!session->HandleNextMessage (buf, length, nullptr, 0)) - LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + if (ts > m_LastIncomingSessionTimestamp + INCOMING_SESSIONS_MINIMAL_INTERVAL) + { + auto session = std::make_shared (this, false); // incoming + if (session->HandleNextMessage (buf, length, nullptr, 0)) + m_LastIncomingSessionTimestamp = ts; + else + LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); + } + else + LogPrint (eLogWarning, "Garlic: Incoming sessions come too ofter"); } else LogPrint (eLogError, "Garlic: Failed to decrypt message"); @@ -737,7 +746,8 @@ namespace garlic } std::shared_ptr GarlicDestination::GetRoutingSession ( - std::shared_ptr destination, bool attachLeaseSet) + std::shared_ptr destination, bool attachLeaseSet, + bool requestNewIfNotFound) { if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) @@ -752,15 +762,16 @@ namespace garlic if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ())) { LogPrint (eLogDebug, "Garlic: Session restarted"); + requestNewIfNotFound = true; // it's not a new session session = nullptr; } } - if (!session) + if (!session && requestNewIfNotFound) { session = std::make_shared (this, true); session->SetRemoteStaticKey (staticKey); } - if (destination->IsDestination ()) + if (session && destination->IsDestination ()) session->SetDestination (destination->GetIdentHash ()); // NS or NSR return session; } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 80fc15da..57c3fddc 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -52,6 +52,7 @@ namespace garlic const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds const int LEASESET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds const int ROUTING_PATH_EXPIRATION_TIMEOUT = 120; // in seconds + const int INCOMING_SESSIONS_MINIMAL_INTERVAL = 200; // in milliseconds struct SessionTag: public i2p::data::Tag<32> { @@ -234,7 +235,8 @@ namespace garlic int GetNumTags () const { return m_NumTags; }; void SetNumRatchetInboundTags (int numTags) { m_NumRatchetInboundTags = numTags; }; int GetNumRatchetInboundTags () const { return m_NumRatchetInboundTags; }; - std::shared_ptr GetRoutingSession (std::shared_ptr destination, bool attachLeaseSet); + std::shared_ptr GetRoutingSession (std::shared_ptr destination, + bool attachLeaseSet, bool requestNewIfNotFound = true); void CleanupExpiredTags (); void RemoveDeliveryStatusSession (uint32_t msgID); std::shared_ptr WrapMessageForRouter (std::shared_ptr router, @@ -284,6 +286,7 @@ namespace garlic std::unordered_map m_Sessions; std::unordered_map, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session uint8_t * m_PayloadBuffer; // for ECIESX25519AEADRatchet + uint64_t m_LastIncomingSessionTimestamp; // in millseconds // incoming int m_NumRatchetInboundTags; std::unordered_map, std::hash > > m_Tags; diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 206f8197..3187f895 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -757,8 +757,8 @@ namespace stream if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());; if (m_RemoteLeaseSet) { - m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true); - m_MTU = m_RoutingSession->IsRatchets () ? STREAMING_MTU_RATCHETS : STREAMING_MTU; + m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming); + m_MTU = (m_RoutingSession && m_RoutingSession->IsRatchets ()) ? STREAMING_MTU_RATCHETS : STREAMING_MTU; } uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED | PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED; @@ -1115,7 +1115,15 @@ namespace stream } } if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ()) // expired and detached or new session sent - m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true); + { + m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true, !m_IsIncoming); + if (!m_RoutingSession) + { + LogPrint (eLogError, "Streaming: Can't obtain routing session, sSID=", m_SendStreamID); + Terminate (); + return; + } + } if (!m_CurrentOutboundTunnel && m_RoutingSession) // first message to send { // try to get shared path first @@ -1416,7 +1424,13 @@ namespace stream SendPackets (packets); m_LastSendTime = ts; m_IsSendTime = false; - if (m_IsNAcked || m_IsResendNeeded) ScheduleSend (); + if (m_IsNAcked || m_IsResendNeeded) + { + if (m_SequenceNumber > 1) // doesn't resend agressively very first packet + ScheduleSend (); + else + ScheduleResend (); + } } else SendBuffer ();