refactor: convert `tr_peerMsgsImpl` helper functions to class methods (#6580)

* refactor: update bep links

* chore: use more appropriate data types

* chore: checkpoint

* refactor: split `can_request()` into each of their own different signature

* chore: checkpoint

* refactor: convert tr_peerMsgsImpl functions to methods

* chore: checkpoint

* refactor: store peer info as reference

* refactor: convert all member variables to private

* chore: re-arrange methods

* refactor: optimise tmp vector default size in `send_ut_pex()`

* chore: housekeeping

* chore: housekeeping

* refactor: avoid `dynamic_cast` when sending cancel

* fix: restore `blocks_sent_to_peer` stat

regression e91af26923

* fix: choke first then reject

* refactor: convert `tr_peerMsgsNew()` to static factory function

* refactor: store `tr_torrent` reference instead of pointer

* Revert "refactor: store peer info as reference"

This reverts commit bb419bf2

---------

Co-authored-by: Charles Kerr <charles@charleskerr.com>
This commit is contained in:
Yat Ho 2024-03-16 08:52:09 +08:00 committed by GitHub
parent 8709ec60e6
commit 152f3e91a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 1401 additions and 1431 deletions

View File

@ -561,7 +561,7 @@ ReadState tr_handshake::can_read(tr_peerIo* peer_io, void* vhandshake, size_t* p
/* no piece data in handshake */
*piece = 0;
tr_logAddTraceHand(handshake, fmt::format("handling canRead; state is [{}]", handshake->state_string()));
tr_logAddTraceHand(handshake, fmt::format("handling can_read; state is [{}]", handshake->state_string()));
ReadState ret = READ_NOW;
while (ret == READ_NOW)

View File

@ -134,7 +134,7 @@ std::optional<tr_sha1_digest_t> parseBase32Hash(std::string_view sv)
std::optional<tr_sha1_digest_t> parseHash(std::string_view sv)
{
// http://bittorrent.org/beps/bep_0009.html
// https://www.bittorrent.org/beps/bep_0009.html
// Is the info-hash hex encoded, for a total of 40 characters.
// For compatibility with existing links in the wild, clients
// should also support the 32 character base32 encoded info-hash.
@ -153,7 +153,7 @@ std::optional<tr_sha1_digest_t> parseHash(std::string_view sv)
std::optional<tr_sha256_digest_t> parseHash2(std::string_view sv)
{
// http://bittorrent.org/beps/bep_0009.html
// https://www.bittorrent.org/beps/bep_0009.html
// Is the info-hash v2 hex encoded and tag removed, for a total of 64 characters.
if (auto const hash = tr_sha256_from_string(sv); hash)

View File

@ -271,7 +271,6 @@ tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_socket_address const
return {};
}
auto ret = tr_peer_socket{};
if (connect(s, reinterpret_cast<sockaddr const*>(&sock), addrlen) == -1 &&
#ifdef _WIN32
sockerrno != WSAEWOULDBLOCK &&
@ -291,15 +290,12 @@ tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_socket_address const
}
tr_net_close_socket(s);
}
else
{
ret = tr_peer_socket{ session, socket_address, s };
return {};
}
tr_logAddTrace(fmt::format("New OUTGOING connection {} ({})", s, socket_address.display_name()));
return ret;
return { session, socket_address, s };
}
namespace

View File

@ -242,7 +242,7 @@ struct tr_address
} addr;
static auto constexpr CompactAddrBytes = std::array{ 4U, 16U };
static auto constexpr CompactAddrMaxBytes = 16U;
static auto constexpr CompactAddrMaxBytes = *std::max_element(std::begin(CompactAddrBytes), std::end(CompactAddrBytes));
static_assert(std::size(CompactAddrBytes) == NUM_TR_AF_INET_TYPES);
[[nodiscard]] static auto any(tr_address_type type) noexcept
@ -397,6 +397,7 @@ struct tr_socket_address
static auto constexpr CompactSockAddrBytes = std::array{ tr_address::CompactAddrBytes[0] + tr_port::CompactPortBytes,
tr_address::CompactAddrBytes[1] + tr_port::CompactPortBytes };
static auto constexpr CompactSockAddrMaxBytes = tr_address::CompactAddrMaxBytes + tr_port::CompactPortBytes;
static_assert(std::size(CompactSockAddrBytes) == NUM_TR_AF_INET_TYPES);
};

View File

