diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 4ed56f05..30c0e32d 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -234,16 +234,24 @@ namespace client else remoteSession->SetSharedRoutingPath (nullptr); } + m_Owner->AddRoutingSession (remote->GetIdentity ()->GetStandardIdentity ().signingKey - 96, remoteSession); // last 32 bytes + return SendMsg (garlic, outboundTunnel, remoteLease); + } + + bool I2CPDestination::SendMsg (std::shared_ptr garlic, + std::shared_ptr outboundTunnel, std::shared_ptr remoteLease) + { if (remoteLease && outboundTunnel) { - std::vector msgs; - msgs.push_back (i2p::tunnel::TunnelMessageBlock - { - i2p::tunnel::eDeliveryTypeTunnel, - remoteLease->tunnelGateway, remoteLease->tunnelID, - garlic + outboundTunnel->SendTunnelDataMsgs ( + { + i2p::tunnel::TunnelMessageBlock + { + i2p::tunnel::eDeliveryTypeTunnel, + remoteLease->tunnelGateway, remoteLease->tunnelID, + garlic + } }); - outboundTunnel->SendTunnelDataMsgs (msgs); return true; } else @@ -253,9 +261,43 @@ namespace client else LogPrint (eLogWarning, "I2CP: Failed to send message. No outbound tunnels"); return false; + } + } + + bool I2CPDestination::SendMsg (const uint8_t * payload, size_t len, + std::shared_ptr remoteSession, uint32_t nonce) + { + if (!remoteSession) return false; + auto path = remoteSession->GetSharedRoutingPath (); + if (!path) return false; + // get tunnels + std::shared_ptr outboundTunnel; + std::shared_ptr remoteLease; + if (!remoteSession->CleanupUnconfirmedTags ()) // no stuck tags + { + outboundTunnel = path->outboundTunnel; + remoteLease = path->remoteLease; } + else + { + remoteSession->SetSharedRoutingPath (nullptr); + return false; + } + // create Data message + auto msg = m_I2NPMsgsPool.AcquireSharedMt (); + uint8_t * buf = msg->GetPayload (); + htobe32buf (buf, len); + memcpy (buf + 4, payload, len); + msg->len += len + 4; + msg->FillI2NPMessageHeader (eI2NPData); + // wrap in gralic + auto garlic = remoteSession->WrapSingleMessage (msg); + // send + bool sent = SendMsg (garlic, outboundTunnel, remoteLease); + m_Owner->SendMessageStatusMessage (nonce, eI2CPMessageStatusGuaranteedSuccess); + return sent; } - + RunnableI2CPDestination::RunnableI2CPDestination (std::shared_ptr owner, std::shared_ptr identity, bool isPublic, const std::map& params): RunnableService ("I2CP"), @@ -707,6 +749,13 @@ namespace client SendI2CPMessage (I2CP_MESSAGE_STATUS_MESSAGE, buf, 15); } + void I2CPSession::AddRoutingSession (const i2p::data::IdentHash& signingKey, std::shared_ptr remoteSession) + { + if (!remoteSession) return; + std::lock_guard l(m_RoutingSessionsMutex); + m_RoutingSessions[signingKey] = remoteSession; + } + void I2CPSession::CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len) { uint16_t sessionID = bufbe16toh (buf); @@ -777,11 +826,10 @@ namespace client size_t offset = 2; if (m_Destination) { - size_t identSize = i2p::data::GetIdentityBufferLen (buf + offset, len - offset); + const uint8_t * ident = buf + offset; + size_t identSize = i2p::data::GetIdentityBufferLen (ident, len - offset); if (identSize) { - i2p::data::IdentHash identHash; - SHA256(buf + offset, identSize, identHash); // caclulate ident hash, because we don't need full identity offset += identSize; uint32_t payloadLen = bufbe32toh (buf + offset); if (payloadLen + offset <= len) @@ -792,10 +840,30 @@ namespace client { if (m_IsSendAccepted) SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted - m_Destination->SendMsgTo (buf + offset, payloadLen, identHash, nonce); - } + std::shared_ptr remoteSession; + { + std::lock_guard l(m_RoutingSessionsMutex); + auto it = m_RoutingSessions.find (ident + i2p::data::DEFAULT_IDENTITY_SIZE - 35); // 32 bytes signing key + if (it != m_RoutingSessions.end ()) + { + if (!it->second->IsTerminated ()) + remoteSession = it->second; + else + m_RoutingSessions.erase (it); + } + } + if (!remoteSession || !m_Destination->SendMsg (buf + offset, payloadLen, remoteSession, nonce)) + { + i2p::data::IdentHash identHash; + SHA256(ident, identSize, identHash); // caclulate ident hash, because we don't need full identity + m_Destination->SendMsgTo (buf + offset, payloadLen, identHash, nonce); + } + } else + { + LogPrint(eLogInfo, "I2CP: Destination is not ready"); SendMessageStatusMessage (nonce, eI2CPMessageStatusNoLocalTunnels); + } } else LogPrint(eLogError, "I2CP: Cannot send message, too big"); diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 02ec72d9..91d567fb 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -12,8 +12,10 @@ #include #include #include +#include #include #include +#include #include #include "util.h" #include "Destination.h" @@ -92,7 +94,8 @@ namespace client void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession - + bool SendMsg (const uint8_t * payload, size_t len, std::shared_ptr remoteSession, uint32_t nonce); + // implements LocalDestination bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const; bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const; @@ -110,7 +113,9 @@ namespace client std::shared_ptr GetSharedFromThis () { return std::static_pointer_cast(shared_from_this ()); } bool SendMsg (std::shared_ptr msg, std::shared_ptr remote); - + bool SendMsg (std::shared_ptr garlic, + std::shared_ptr outboundTunnel, std::shared_ptr remoteLease); + void PostCreateNewLeaseSet (std::vector > tunnels); private: @@ -157,6 +162,7 @@ namespace client void SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len); void SendMessagePayloadMessage (const uint8_t * payload, size_t len); void SendMessageStatusMessage (uint32_t nonce, I2CPMessageStatus status); + void AddRoutingSession (const i2p::data::IdentHash& signingKey, std::shared_ptr remoteSession); // message handlers void GetDateMessageHandler (const uint8_t * buf, size_t len); @@ -197,6 +203,8 @@ namespace client size_t m_PayloadLen; std::shared_ptr m_Destination; + std::mutex m_RoutingSessionsMutex; + std::unordered_map > m_RoutingSessions; // signing key->session uint16_t m_SessionID; uint32_t m_MessageID; bool m_IsSendAccepted; @@ -226,8 +234,6 @@ namespace client private: - void Run (); - void Accept (); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket);