mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2026-10-05 20:57:48 +00:00
handle get_peers response
This commit is contained in:
@@ -17,6 +17,15 @@ namespace i2p
|
||||
{
|
||||
namespace torrents
|
||||
{
|
||||
NodeInfo Node::GetNodeInfo () const
|
||||
{
|
||||
NodeInfo nodeInfo;
|
||||
memcpy (nodeInfo.data (), id.data (), id.size ());
|
||||
memcpy (nodeInfo.data () + id.size (), peer, peer.len);
|
||||
htobe16buf (nodeInfo.data () + nodeInfo.size () - 2, port);
|
||||
return nodeInfo;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Bucket::FindNode (const NodeID& id) const
|
||||
{
|
||||
auto it = std::find_if (nodes.begin (), nodes.end (),
|
||||
@@ -138,6 +147,13 @@ namespace torrents
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> RoutingTable::FindNode (const NodeID& id) const
|
||||
{
|
||||
auto bucket = FindBucket (id);
|
||||
if (!bucket) return nullptr;
|
||||
return bucket->FindNode (id);
|
||||
}
|
||||
|
||||
std::list<std::pair<std::shared_ptr<Node>, Distance> > RoutingTable::FindClosestNodes (const Torrent::InfoHash& infoHash, size_t num) const
|
||||
{
|
||||
std::list<std::pair<std::shared_ptr<Node>, Distance> > ret;
|
||||
@@ -176,6 +192,12 @@ namespace torrents
|
||||
m_IncomingGetPeers.emplace (token, node);
|
||||
}
|
||||
|
||||
void DHTTorrent::AddOutgoingGetPeerNode (GetPeersToken token, std::shared_ptr<Node> node)
|
||||
{
|
||||
if (!node) return;
|
||||
m_OutgoingGetPeers.emplace (token, node);
|
||||
}
|
||||
|
||||
TorrentsDHT::TorrentsDHT (TorrentsTunnel& tunnel, uint16_t port):
|
||||
m_Tunnel (tunnel), m_Port (port)
|
||||
{
|
||||
@@ -185,9 +207,7 @@ namespace torrents
|
||||
memcpy (m_NodeID.data (), dest->GetIdentHash (), m_NodeID.size ());
|
||||
m_NodeID[4] ^= (port >> 8);
|
||||
m_NodeID[5] ^= (port & 0xFF);
|
||||
memcpy (m_NodeInfo.data (), m_NodeID.data (), m_NodeID.size ());
|
||||
memcpy (m_NodeInfo.data () + m_NodeID.size (), dest->GetIdentHash (), i2p::data::IdentHash::len);
|
||||
htobe16buf (m_NodeInfo.data () + m_NodeInfo.size () - 2, port);
|
||||
m_NodeInfo = Node (m_NodeID, dest->GetIdentHash (), port).GetNodeInfo ();
|
||||
m_RoutingTable = std::make_unique<RoutingTable> (m_NodeID);
|
||||
}
|
||||
else
|
||||
@@ -224,8 +244,10 @@ namespace torrents
|
||||
// response or error
|
||||
char type = 0;
|
||||
std::string transactionID, id;
|
||||
uint64_t token = 0;
|
||||
std::vector<std::string_view> values;
|
||||
ParseDictionary (std::string_view ((const char *)buf, len),
|
||||
[&type, &transactionID, &id](std::string_view key, std::string_view buf)->size_t
|
||||
[&type, &transactionID, &id, &values, &token](std::string_view key, std::string_view buf)->size_t
|
||||
{
|
||||
if (key == "y")
|
||||
{
|
||||
@@ -239,10 +261,17 @@ namespace torrents
|
||||
if (l) transactionID = value;
|
||||
return l;
|
||||
}
|
||||
else if (key == "token")
|
||||
{
|
||||
auto [value, l] = ExtractByteString (buf);
|
||||
if (l && value.size () <= 8)
|
||||
memcpy (&token, value.data (), 8);
|
||||
return l;
|
||||
}
|
||||
else if (key == "r")
|
||||
{
|
||||
return ParseDictionary (buf,
|
||||
[&id](std::string_view key, std::string_view buf)->size_t
|
||||
[&id, &values](std::string_view key, std::string_view buf)->size_t
|
||||
{
|
||||
if (key == "id")
|
||||
{
|
||||
@@ -250,6 +279,12 @@ namespace torrents
|
||||
if (l) id = value;
|
||||
return l;
|
||||
}
|
||||
else if (key == "values")
|
||||
{
|
||||
auto [v, l] = ParseStringList (buf);
|
||||
if (l) values = v;
|
||||
return l;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
@@ -260,7 +295,7 @@ namespace torrents
|
||||
switch (type)
|
||||
{
|
||||
case 'r':
|
||||
HandleResponse (transactionID, id);
|
||||
HandleResponse (transactionID, id, token, values);
|
||||
break;
|
||||
case 'e':
|
||||
LogPrint (eLogDebug, "TorrentsDHT: Error msg received");
|
||||
@@ -374,9 +409,19 @@ namespace torrents
|
||||
it->second->AddIncomingGetPeerNode (token, node);
|
||||
SendGetPeersResponse (transactionID, it->second, token, fromIdent, fromPort + 1); // to rport
|
||||
}
|
||||
else if (m_RoutingTable)
|
||||
{
|
||||
auto nodes = m_RoutingTable->FindClosestNodes (hash);
|
||||
if (!nodes.empty ())
|
||||
{
|
||||
uint64_t token = m_Tunnel.GetLocalDestination () ? m_Tunnel.GetLocalDestination ()->GetRng ()() : 1;
|
||||
SendGetPeersResponse (transactionID, nodes.front ().first, token, fromIdent, fromPort + 1); // to rport
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentsDHT::HandleResponse (std::string_view transactionID, std::string_view id)
|
||||
void TorrentsDHT::HandleResponse (std::string_view transactionID, std::string_view id,
|
||||
uint64_t token, const std::vector<std::string_view>& values)
|
||||
{
|
||||
LogPrint (eLogDebug, "TorrentsDHT: Response msg received");
|
||||
uint16_t t = 0;
|
||||
@@ -385,20 +430,46 @@ namespace torrents
|
||||
auto it = m_Queries.find (t);
|
||||
if (t && it != m_Queries.end ())
|
||||
{
|
||||
// assume ping for now
|
||||
if (id.size () < NodeID::len)
|
||||
{
|
||||
LogPrint (eLogInfo, "TorrentsDHT: received id is too short ", id.size ());
|
||||
return;
|
||||
}
|
||||
NodeID nodeID;
|
||||
memcpy (nodeID.data (), id.data (), NodeID::len);
|
||||
if (m_RoutingTable)
|
||||
{
|
||||
NodeID nodeID;
|
||||
memcpy (nodeID.data (), id.data (), NodeID::len);
|
||||
if (m_RoutingTable->AddNode (nodeID, it->second.first, it->second.second))
|
||||
LogPrint (eLogDebug, "TorrentsDHT: Node ", it->second.first.ToBase64 (), ":", it->second.second, " added");
|
||||
else
|
||||
LogPrint (eLogError, "TorrentsDHT: Failed to add node ", it->second.first.ToBase64 ());
|
||||
const auto& [ident, port, query, torrentw] = it->second;
|
||||
if (query == "ping")
|
||||
{
|
||||
LogPrint (eLogDebug, "TorrentsDHT: Ping response received");
|
||||
if (m_RoutingTable->AddNode (nodeID, ident, port))
|
||||
LogPrint (eLogDebug, "TorrentsDHT: Node ", ident.ToBase64 (), ":", port, " added");
|
||||
else
|
||||
LogPrint (eLogError, "TorrentsDHT: Failed to add node ", ident.ToBase64 ());
|
||||
}
|
||||
else if (query == "get_peers")
|
||||
{
|
||||
LogPrint (eLogDebug, "TorrentsDHT: get_peers response received");
|
||||
auto torrent = torrentw.lock ();
|
||||
if (!torrent)
|
||||
{
|
||||
auto node = m_RoutingTable->FindNode (nodeID);
|
||||
if (node)
|
||||
{
|
||||
std::shared_ptr<DHTTorrent> dhtTorrent;
|
||||
auto it1 = m_Torrents.find (torrent->GetInfoHash ());
|
||||
if (it1 != m_Torrents.end ())
|
||||
dhtTorrent = it1->second;
|
||||
else
|
||||
{
|
||||
dhtTorrent = std::make_shared<DHTTorrent>();
|
||||
m_Torrents.emplace (torrent->GetInfoHash (), dhtTorrent);
|
||||
}
|
||||
dhtTorrent->AddOutgoingGetPeerNode (token, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -437,7 +508,7 @@ namespace torrents
|
||||
{ "t", CreateByteString (std::string_view ((const char *)&transactionID, 2)) },
|
||||
{ "y", CreateByteString ("q") }
|
||||
});
|
||||
m_Queries.insert_or_assign (transactionID, std::make_pair (toIdent, toPort));
|
||||
m_Queries.insert_or_assign (transactionID, std::make_tuple (toIdent, toPort, query, std::shared_ptr<Torrent>{}));
|
||||
SendDatagram (msg, toIdent, toPort);
|
||||
}
|
||||
|
||||
@@ -471,6 +542,7 @@ namespace torrents
|
||||
void TorrentsDHT::SendGetPeersResponse (std::string_view transactionID, std::shared_ptr<DHTTorrent> torrent,
|
||||
uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort)
|
||||
{
|
||||
if (!torrent) return;
|
||||
SendResponseMsg (CreateDictionary ({
|
||||
{ "id", CreateByteString (std::string_view ((const char *)m_NodeID.data (), m_NodeID.size ())) },
|
||||
{ "token", CreateByteString (std::string_view ((const char *)&token, 8)) },
|
||||
@@ -479,6 +551,18 @@ namespace torrents
|
||||
transactionID, toIdent, toPort);
|
||||
}
|
||||
|
||||
void TorrentsDHT::SendGetPeersResponse (std::string_view transactionID, std::shared_ptr<Node> node,
|
||||
uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort)
|
||||
{
|
||||
if (!node) return;
|
||||
NodeInfo nodeInfo = node->GetNodeInfo ();
|
||||
SendResponseMsg (CreateDictionary ({
|
||||
{ "id", CreateByteString (std::string_view ((const char *)m_NodeID.data (), m_NodeID.size ())) },
|
||||
{ "token", CreateByteString (std::string_view ((const char *)&token, 8)) },
|
||||
{ "nodes", CreateByteString (std::string_view ((const char *)nodeInfo.data (), nodeInfo.size ())) }
|
||||
}),
|
||||
transactionID, toIdent, toPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <openssl/sha.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <array>
|
||||
#include <list>
|
||||
@@ -59,6 +60,7 @@ namespace torrents
|
||||
}
|
||||
};
|
||||
|
||||
using NodeInfo = std::array<uint8_t, NodeID::len + i2p::data::IdentHash::len + 2>;
|
||||
struct Node
|
||||
{
|
||||
NodeID id;
|
||||
@@ -67,6 +69,8 @@ namespace torrents
|
||||
|
||||
Node (const NodeID& id1, const i2p::data::IdentHash& peer1, uint16_t port1):
|
||||
id (id1), peer (peer1), port (port1) {}
|
||||
|
||||
NodeInfo GetNodeInfo () const;
|
||||
};
|
||||
|
||||
constexpr size_t MAX_BUCKET_CAPACITY = 8;
|
||||
@@ -93,7 +97,8 @@ namespace torrents
|
||||
~RoutingTable ();
|
||||
|
||||
std::shared_ptr<Node> AddNode (const NodeID& id, const i2p::data::IdentHash& peer, uint16_t port);
|
||||
std::list<std::pair<std::shared_ptr<Node>, Distance> > FindClosestNodes (const Torrent::InfoHash& infoHash, size_t num) const;
|
||||
std::shared_ptr<Node> FindNode (const NodeID& id) const;
|
||||
std::list<std::pair<std::shared_ptr<Node>, Distance> > FindClosestNodes (const Torrent::InfoHash& infoHash, size_t num = 1) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -115,6 +120,7 @@ namespace torrents
|
||||
|
||||
std::string GetBEncodedPeers () const;
|
||||
void AddIncomingGetPeerNode (GetPeersToken token, std::shared_ptr<Node> node);
|
||||
void AddOutgoingGetPeerNode (GetPeersToken token, std::shared_ptr<Node> node);
|
||||
|
||||
private:
|
||||
|
||||
@@ -123,8 +129,6 @@ namespace torrents
|
||||
std::unordered_map<GetPeersToken, std::weak_ptr<Node> > m_OutgoingGetPeers; // we recive announces from
|
||||
};
|
||||
|
||||
using NodeInfo = std::array<uint8_t, NodeID::len + i2p::data::IdentHash::len + 2>;
|
||||
|
||||
class TorrentsTunnel;
|
||||
class TorrentsDHT
|
||||
{
|
||||
@@ -149,7 +153,8 @@ namespace torrents
|
||||
std::string_view transactionID, std::string_view id);
|
||||
void HandleGetPeersQuery (const i2p::data::IdentHash& fromIdent, uint16_t fromPort,
|
||||
std::string_view transactionID, std::string_view id, std::string_view infoHash);
|
||||
void HandleResponse (std::string_view transactionID, std::string_view id);
|
||||
void HandleResponse (std::string_view transactionID, std::string_view id, uint64_t token,
|
||||
const std::vector<std::string_view>& values);
|
||||
|
||||
void SendDatagram (std::string_view msg, const i2p::data::IdentHash& toIdent, uint16_t toPort);
|
||||
void SendRawDatagram (std::string_view msg, const i2p::data::IdentHash& toIdent, uint16_t toPort);
|
||||
@@ -158,6 +163,8 @@ namespace torrents
|
||||
void SendPingResponse (std::string_view transactionID, const i2p::data::IdentHash& toIdent, uint16_t toPort);
|
||||
void SendGetPeersResponse (std::string_view transactionID, std::shared_ptr<DHTTorrent> torrent,
|
||||
uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort);
|
||||
void SendGetPeersResponse (std::string_view transactionID, std::shared_ptr<Node> node,
|
||||
uint64_t token, const i2p::data::IdentHash& toIdent, uint16_t toPort);
|
||||
|
||||
private:
|
||||
|
||||
@@ -166,7 +173,7 @@ namespace torrents
|
||||
NodeID m_NodeID;
|
||||
NodeInfo m_NodeInfo; // 20 byte Node ID + 32 byte IdentHash + 2 byte port
|
||||
std::unique_ptr<RoutingTable> m_RoutingTable;
|
||||
std::unordered_map<uint16_t, std::pair<i2p::data::IdentHash, uint16_t> > m_Queries;
|
||||
std::unordered_map<uint16_t, std::tuple<i2p::data::IdentHash, uint16_t, std::string, std::weak_ptr<Torrent> > > m_Queries;
|
||||
std::map<Torrent::InfoHash, std::shared_ptr<DHTTorrent> > m_Torrents;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user