@ -26,9 +26,9 @@
* @{
*/
class tr_peer;
class tr_swarm;
struct tr_bandwidth;
struct tr_peer;
// --- Peer Publish / Subscribe
@ -178,27 +178,26 @@ using tr_peer_callback_generic = void (*)(tr_peer* peer, tr_peer_event const& ev
* @see tr_peer_info
* @see tr_peerMsgs
*/
class tr_peer
struct tr_peer
{
public:
using Speed = libtransmission::Values::Speed;
explicit tr_peer(tr_torrent const* tor);
explicit tr_peer(tr_torrent const& tor);
virtual ~tr_peer();
[[nodiscard]] virtual Speed get_piece_speed(uint64_t now, tr_direction direction) const = 0;
[[nodiscard]] bool hasPiece(tr_piece_index_t piece) const noexcept
[[nodiscard]] bool has_piece(tr_piece_index_t piece) const noexcept
{
return has().test(piece);
}
[[nodiscard]] float percentDone() const noexcept
[[nodiscard]] float percent_done() const noexcept
{
return has().percent();
}
[[nodiscard]] bool isSeed() const noexcept
[[nodiscard]] bool is_seed() const noexcept
{
return has().has_all();
}
@ -208,22 +207,13 @@ public:
[[nodiscard]] virtual tr_bitfield const& has() const noexcept = 0;
// requests that have been made but haven't been fulfilled yet
[[nodiscard]] virtual size_t activeReqCount(tr_direction) const noexcept = 0;
[[nodiscard]] virtual size_t active_req_count(tr_direction) const noexcept = 0;
virtual void requestBlocks(tr_block_span_t const* block_spans, size_t n_spans) = 0;
virtual void request_blocks(tr_block_span_t const* block_spans, size_t n_spans) = 0;
struct RequestLimit
virtual void cancel_block_request(tr_block_index_t /*block*/)
{
// How many blocks we could request.
size_t max_spans = 0;
// How many spans those blocks could be in.
// This is for webseeds, which make parallel requests.
size_t max_blocks = 0;
};
// how many blocks could we request from this peer right now?
[[nodiscard]] virtual RequestLimit canRequest() const noexcept = 0;
}
tr_session* const session;

View File

@ -21,7 +21,7 @@
#include "libtransmission/peer-mgr-wishlist.h"
#include "libtransmission/tr-assert.h"
class tr_peer;
struct tr_peer;
class ActiveRequests::Impl
{

View File

@ -17,7 +17,7 @@
#include "libtransmission/transmission.h" // tr_block_index_t
class tr_peer;
struct tr_peer;
/**
* Bookkeeping for the active requests we have --

View File

@ -646,7 +646,7 @@ private:
webseeds.reserve(n);
for (size_t i = 0; i < n; ++i)
{
webseeds.emplace_back(tr_webseedNew(tor, tor->webseed(i), &tr_swarm::peer_callback_webseed, this));
webseeds.emplace_back(tr_webseedNew(*tor, tor->webseed(i), &tr_swarm::peer_callback_webseed, this));
}
webseeds.shrink_to_fit();
@ -681,11 +681,9 @@ private:
static void maybe_send_cancel_request(tr_peer* peer, tr_block_index_t block, tr_peer const* muted)
{
auto* msgs = dynamic_cast<tr_peerMsgs*>(peer);
if (msgs != nullptr && msgs != muted)
if (peer != nullptr && peer != muted)
{
peer->cancels_sent_to_peer.add(tr_time(), 1);
msgs->cancel_block_request(block);
peer->cancel_block_request(block);
}
}
@ -780,9 +778,9 @@ private:
// didn't have the metadata before now... so refresh them all...
for (auto* peer : peers)
{
peer->onTorrentGotMetainfo();
peer->on_torrent_got_metainfo();
if (peer->isSeed())
if (peer->is_seed())
{
mark_peer_as_seed(*peer->peer_info);
}
@ -1006,7 +1004,7 @@ size_t tr_swarm::WishlistMediator::count_piece_replication(tr_piece_index_t piec
std::begin(swarm_.peers),
std::end(swarm_.peers),
size_t{},
[piece](size_t acc, tr_peer* peer) { return acc + (peer->hasPiece(piece) ? 1U : 0U); });
[piece](size_t acc, tr_peer* peer) { return acc + (peer->has_piece(piece) ? 1U : 0U); });
}
tr_block_span_t tr_swarm::WishlistMediator::block_span(tr_piece_index_t piece) const
@ -1195,10 +1193,10 @@ private:
// --- tr_peer virtual functions
tr_peer::tr_peer(tr_torrent const* tor)
: session{ tor->session }
, swarm{ tor->swarm }
, blame{ tor->block_count() }
tr_peer::tr_peer(tr_torrent const& tor)
: session{ tor.session }
, swarm{ tor.swarm }
, blame{ tor.block_count() }
{
}
@ -1263,7 +1261,7 @@ std::vector<tr_block_span_t> tr_peerMgrGetNextRequests(tr_torrent* torrent, tr_p
swarm.update_endgame();
return swarm.wishlist->next(
numwant,
[peer](tr_piece_index_t p) { return peer->hasPiece(p); },
[peer](tr_piece_index_t p) { return peer->has_piece(p); },
[peer, &swarm](tr_block_index_t b) { return swarm.active_requests.has(b, peer); });
}
@ -1294,15 +1292,14 @@ namespace
{
namespace handshake_helpers
{
void create_bit_torrent_peer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io, tr_peer_info* peer_info, tr_interned_string client)
void create_bit_torrent_peer(tr_torrent& tor, std::shared_ptr<tr_peerIo> io, tr_peer_info* peer_info, tr_interned_string client)
{
TR_ASSERT(peer_info != nullptr);
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(tor->swarm != nullptr);
TR_ASSERT(tor.swarm != nullptr);
tr_swarm* swarm = tor->swarm;
tr_swarm* swarm = tor.swarm;
auto* peer = tr_peerMsgsNew(tor, peer_info, std::move(io), client, &tr_swarm::peer_callback_bt, swarm);
auto* peer = tr_peerMsgs::create(tor, peer_info, std::move(io), client, &tr_swarm::peer_callback_bt, swarm);
swarm->peers.push_back(peer);
@ -1399,7 +1396,7 @@ void create_bit_torrent_peer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io, tr_
}
result.io->set_bandwidth(&swarm->tor->bandwidth());
create_bit_torrent_peer(swarm->tor, result.io, info, client);
create_bit_torrent_peer(*swarm->tor, result.io, info, client);
return true;
}
@ -1635,7 +1632,7 @@ int8_t tr_peerMgrPieceAvailability(tr_torrent const* tor, tr_piece_index_t piece
}
auto const& peers = tor->swarm->peers;
return std::count_if(std::begin(peers), std::end(peers), [piece](auto const* peer) { return peer->hasPiece(piece); });
return std::count_if(std::begin(peers), std::end(peers), [piece](auto const* peer) { return peer->has_piece(piece); });
}
void tr_peerMgrTorrentAvailability(tr_torrent const* tor, int8_t* tab, unsigned int n_tabs)
@ -1741,7 +1738,7 @@ namespace peer_stat_helpers
stats.client = peer->user_agent().c_str();
stats.port = port.host();
stats.from = peer->peer_info->from_first();
stats.progress = peer->percentDone();
stats.progress = peer->percent_done();
stats.isUTP = peer->is_utp_connection();
stats.isEncrypted = peer->is_encrypted();
stats.rateToPeer_KBps = peer->get_piece_speed(now_msec, TR_CLIENT_TO_PEER).count(Speed::Units::KByps);
@ -1753,15 +1750,15 @@ namespace peer_stat_helpers
stats.isIncoming = peer->is_incoming_connection();
stats.isDownloadingFrom = peer->is_active(TR_PEER_TO_CLIENT);
stats.isUploadingTo = peer->is_active(TR_CLIENT_TO_PEER);
stats.isSeed = peer->isSeed();
stats.isSeed = peer->is_seed();
stats.blocksToPeer = peer->blocks_sent_to_peer.count(now, CancelHistorySec);
stats.blocksToClient = peer->blocks_sent_to_client.count(now, CancelHistorySec);
stats.cancelsToPeer = peer->cancels_sent_to_peer.count(now, CancelHistorySec);
stats.cancelsToClient = peer->cancels_sent_to_client.count(now, CancelHistorySec);
stats.activeReqsToPeer = peer->activeReqCount(TR_CLIENT_TO_PEER);
stats.activeReqsToClient = peer->activeReqCount(TR_PEER_TO_CLIENT);
stats.activeReqsToPeer = peer->active_req_count(TR_CLIENT_TO_PEER);
stats.activeReqsToClient = peer->active_req_count(TR_PEER_TO_CLIENT);
char* pch = stats.flagStr;
@ -1876,14 +1873,14 @@ namespace update_interest_helpers
TR_ASSERT(!tor->is_done());
TR_ASSERT(tor->client_can_download());
if (peer->isSeed())
if (peer->is_seed())
{
return true;
}
for (tr_piece_index_t i = 0; i < tor->piece_count(); ++i)
{
if (piece_is_interesting[i] && peer->hasPiece(i))
if (piece_is_interesting[i] && peer->has_piece(i))
{
return true;
}
@ -1904,11 +1901,11 @@ void updateInterest(tr_swarm* swarm)
if (auto const& peers = swarm->peers; !std::empty(peers))
{
int const n = tor->piece_count();
auto const n = tor->piece_count();
// build a bitfield of interesting pieces...
auto piece_is_interesting = std::vector<bool>(n);
for (int i = 0; i < n; ++i)
for (tr_piece_index_t i = 0U; i < n; ++i)
{
piece_is_interesting[i] = tor->piece_is_wanted(i) && !tor->has_piece(i);
}
@ -2019,7 +2016,7 @@ void rechokeUploads(tr_swarm* s, uint64_t const now)
auto salter = tr_salt_shaker{};
for (auto* const peer : peers)
{
if (peer->isSeed())
if (peer->is_seed())
{
/* choke seeds and partial seeds */
peer->set_choke(true);
@ -2160,7 +2157,7 @@ auto constexpr MaxUploadIdleSecs = time_t{ 60 * 5 };
auto const* const info = peer->peer_info;
/* disconnect if we're both seeds and enough time has passed for PEX */
if (tor->is_done() && peer->isSeed())
if (tor->is_done() && peer->is_seed())
{
return !tor->allows_pex() || info->idle_secs(now).value_or(0U) >= 30U;
}

View File

@ -30,8 +30,8 @@
* @{
*/
class tr_peer;
class tr_peer_socket;
struct tr_peer;
struct tr_peerMgr;
struct tr_peer_stat;
struct tr_session;

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ class tr_peerMsgs : public tr_peer
{
public:
tr_peerMsgs(
tr_torrent const* tor,
tr_torrent const& tor,
tr_peer_info* peer_info_in,
tr_interned_string user_agent,
bool connection_is_encrypted,
@ -97,17 +97,23 @@ public:
[[nodiscard]] virtual tr_socket_address socket_address() const = 0;
virtual void cancel_block_request(tr_block_index_t block) = 0;
virtual void set_choke(bool peer_is_choked) = 0;
virtual void set_interested(bool client_is_interested) = 0;
virtual void pulse() = 0;
virtual void onTorrentGotMetainfo() = 0;
virtual void on_torrent_got_metainfo() noexcept = 0;
virtual void on_piece_completed(tr_piece_index_t) = 0;
static tr_peerMsgs* create(
tr_torrent& torrent,
tr_peer_info* peer_info,
std::shared_ptr<tr_peerIo> io,
tr_interned_string user_agent,
tr_peer_callback_bt callback,
void* callback_data);
protected:
constexpr void set_client_choked(bool val) noexcept
{
@ -169,12 +175,4 @@ private:
bool peer_is_interested_ = false;
};
tr_peerMsgs* tr_peerMsgsNew(
tr_torrent* torrent,
tr_peer_info* peer_info,
std::shared_ptr<tr_peerIo> io,
tr_interned_string user_agent,
tr_peer_callback_bt callback,
void* callback_data);
/* @} */

View File

@ -32,7 +32,7 @@ using namespace std::literals;
/**
* @brief Ensure that the URLs for multfile torrents end in a slash.
*
* See http://bittorrent.org/beps/bep_0019.html#metadata-extension
* See https://www.bittorrent.org/beps/bep_0019.html#metadata-extension
* for background on how the trailing slash is used for "url-list"
* fields.
*
@ -513,7 +513,7 @@ private:
bool finish(Context const& context)
{
// bittorrent 1.0 spec
// http://bittorrent.org/beps/bep_0003.html
// https://www.bittorrent.org/beps/bep_0003.html
//
// "There is also a key length or a key files, but not both or neither.
//

View File

@ -231,7 +231,7 @@ private:
// Offset + size of the bencoded info dict subset of the bencoded data.
// Used when loading pieces of it to sent to magnet peers.
// See http://bittorrent.org/beps/bep_0009.html
// See https://www.bittorrent.org/beps/bep_0009.html
uint64_t info_dict_size_ = 0;
uint64_t info_dict_offset_ = 0;

View File

@ -168,15 +168,25 @@ void onBufferGotData(evbuffer* /*buf*/, evbuffer_cb_info const* info, void* vtas
class tr_webseed final : public tr_peer
{
public:
tr_webseed(struct tr_torrent* tor, std::string_view url, tr_peer_callback_webseed callback_in, void* callback_data_in)
struct RequestLimit
{
// How many spans those blocks could be in.
// This is for webseeds, which make parallel requests.
size_t max_spans = 0;
// How many blocks we could request.
size_t max_blocks = 0;
};
tr_webseed(tr_torrent& tor, std::string_view url, tr_peer_callback_webseed callback_in, void* callback_data_in)
: tr_peer{ tor }
, torrent_id{ tr_torrentId(tor) }
, torrent_id{ tor.id() }
, base_url{ url }
, callback{ callback_in }
, callback_data{ callback_data_in }
, idle_timer_{ session->timerMaker().create([this]() { on_idle(this); }) }
, have_{ tor->piece_count() }
, bandwidth_{ &tor->bandwidth() }
, have_{ tor.piece_count() }
, bandwidth_{ &tor.bandwidth() }
{
have_.set_has_all();
idle_timer_->start_repeating(IdleTimerInterval);
@ -204,7 +214,7 @@ public:
return dir == TR_DOWN ? bandwidth_.get_piece_speed(now, dir) : Speed{};
}
[[nodiscard]] TR_CONSTEXPR20 size_t activeReqCount(tr_direction dir) const noexcept override
[[nodiscard]] TR_CONSTEXPR20 size_t active_req_count(tr_direction dir) const noexcept override
{
if (dir == TR_CLIENT_TO_PEER) // blocks we've requested
{
@ -250,7 +260,7 @@ public:
}
}
void requestBlocks(tr_block_span_t const* block_spans, size_t n_spans) override
void request_blocks(tr_block_span_t const* block_spans, size_t n_spans) override
{
auto* const tor = getTorrent();
if (tor == nullptr || !tor->is_running() || tor->is_done())
@ -269,7 +279,7 @@ public:
}
}
[[nodiscard]] RequestLimit canRequest() const noexcept override
[[nodiscard]] RequestLimit max_available_reqs() const noexcept
{
auto const n_slots = connection_limiter.slotsAvailable();
if (n_slots == 0)
@ -285,7 +295,7 @@ public:
// Prefer to request large, contiguous chunks from webseeds.
// The actual value of '64' is arbitrary here;
// we could probably be smarter about this.
auto constexpr PreferredBlocksPerTask = size_t{ 64 };
static auto constexpr PreferredBlocksPerTask = size_t{ 64 };
return { n_slots, n_slots * PreferredBlocksPerTask };
}
@ -413,7 +423,7 @@ void onBufferGotData(evbuffer* /*buf*/, evbuffer_cb_info const* info, void* vtas
void on_idle(tr_webseed* webseed)
{
auto const [max_spans, max_blocks] = webseed->canRequest();
auto const [max_spans, max_blocks] = webseed->max_available_reqs();
if (max_spans == 0 || max_blocks == 0)
{
return;
@ -427,7 +437,7 @@ void on_idle(tr_webseed* webseed)
{
spans.resize(max_spans);
}
webseed->requestBlocks(std::data(spans), std::size(spans));
webseed->request_blocks(std::data(spans), std::size(spans));
}
void onPartialDataFetched(tr_web::FetchResponse const& web_response)
@ -523,9 +533,9 @@ void task_request_next_chunk(tr_webseed_task* task)
// ---
tr_peer* tr_webseedNew(tr_torrent* torrent, std::string_view url, tr_peer_callback_webseed callback, void* callback_data)
tr_peer* tr_webseedNew(tr_torrent& torrent, std::string_view url, tr_peer_callback_webseed callback, void* callback_data)
{
return new tr_webseed(torrent, url, callback, callback_data);
return new tr_webseed{ torrent, url, callback, callback_data };
}
tr_webseed_view tr_webseedView(tr_peer const* peer)

View File

@ -17,6 +17,6 @@
using tr_peer_callback_webseed = tr_peer_callback_generic;
tr_peer* tr_webseedNew(struct tr_torrent* torrent, std::string_view, tr_peer_callback_webseed callback, void* callback_data);
tr_peer* tr_webseedNew(tr_torrent& torrent, std::string_view, tr_peer_callback_webseed callback, void* callback_data);
tr_webseed_view tr_webseedView(tr_peer const* peer);

View File

@ -187,7 +187,7 @@ TEST_F(CompletionTest, percentCompleteAndDone)
EXPECT_DOUBLE_EQ(0.5, completion.percent_done());
// but marking some of the pieces we have as unwanted
// should not change percentDone
// should not change percent_done
for (size_t i = 0; i < 16; ++i)
{
torrent.dnd_pieces.insert(i);
@ -197,7 +197,7 @@ TEST_F(CompletionTest, percentCompleteAndDone)
EXPECT_DOUBLE_EQ(0.5, completion.percent_done());
// but marking some of the pieces we DON'T have as unwanted
// SHOULD change percentDone
// SHOULD change percent_done
for (size_t i = 32; i < 48; ++i)
{
torrent.dnd_pieces.insert(i);