From e8420b422c2a689ff69151a726e0d56ffbeca375 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 12 Jul 2026 11:49:43 -0400 Subject: [PATCH] connect to peer. send handshake --- libi2pd_client/Torrents.cpp | 102 ++++++++++++++++++++++++++++++++---- libi2pd_client/Torrents.h | 26 +++++++-- 2 files changed, 115 insertions(+), 13 deletions(-) diff --git a/libi2pd_client/Torrents.cpp b/libi2pd_client/Torrents.cpp index cddfe340..5d689836 100644 --- a/libi2pd_client/Torrents.cpp +++ b/libi2pd_client/Torrents.cpp @@ -218,25 +218,29 @@ namespace torrents }); if (!len) return 0; // calculate info hash - uint8_t digest[SHA_DIGEST_LENGTH]; - SHA1 ((const uint8_t *)buf.data (), len, digest); - // convert info hash to hex chars - BIGNUM * bn = BN_bin2bn (digest, SHA_DIGEST_LENGTH, nullptr); + SHA1 ((const uint8_t *)buf.data (), len, m_InfoHash.data ()); + return len; + } + + std::string Torrent::GetHexStraingInfoHash () const + { + std::string infoHash; + BIGNUM * bn = BN_bin2bn (m_InfoHash.data (), SHA_DIGEST_LENGTH, nullptr); char * str = BN_bn2hex (bn); if (str) { - m_InfoHash = str; + infoHash = str; OPENSSL_free (str); } BN_free (bn); - return len; + return infoHash; } i2p::http::HTTPReq Torrent::GetTrackerRequest () const { i2p::http::HTTPReq req; req.parse (m_Announce); - req.AddHeader ("info_hash", m_InfoHash); + req.AddHeader ("info_hash", GetHexStraingInfoHash ()); return req; } @@ -288,10 +292,18 @@ namespace torrents } PeerConnection::PeerConnection (i2p::client::I2PService * owner, std::shared_ptr stream): - i2p::client::I2PServiceHandler (owner), m_Stream (stream), m_ReceiveBufferOffset (0) + i2p::client::I2PServiceHandler (owner), m_Stream (stream), m_ReceiveBufferOffset (0), + m_IsHandshakeSent (false) { } + PeerConnection::PeerConnection (i2p::client::I2PService * owner, + std::shared_ptr stream, std::shared_ptr torrent): + PeerConnection (owner, stream) + { + m_Torrent = torrent; + } + void PeerConnection::Terminate () { if (Kill()) return; @@ -303,6 +315,16 @@ namespace torrents Done(shared_from_this ()); } + TorrentsTunnel * PeerConnection::GetTorrentsTunnel () const + { + return static_cast(GetOwner ()); + } + + void PeerConnection::Connect () + { + SendHandshakeMsg (); + } + void PeerConnection::ReceiveHandshake () { StreamReceive (); @@ -395,11 +417,45 @@ namespace torrents Terminate (); return 0; } + if (GetTorrentsTunnel ()) + { + Torrent::InfoHash infoHash; + memcpy (infoHash.data (), m_ReceiveBuffer + 28, 20); + m_Torrent = GetTorrentsTunnel ()->FindTorrent (infoHash); + } + if (!m_Torrent) + { + LogPrint (eLogError, "Torrents: Torrent with InfoHash not found"); + Terminate (); + return 0; + } m_RemotePeerID = std::string_view ((const char *)(m_ReceiveBuffer + 48), 20); - // TODO:: send reply + SendHandshakeMsg (); return HANDSHAKE_MSG_LENGTH; } + void PeerConnection::SendHandshakeMsg () + { + if (m_IsHandshakeSent || !m_Torrent || !m_Stream || !m_Stream->IsOpen ()) return; + uint8_t buf[HANDSHAKE_MSG_LENGTH]; + buf[0] = 19; memcpy (buf + 1, "BitTorrent protocol", 19); + memset (buf + 20, 0, 8); + memcpy (buf + 28, m_Torrent->GetInfoHash ().data (), 20); + memset (buf + 48, '0', 20); + if (GetTorrentsTunnel ()) + { + const auto& peerID = GetTorrentsTunnel ()->GetPeerID (); + size_t len = peerID.length (); if (len > 20) len = 20; + memcpy (buf + 48, peerID.data (), len); + } + m_Stream->AsyncSend (buf, HANDSHAKE_MSG_LENGTH, + [s = shared_from_this ()](const boost::system::error_code& ecode) + { + if (ecode) s->Terminate (); + }); + m_IsHandshakeSent = true; + } + TorrentsTunnel::TorrentsTunnel (std::shared_ptr localDestination, std::string_view torrentsDir): i2p::client::I2PService (localDestination), m_TorrentsDir (torrentsDir), m_PeerID ("-I2PD-") @@ -450,8 +506,9 @@ namespace torrents s.seekg(0, std::ios::beg); char * buf = new char[len]; s.read(buf, len); - m_Torrents.emplace_back (std::make_shared(std::string_view{buf, len})); + auto torrent = std::make_shared(std::string_view{buf, len}); delete[] buf; + m_Torrents.emplace (torrent->GetInfoHash (), torrent); } else LogPrint (eLogError, "Torrents: Empty file ", path); @@ -460,6 +517,14 @@ namespace torrents LogPrint (eLogError, "Torrents: Can't open file ", path); } + std::shared_ptr TorrentsTunnel::FindTorrent (const Torrent::InfoHash& infoHash) const + { + auto it = m_Torrents.find (infoHash); + if (it != m_Torrents.end ()) + return it->second; + return nullptr; + } + void TorrentsTunnel::Accept () { auto localDestination = GetLocalDestination (); @@ -579,5 +644,22 @@ namespace torrents } torrent->ParseTrackerResponse (response.substr (headersLen, contentLen)); } + + void TorrentsTunnel::ConnectToPeer (std::shared_ptr torrent, + std::shared_ptr peer) + { + if (!torrent && !peer) return; + CreateStream ([this, torrent](std::shared_ptr stream) + { + if (stream) + { + auto connection = std::make_shared(this, stream, torrent); + AddHandler (connection); + connection->Connect (); + } + else + LogPrint (eLogInfo, "Torrents: Can't connect to peer"); + }, peer, 6881); + } } } diff --git a/libi2pd_client/Torrents.h b/libi2pd_client/Torrents.h index 6cb3ffc3..75635026 100644 --- a/libi2pd_client/Torrents.h +++ b/libi2pd_client/Torrents.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include "Streaming.h" @@ -57,14 +58,19 @@ namespace torrents { public: + using InfoHash = std::array; + Torrent (std::string_view buf); i2p::http::HTTPReq GetTrackerRequest () const; void ParseTrackerResponse (std::string_view buf); const std::string& GetName () const { return m_Name; } + const InfoHash& GetInfoHash () const { return m_InfoHash; } private: + std::string GetHexStraingInfoHash () const; + size_t ParsePieces (std::string_view buf); size_t ParseInfo (std::string_view buf); size_t ParsePeers (std::string_view buf); @@ -72,37 +78,47 @@ namespace torrents private: - std::string m_Name, m_Announce, m_InfoHash; // 40 hex chars + std::string m_Name, m_Announce; size_t m_Length, m_PieceLength; int m_Interval; + InfoHash m_InfoHash; // SHA1 std::vector m_Pieces; std::list > > m_Peers; }; + class TorrentsTunnel; class PeerConnection: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this { public: - PeerConnection (i2p::client::I2PService * owner, std::shared_ptr stream); + PeerConnection (i2p::client::I2PService * owner, std::shared_ptr stream); // incoming + PeerConnection (i2p::client::I2PService * owner, std::shared_ptr stream, + std::shared_ptr torrent); // outgoing + void Connect (); void ReceiveHandshake (); private: void Terminate (); + TorrentsTunnel * GetTorrentsTunnel () const; + void StreamReceive (); void HandleStreamReceive (const boost::system::error_code& ecode, size_t bytes_transferred); void HandleReceived (); size_t HandleNextMsg (size_t offset); size_t HandleHandshakeMsg (); + void SendHandshakeMsg (); private: std::shared_ptr m_Stream; uint8_t m_ReceiveBuffer[PEER_CONNECTION_RECEIVE_BUFFER_SIZE]; size_t m_ReceiveBufferOffset; + std::shared_ptr m_Torrent; std::string m_RemotePeerID; + bool m_IsHandshakeSent; }; class TorrentsTunnel: public i2p::client::I2PService @@ -116,6 +132,10 @@ namespace torrents void Start () override; void Stop () override; + const std::string& GetPeerID () const { return m_PeerID; } + std::shared_ptr FindTorrent (const Torrent::InfoHash& infoHash) const; + void ConnectToPeer (std::shared_ptr torrent, std::shared_ptr peer); + const char* GetName() const override { return "Torrents"; } private: @@ -132,7 +152,7 @@ namespace torrents private: std::string m_TorrentsDir, m_PeerID; // 20 characters - std::list > m_Torrents; + std::map > m_Torrents; }; } }