connect to peer. send handshake

This commit is contained in:
orignal
2026-07-12 11:49:43 -04:00
parent d30ff0e11a
commit e8420b422c
2 changed files with 115 additions and 13 deletions
+92 -10
View File
@@ -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<i2p::stream::Stream> 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<i2p::stream::Stream> stream, std::shared_ptr<Torrent> 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<TorrentsTunnel *>(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<i2p::client::ClientDestination> 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<Torrent>(std::string_view{buf, len}));
auto torrent = std::make_shared<Torrent>(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<Torrent> 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> torrent,
std::shared_ptr<const i2p::client::Address> peer)
{
if (!torrent && !peer) return;
CreateStream ([this, torrent](std::shared_ptr<i2p::stream::Stream> stream)
{
if (stream)
{
auto connection = std::make_shared<PeerConnection>(this, stream, torrent);
AddHandler (connection);
connection->Connect ();
}
else
LogPrint (eLogInfo, "Torrents: Can't connect to peer");
}, peer, 6881);
}
}
}
+23 -3
View File
@@ -16,6 +16,7 @@
#include <vector>
#include <array>
#include <list>
#include <map>
#include <string>
#include <string_view>
#include "Streaming.h"
@@ -57,14 +58,19 @@ namespace torrents
{
public:
using InfoHash = std::array<uint8_t, 20>;
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<Piece> m_Pieces;
std::list<std::pair<std::string, std::shared_ptr<const i2p::client::Address> > > m_Peers;
};
class TorrentsTunnel;
class PeerConnection: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<PeerConnection>
{
public:
PeerConnection (i2p::client::I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream);
PeerConnection (i2p::client::I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream); // incoming
PeerConnection (i2p::client::I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<Torrent> 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<i2p::stream::Stream> m_Stream;
uint8_t m_ReceiveBuffer[PEER_CONNECTION_RECEIVE_BUFFER_SIZE];
size_t m_ReceiveBufferOffset;
std::shared_ptr<Torrent> 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<Torrent> FindTorrent (const Torrent::InfoHash& infoHash) const;
void ConnectToPeer (std::shared_ptr<Torrent> torrent, std::shared_ptr<const i2p::client::Address> 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<std::shared_ptr<Torrent> > m_Torrents;
std::map<Torrent::InfoHash, std::shared_ptr<Torrent> > m_Torrents;
};
}
}