From daccef90c11ae149b9dc69d9a2d3ab196ef71f13 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 5 Sep 2026 15:07:16 -0400 Subject: [PATCH] BEP6 --- libi2pd_client/Torrents.cpp | 64 ++++++++++++++++++++++++++++++++++--- libi2pd_client/Torrents.h | 16 +++++++++- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/libi2pd_client/Torrents.cpp b/libi2pd_client/Torrents.cpp index d82150f3..66563ab3 100644 --- a/libi2pd_client/Torrents.cpp +++ b/libi2pd_client/Torrents.cpp @@ -879,7 +879,7 @@ namespace torrents m_IsHandshakeSent (false), m_IsEstablished (false), m_IsChoked (true), m_IsRemoteChoked (true), m_IsInterested (false), m_IsRemoteInterested (false), m_LastReceiveTime (0), m_LastSendTime (0), m_NumRequests (0), m_NumPieces (0), m_LastRequestedPieceIndex (-1), m_RemoteMetadataSize (0), - m_Downloaded (0), m_Uploaded (0) + m_IsFast (false), m_Downloaded (0), m_Uploaded (0) { ResetStats (); } @@ -1175,6 +1175,15 @@ namespace torrents case eMessageTypeExtended: HandleExtendedMsg (m_ReceiveBuffer + offset + 1, msgLen - 1); break; + case eMessageTypeSuggestPiece: + LogPrint (eLogDebug, "Torrents: suggest piece msg received"); + break; + case eMessageTypeRejectRequest: + LogPrint (eLogDebug, "Torrents: reject request msg received"); + break; + case eMessageTypeAllowedFast: + LogPrint (eLogDebug, "Torrents: allowed fast msg received"); + break; default: LogPrint (eLogWarning, "Torrents: Unexpected message type ", (int)m_ReceiveBuffer[offset], ". Ignored"); }; @@ -1215,7 +1224,8 @@ namespace torrents // respond with handshake if incoming if (!m_IsHandshakeSent) SendHandshakeMsg (); - if (m_ReceiveBuffer[20 + 5] & 0x10) // bit 20 of reserved, BEP10 + // BEP10 + if (m_ReceiveBuffer[20 + 5] & 0x10) // bit 20 of reserved SendExtendedMsg (); // extended handshake if peer supports BEP10 else if (!m_Torrent->GetLength ()) // we are magnet without info { @@ -1223,10 +1233,20 @@ namespace torrents Terminate (); return 0; } - // send bitfield if not empty + // BEP6 + if (m_ReceiveBuffer[20 + 7] & 0x04) // bit 61 of reserved + m_IsFast = true; + // send bitfield, have all or have none auto [bitfield, empty] = m_Torrent->CreateBitfield (); if (!empty) - SendBitfieldMsg (bitfield.data (), bitfield.size ()); + { + if (m_IsFast && m_Torrent->IsComplete ()) + SendHaveAllMsg (); + else + SendBitfieldMsg (bitfield.data (), bitfield.size ()); + } + else if (m_IsFast) + SendHaveNoneMsg (); m_IsEstablished = true; return HANDSHAKE_MSG_LENGTH; } @@ -1238,6 +1258,7 @@ namespace torrents buf[0] = 19; memcpy (buf + 1, "BitTorrent protocol", 19); memset (buf + 20, 0, 8); // reserved buf[20 + 5] |= 0x10; // bit 20 of reserved, BEP10 + buf[20 + 7] |= 0x04; // bit 61 of reserved, BEP6 memcpy (buf + 28, m_Torrent->GetInfoHash ().data (), 20); memset (buf + 48, '0', 20); if (GetTorrentsTunnel ()) @@ -1342,6 +1363,14 @@ namespace torrents Terminate (); // we don't need this connection } + void PeerConnection::SendHaveAllMsg () + { + uint8_t buf[HAVE_ALL_MSG_LENGTH]; + htobe32buf (buf, 1); + buf[4] = eMessageTypeHaveAll; + WriteToStream (buf, HAVE_ALL_MSG_LENGTH); + } + void PeerConnection::HandleHaveNoneMsg () { if (!m_Torrent) return; @@ -1350,6 +1379,14 @@ namespace torrents m_RemoteBitfield.reset (); } + void PeerConnection::SendHaveNoneMsg () + { + uint8_t buf[HAVE_NONE_MSG_LENGTH]; + htobe32buf (buf, 1); + buf[4] = eMessageTypeHaveNone; + WriteToStream (buf, HAVE_NONE_MSG_LENGTH); + } + void PeerConnection::HandlePieceMsg (const uint8_t * buf, size_t len) { if (len < 8) return; @@ -1466,6 +1503,17 @@ namespace torrents m_Torrent->AddUploaded (len); } + void PeerConnection::SendRejectRequestMsg (uint32_t index, uint32_t offset, uint32_t len) + { + uint8_t buf[REJECT_REQUEST_MSG_LENGTH]; + htobe32buf (buf, REJECT_REQUEST_MSG_PAYLOAD_LENGTH + 1); // msg length + buf[4] = eMessageTypeRejectRequest; // msg ID + htobe32buf (buf + 5, index); // index + htobe32buf (buf + 9, offset); // offset + htobe32buf (buf + 13, len); // length + WriteToStream (buf, REJECT_REQUEST_MSG_LENGTH); + } + void PeerConnection::HandleRequestMsg (const uint8_t * buf, size_t len) { if (!m_Torrent) return; @@ -1541,10 +1589,18 @@ namespace torrents } } else + { LogPrint (eLogWarning, "Torrents: Requested block (", index, ",", offset, ") is not available"); + if (m_IsFast) + SendRejectRequestMsg (index, offset, length); + } } else + { LogPrint (eLogWarning, "Torrents: Requested index ", index, "exceeds number of pieces", m_Torrent->GetNumPieces ()); + if (m_IsFast) + SendRejectRequestMsg (index, offset, length); + } } bool PeerConnection::SendRequestedBlock (const RequestedBlock& requestedBlock) diff --git a/libi2pd_client/Torrents.h b/libi2pd_client/Torrents.h index 99f54ccf..0a75c845 100644 --- a/libi2pd_client/Torrents.h +++ b/libi2pd_client/Torrents.h @@ -51,8 +51,12 @@ namespace torrents constexpr size_t NOTINTERESTED_MSG_LENGTH = 5; constexpr size_t CHOKE_MSG_LENGTH = 5; constexpr size_t UNCHOKE_MSG_LENGTH = 5; + constexpr size_t HAVE_ALL_MSG_LENGTH = 5; + constexpr size_t HAVE_NONE_MSG_LENGTH = 5; constexpr size_t REQUEST_MSG_PAYLOAD_LENGTH = 12; constexpr size_t REQUEST_MSG_LENGTH = REQUEST_MSG_PAYLOAD_LENGTH + 5; + constexpr size_t REJECT_REQUEST_MSG_PAYLOAD_LENGTH = 12; + constexpr size_t REJECT_REQUEST_MSG_LENGTH = REJECT_REQUEST_MSG_PAYLOAD_LENGTH + 5; constexpr size_t HAVE_MSG_PAYLOAD_LENGTH = 4; // extensions @@ -69,9 +73,14 @@ namespace torrents eMessageTypeBitfield = 5, eMessageTypeRequest = 6, eMessageTypePiece = 7, + // BEP6 + eMessageTypeSuggestPiece = 13, eMessageTypeHaveAll = 14, eMessageTypeHaveNone = 15, - eMessageTypeExtended = 20 // BEP10 + eMessageTypeRejectRequest = 16, + eMessageTypeAllowedFast = 17, + // BEP10 + eMessageTypeExtended = 20 }; struct PieceFileFragment // fragment to save to/load from file @@ -315,9 +324,12 @@ namespace torrents void HandleBitfieldMsg (const uint8_t * buf, size_t len); void SendBitfieldMsg (const uint8_t * bitfield, size_t bitfieldLen); void HandleHaveAllMsg (); + void SendHaveAllMsg (); void HandleHaveNoneMsg (); + void SendHaveNoneMsg (); void HandlePieceMsg (const uint8_t * buf, size_t len); void SendPieceMsg (uint32_t index, uint32_t offset, const uint8_t * data, size_t len); + void SendRejectRequestMsg (uint32_t index, uint32_t offset, uint32_t len); void HandleRequestMsg (const uint8_t * buf, size_t len); void SendRequestMsg (uint32_t index, uint32_t offset, uint32_t len); size_t FillRequestMsg (uint8_t * buf, uint32_t index, uint32_t offset, uint32_t len); @@ -355,6 +367,8 @@ namespace torrents // BEP9 size_t m_RemoteMetadataSize; std::vector m_RemoteMetadata; + // BEP6 + bool m_IsFast; // stats uint64_t m_DownloadRate, m_UploadRate; // B/sec uint64_t m_LastBlockDownloadTimestamp, m_LastBlockUploadTimestamp; // monotonic milliseconds