handle announce_peer

This commit is contained in:
orignal
2026-09-24 17:21:56 -04:00
parent 69e9eadc0b
commit 1af997ac82
2 changed files with 80 additions and 41 deletions
+75 -39
View File
@@ -12,6 +12,7 @@
#include <vector>
#include <fstream>
#include "I2PEndian.h"
#include "Timestamp.h"
#include "TorrentsTunnel.h"
#include "TorrentsDHT.h"
@@ -223,7 +224,7 @@ namespace torrents
void RoutingTable::Load (const std::filesystem::path& file)
{
std::ifstream f (file, std::ios::in | std::ios::binary);
std::ifstream f (file, std::ifstream::in | std::ifstream::binary);
if (f.is_open ())
{
CleanUp ();
@@ -257,6 +258,19 @@ namespace torrents
m_OutgoingGetPeers.emplace (token, node);
}
std::shared_ptr<Node> DHTTorrent::GetIncomingGetPeerNode (GetPeersToken token) const
{
auto it = m_IncomingGetPeers.find (token);
if (it != m_IncomingGetPeers.end ())
return it->second.lock ();
return nullptr;
}
void DHTTorrent::AddPeer (const i2p::data::IdentHash& peer)
{
m_Peers.push_back ( { peer, i2p::util::GetMonotonicSeconds () } );
}
TorrentsDHT::TorrentsDHT (TorrentsTunnel& tunnel, uint16_t port):
m_Tunnel (tunnel), m_Port (port)
{
@@ -302,11 +316,11 @@ namespace torrents
{
// response or error
char type = 0;
std::string transactionID, id;
std::string transactionID, query, id, infoHash;
uint64_t token = 0;
std::vector<std::string_view> values;
ParseDictionary (std::string_view ((const char *)buf, len),
[&type, &transactionID, &id, &values, &token](std::string_view key, std::string_view buf)->size_t
[&type, &transactionID, &id, &values, &token, &infoHash, &query](std::string_view key, std::string_view buf)->size_t
{
if (key == "y")
{
@@ -320,17 +334,16 @@ namespace torrents
if (l) transactionID = value;
return l;
}
else if (key == "token")
else if (key == "q")
{
auto [value, l] = ExtractByteString (buf);
if (l && value.size () >= 8)
memcpy (&token, value.data (), 8);
if (l) query = value;
return l;
}
else if (key == "r")
else if (key == "r" || key == "a")
{
return ParseDictionary (buf,
[&id, &values](std::string_view key, std::string_view buf)->size_t
[&id, &values, &token, &infoHash](std::string_view key, std::string_view buf)->size_t
{
if (key == "id")
{
@@ -344,6 +357,19 @@ namespace torrents
if (l) values = v;
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 == "info_hash")
{
auto [value, l] = ExtractByteString (buf);
if (l) infoHash = value;
return l;
}
return 0;
});
}
@@ -360,7 +386,10 @@ namespace torrents
LogPrint (eLogDebug, "TorrentsDHT: Error msg received");
break;
case 'q':
LogPrint (eLogError, "TorrentsDHT: Query can't come as raw datagram");
if (query == "announce_peer")
HandleAnnouncePeer (infoHash, token);
else
LogPrint (eLogError, "TorrentsDHT: Query can't come as raw datagram");
break;
default:
LogPrint (eLogInfo, "TorrentsDHT: Unxpected msg type ", (int)type);
@@ -461,21 +490,45 @@ namespace torrents
return;
}
memcpy (hash.data (), infoHash.data (), hash.size ());
std::shared_ptr<DHTTorrent> torrent;
auto it = m_Torrents.find (hash);
if (it != m_Torrents.end ())
torrent = it->second;
else
{
torrent = std::make_shared<DHTTorrent>();
m_Torrents.emplace (hash, torrent);
}
uint64_t token = m_Tunnel.GetLocalDestination () ? m_Tunnel.GetLocalDestination ()->GetRng ()() : 1;
it->second->AddIncomingGetPeerNode (token, node);
if (m_RoutingTable)
{
auto nodes = m_RoutingTable->FindClosestNodes (hash);
if (!nodes.empty () && nodes.front ().second < (m_NodeID ^ hash))
SendGetPeersResponse (transactionID, nodes.front ().first, token, fromIdent, fromPort + 1); // to rport
else
SendGetPeersResponse (transactionID, torrent, token, fromIdent, fromPort + 1); // to rport
}
}
void TorrentsDHT::HandleAnnouncePeer (std::string_view infoHash, uint64_t token)
{
LogPrint (eLogDebug, "TorrentsDHT: Announce peer received");
Torrent::InfoHash hash;
if (infoHash.size () < hash.size ())
{
LogPrint (eLogInfo, "TorrentsDHT: Announced info hash is too short ", infoHash.size ());
return;
}
memcpy (hash.data (), infoHash.data (), hash.size ());
auto it = m_Torrents.find (hash);
if (it != m_Torrents.end ())
{
uint64_t token = m_Tunnel.GetLocalDestination () ? m_Tunnel.GetLocalDestination ()->GetRng ()() : 1;
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
}
auto node = it->second->GetIncomingGetPeerNode (token);
if (node)
it->second->AddPeer (node->peer);
}
}
@@ -510,24 +563,7 @@ namespace torrents
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);
}
}
// TODO:
}
}
}
+5 -2
View File
@@ -128,12 +128,14 @@ namespace torrents
std::string GetBEncodedPeers () const;
void AddIncomingGetPeerNode (GetPeersToken token, std::shared_ptr<Node> node);
void AddOutgoingGetPeerNode (GetPeersToken token, std::shared_ptr<Node> node);
std::shared_ptr<Node> GetIncomingGetPeerNode (GetPeersToken token) const;
void AddPeer (const i2p::data::IdentHash& peer);
private:
std::list<std::pair<i2p::data::IdentHash, uint64_t> > m_Peers; // (ident, update time in monotonic seconds)
std::unordered_map<GetPeersToken, std::weak_ptr<Node> > m_IncomingGetPeers; // we send announces to
std::unordered_map<GetPeersToken, std::weak_ptr<Node> > m_OutgoingGetPeers; // we recive announces from
std::unordered_map<GetPeersToken, std::weak_ptr<Node> > m_IncomingGetPeers; // they request peers and send announces to us
std::unordered_map<GetPeersToken, std::weak_ptr<Node> > m_OutgoingGetPeers; // we request peers from and send announces to
};
class TorrentsTunnel;
@@ -162,6 +164,7 @@ namespace torrents
std::string_view transactionID, std::string_view id, std::string_view infoHash);
void HandleResponse (std::string_view transactionID, std::string_view id, uint64_t token,
const std::vector<std::string_view>& values);
void HandleAnnouncePeer (std::string_view infoHash, uint64_t token);
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);