From 095bad65689e623fa7aba6978ef196e54216022b Mon Sep 17 00:00:00 2001 From: Yat Ho Date: Tue, 9 Dec 2025 05:43:56 +0800 Subject: [PATCH] fix: check if piece is wanted upon receiving block (#7866) * fix: check if piece is wanted upon receiving block * test: block_last_loc --- libtransmission/block-info.h | 6 ++++ libtransmission/peer-msgs.cc | 16 +++++++---- libtransmission/torrent-metainfo.h | 4 +++ libtransmission/torrent.h | 4 +++ tests/libtransmission/block-info-test.cc | 35 ++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 6 deletions(-) diff --git a/libtransmission/block-info.h b/libtransmission/block-info.h index 02696b895..64ce23de6 100644 --- a/libtransmission/block-info.h +++ b/libtransmission/block-info.h @@ -97,6 +97,12 @@ public: return byte_loc(uint64_t{ block } * BlockSize); } + // Location of the last byte in `block`. + [[nodiscard]] constexpr auto block_last_loc(tr_block_index_t const block) const noexcept + { + return byte_loc((uint64_t{ block } * BlockSize) + block_size(block) - 1U); + } + // Location of the first byte (+ optional offset and length) in `piece` [[nodiscard]] constexpr auto piece_loc(tr_piece_index_t piece, uint32_t offset = {}, uint32_t length = {}) const noexcept { diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc index cfb1966d8..c7aad71b1 100644 --- a/libtransmission/peer-msgs.cc +++ b/libtransmission/peer-msgs.cc @@ -1688,18 +1688,22 @@ ReadResult tr_peerMsgsImpl::read_piece_data(MessageReader& payload) return { ReadState::Err, len }; } - if (!active_requests.test(block)) - { - logwarn(this, fmt::format("got unrequested block {:d} ({:d}:{:d}->{:d})", block, piece, offset, len)); - return { ReadState::Err, len }; - } - if (tor_.has_block(block)) { logtrace(this, fmt::format("got completed block {:d} ({:d}:{:d}->{:d})", block, piece, offset, len)); return { ReadState::Err, len }; } + if (auto const block_loc = tor_.block_loc(block); !tor_.piece_is_wanted(block_loc.piece)) + { + if (auto const block_last_loc = tor_.block_last_loc(block); + block_loc.piece == block_last_loc.piece || !tor_.piece_is_wanted(block_last_loc.piece)) + { + logwarn(this, fmt::format("got unwanted block {:d} ({:d}:{:d}->{:d})", block, piece, offset, len)); + return { ReadState::Err, len }; + } + } + peer_info->set_latest_piece_data_time(tr_time()); bytes_sent_to_client.add(tr_time(), len); publish(tr_peer_event::GotPieceData(len)); diff --git a/libtransmission/torrent-metainfo.h b/libtransmission/torrent-metainfo.h index 7f14d236d..0c7c9ffe5 100644 --- a/libtransmission/torrent-metainfo.h +++ b/libtransmission/torrent-metainfo.h @@ -79,6 +79,10 @@ public: { return block_info().block_loc(block); } + [[nodiscard]] constexpr auto block_last_loc(tr_block_index_t block) const noexcept + { + return block_info().block_last_loc(block); + } [[nodiscard]] constexpr auto piece_loc(tr_piece_index_t piece, uint32_t offset = 0, uint32_t length = 0) const noexcept { return block_info().piece_loc(piece, offset, length); diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 12703ed28..108dfd71f 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -267,6 +267,10 @@ struct tr_torrent { return metainfo_.block_loc(block); } + [[nodiscard]] constexpr auto block_last_loc(tr_block_index_t block) const noexcept + { + return metainfo_.block_last_loc(block); + } [[nodiscard]] constexpr auto piece_loc(tr_piece_index_t piece, uint32_t offset = 0, uint32_t length = 0) const noexcept { return metainfo_.piece_loc(piece, offset, length); diff --git a/tests/libtransmission/block-info-test.cc b/tests/libtransmission/block-info-test.cc index 59a014426..f74e95335 100644 --- a/tests/libtransmission/block-info-test.cc +++ b/tests/libtransmission/block-info-test.cc @@ -136,6 +136,41 @@ TEST_F(BlockInfoTest, blockLoc) EXPECT_EQ(0U, loc.piece_offset); } +TEST_F(BlockInfoTest, blockLastLoc) +{ + static auto constexpr ExpectedBlockSize = uint64_t{ 1024U } * 16U; + static auto constexpr ExpectedBlocksPerPiece = uint64_t{ 4U }; + static auto constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + static auto constexpr PieceCount = uint64_t{ 5U }; + static auto constexpr TotalSize = (PieceSize * (PieceCount - 1U)) + 1U; + + auto const info = tr_block_info{ TotalSize, PieceSize }; + + // begin + auto loc = info.block_last_loc(0); + EXPECT_EQ(ExpectedBlockSize - 1U, loc.byte); + EXPECT_EQ(0U, loc.block); + EXPECT_EQ(ExpectedBlockSize - 1U, loc.block_offset); + EXPECT_EQ(0U, loc.piece); + EXPECT_EQ(ExpectedBlockSize - 1U, loc.piece_offset); + + // third block is halfway through the first piece + loc = info.block_last_loc(2); + EXPECT_EQ((ExpectedBlockSize * 3U) - 1U, loc.byte); + EXPECT_EQ(2U, loc.block); + EXPECT_EQ(ExpectedBlockSize - 1U, loc.block_offset); + EXPECT_EQ(0U, loc.piece); + EXPECT_EQ((ExpectedBlockSize * 3U) - 1U, loc.piece_offset); + + // second piece aligns with fifth block + loc = info.block_last_loc(4); + EXPECT_EQ(PieceSize + ExpectedBlockSize - 1U, loc.byte); + EXPECT_EQ(4U, loc.block); + EXPECT_EQ(ExpectedBlockSize - 1U, loc.block_offset); + EXPECT_EQ(1U, loc.piece); + EXPECT_EQ(ExpectedBlockSize - 1U, loc.piece_offset); +} + TEST_F(BlockInfoTest, pieceLoc) { static auto constexpr ExpectedBlockSize = uint64_t{ 1024U } * 16U;