mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2026-08-28 05:14:25 +00:00
connect to peer. send handshake
This commit is contained in:
+92
-10
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user