Compare commits

...

10 Commits

Author SHA1 Message Date
Yat Ho dd44cd3d3f
Merge 51c9cc4a85 into 821a6816ef 2024-04-24 02:42:11 +00:00
Yat Ho 51c9cc4a85 fix: remove constexpr 2024-04-24 10:42:07 +08:00
Yat Ho dccb10dc6b refactor: use `small::map` 2024-04-24 10:42:07 +08:00
Yat Ho 1f83cd4972 fix: suppress goto warning 2024-04-24 10:42:07 +08:00
Yat Ho 67bff3a398 refactor: use small maps but with `std::vector` as base 2024-04-24 10:42:07 +08:00
Yat Ho c91613a49f fix: use `std::unordered_map` as a stand-in for `small::map` 2024-04-24 10:42:07 +08:00
Yat Ho 7dff58664d refactor: unify `on_got_port()` exit point to simplify cleanup 2024-04-24 10:42:07 +08:00
Yat Ho 6652b3dd72 refactor: minimise insert/erase operations to the peer info pool 2024-04-24 10:42:07 +08:00
Yat Ho 05e882b046 refactor: store peer info objects in shared_ptr 2024-04-24 10:42:07 +08:00
Yat Ho 007e32b59c chore: housekeeping 2024-04-24 10:42:07 +08:00
3 changed files with 144 additions and 171 deletions

View File

@ -20,6 +20,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <small/map.hpp>
#include <small/vector.hpp> #include <small/vector.hpp>
#include <fmt/core.h> #include <fmt/core.h>
@ -283,7 +284,7 @@ class tr_swarm
{ {
public: public:
using Peers = std::vector<tr_peerMsgs*>; using Peers = std::vector<tr_peerMsgs*>;
using Pool = std::unordered_map<tr_socket_address, tr_peer_info>; using Pool = small::map<tr_socket_address, std::shared_ptr<tr_peer_info>>;
class WishlistMediator final : public Wishlist::Mediator class WishlistMediator final : public Wishlist::Mediator
{ {
@ -377,12 +378,16 @@ public:
void remove_inactive_peer_info() noexcept void remove_inactive_peer_info() noexcept
{ {
auto const now = tr_time(); auto const now = tr_time();
for (auto iter = std::begin(connectable_pool), end = std::end(connectable_pool); iter != end;)
// N.B. Unlike `std::map`, erasing elements in `small::map` seems to invalidate
// iterators other than the one being erased. So make sure `std::end()` is called
// every iteration
for (auto iter = std::begin(connectable_pool); iter != std::end(connectable_pool);)
{ {
auto& [socket_address, peer_info] = *iter; auto const& [socket_address, peer_info] = *iter;
if (peer_info.is_inactive(now)) if (peer_info->is_inactive(now))
{ {
--stats.known_peer_from_count[peer_info.from_first()]; --stats.known_peer_from_count[peer_info->from_first()];
iter = connectable_pool.erase(iter); iter = connectable_pool.erase(iter);
} }
else else
@ -416,10 +421,8 @@ public:
peer_disconnect.emit(tor, peer->has()); peer_disconnect.emit(tor, peer->has());
auto* const peer_info = peer->peer_info; auto const& peer_info = peer->peer_info;
auto const socket_address = peer->socket_address(); TR_ASSERT(peer_info);
[[maybe_unused]] auto const is_incoming = peer->is_incoming_connection();
TR_ASSERT(peer_info != nullptr);
--stats.peer_count; --stats.peer_count;
--stats.peer_from_count[peer_info->from_first()]; --stats.peer_from_count[peer_info->from_first()];
@ -431,17 +434,6 @@ public:
} }
delete peer; delete peer;
if (std::empty(peer_info->listen_port())) // is not connectable
{
TR_ASSERT(is_incoming);
[[maybe_unused]] auto const count = incoming_pool.erase(socket_address);
TR_ASSERT(count != 0U);
}
else
{
graveyard_pool.erase(peer_info->listen_socket_address());
}
} }
void remove_all_peers() void remove_all_peers()
@ -475,37 +467,41 @@ public:
pool_is_all_seeds_ = std::all_of( pool_is_all_seeds_ = std::all_of(
std::begin(connectable_pool), std::begin(connectable_pool),
std::end(connectable_pool), std::end(connectable_pool),
[](auto const& key_val) { return key_val.second.is_seed(); }); [](auto const& key_val) { return key_val.second->is_seed(); });
} }
return *pool_is_all_seeds_; return *pool_is_all_seeds_;
} }
[[nodiscard]] tr_peer_info* get_existing_peer_info(tr_socket_address const& socket_address) noexcept [[nodiscard]] std::shared_ptr<tr_peer_info> get_existing_peer_info(tr_socket_address const& socket_address) const noexcept
{ {
auto&& it = connectable_pool.find(socket_address); if (auto it = connectable_pool.find(socket_address); it != std::end(connectable_pool))
return it != connectable_pool.end() ? &it->second : nullptr; {
return it->second;
}
return {};
} }
tr_peer_info& ensure_info_exists( std::shared_ptr<tr_peer_info> ensure_info_exists(
tr_socket_address const& socket_address, tr_socket_address const& socket_address,
uint8_t const flags, uint8_t const flags,
tr_peer_from const from, tr_peer_from const from)
bool is_connectable)
{ {
TR_ASSERT(socket_address.is_valid()); TR_ASSERT(socket_address.is_valid());
TR_ASSERT(from < TR_PEER_FROM__MAX); TR_ASSERT(from < TR_PEER_FROM__MAX);
auto&& [it, is_new] = is_connectable ? connectable_pool.try_emplace(socket_address, socket_address, flags, from) : auto peer_info = get_existing_peer_info(socket_address);
incoming_pool.try_emplace(socket_address, socket_address.address(), flags, from); if (peer_info)
auto& peer_info = it->second;
if (!is_new)
{ {
peer_info.found_at(from); peer_info->found_at(from);
peer_info.set_pex_flags(flags); peer_info->set_pex_flags(flags);
} }
else if (is_connectable) else
{ {
peer_info = connectable_pool
.try_emplace(socket_address, std::make_shared<tr_peer_info>(socket_address, flags, from))
.first->second;
++stats.known_peer_from_count[from]; ++stats.known_peer_from_count[from];
} }
@ -568,19 +564,13 @@ public:
break; break;
case tr_peer_event::Type::ClientGotPort: case tr_peer_event::Type::ClientGotPort:
if (std::empty(event.port)) // We have 2 cases:
// 1. We don't know the listening port of this peer (i.e. incoming connection and first time ClientGotPort)
// 2. We got a new listening port from a known peer
if (auto const& info = msgs->peer_info;
!std::empty(event.port) && info && (std::empty(info->listen_port()) || info->listen_port() != event.port))
{ {
// Do nothing s->on_got_port(msgs, event);
}
// If we don't know the listening port of this peer (i.e. incoming connection and first time ClientGotPort)
else if (auto const& info = *msgs->peer_info; std::empty(info.listen_port()))
{
s->on_got_port(msgs, event, false);
}
// If we got a new listening port from a known connectable peer
else if (info.listen_port() != event.port)
{
s->on_got_port(msgs, event, true);
} }
break; break;
@ -622,9 +612,6 @@ public:
std::unique_ptr<Wishlist> wishlist; std::unique_ptr<Wishlist> wishlist;
// tr_peerMsgs hold pointers to the items in these containers,
// therefore references to elements within cannot invalidate
Pool incoming_pool;
Pool connectable_pool; Pool connectable_pool;
tr_peerMsgs* optimistic = nullptr; /* the optimistic peer, or nullptr if none */ tr_peerMsgs* optimistic = nullptr; /* the optimistic peer, or nullptr if none */
@ -674,7 +661,7 @@ private:
remove_all_peers(); remove_all_peers();
for (auto& [sockaddr, peer_info] : connectable_pool) for (auto& [sockaddr, peer_info] : connectable_pool)
{ {
peer_info.destroy_handshake(); peer_info->destroy_handshake();
} }
} }
@ -717,9 +704,9 @@ private:
{ {
auto const lock = unique_lock(); auto const lock = unique_lock();
for (auto& [socket_address, atom] : connectable_pool) for (auto const& [socket_address, peer_info] : connectable_pool)
{ {
mark_peer_as_seed(atom); mark_peer_as_seed(*peer_info);
} }
mark_all_seeds_flag_dirty(); mark_all_seeds_flag_dirty();
@ -862,89 +849,75 @@ private:
tor->session->add_downloaded(sent_length); tor->session->add_downloaded(sent_length);
} }
void on_got_port(tr_peerMsgs* const msgs, tr_peer_event const& event, bool was_connectable) void on_got_port(tr_peerMsgs* const msgs, tr_peer_event const& event)
{ {
auto& info_this = *msgs->peer_info; auto info_this = msgs->peer_info;
TR_ASSERT(info_this.is_connected()); TR_ASSERT(info_this->is_connected());
TR_ASSERT(was_connectable != std::empty(info_this.listen_port())); TR_ASSERT(info_this->listen_port() != event.port);
// If we already know about this peer, merge the info objects without invalidating references // we already know about this peer
if (auto it_that = connectable_pool.find({ info_this.listen_address(), event.port }); if (auto it_that = connectable_pool.find({ info_this->listen_address(), event.port });
it_that != std::end(connectable_pool)) it_that != std::end(connectable_pool))
{ {
auto& info_that = it_that->second; auto const info_that = it_that->second;
TR_ASSERT(it_that->first == info_that.listen_socket_address()); TR_ASSERT(it_that->first == info_that->listen_socket_address());
TR_ASSERT(it_that->first.address() == info_this.listen_address()); TR_ASSERT(it_that->first.address() == info_this->listen_address());
TR_ASSERT(it_that->first.port() != info_this.listen_port()); TR_ASSERT(it_that->first.port() != info_this->listen_port());
// If there is an existing connection to this peer, keep the better one // if there is an existing connection to this peer, keep the better one
if (info_that.is_connected() && on_got_port_duplicate_connection(msgs, it_that, was_connectable)) if (info_that->is_connected() && on_got_port_duplicate_connection(msgs, info_that))
{ {
return; goto EXIT; // NOLINT cppcoreguidelines-avoid-goto
} }
info_this.merge(info_that); // merge the peer info objects
auto from = info_that.from_first(); info_this->merge(*info_that);
stats.known_peer_from_count[from] -= connectable_pool.erase(info_that.listen_socket_address());
// info_that will be replaced by info_this later, so decrement stat
--stats.known_peer_from_count[info_that->from_first()];
} }
else if (!was_connectable) // we are going to insert a brand-new peer info object to the pool
else if (std::empty(info_this->listen_port()))
{ {
info_this.set_connectable(); info_this->set_connectable();
} }
auto nh = was_connectable ? connectable_pool.extract(info_this.listen_socket_address()) : // erase the old peer info entry
incoming_pool.extract(msgs->socket_address()); stats.known_peer_from_count[info_this->from_first()] -= connectable_pool.erase(info_this->listen_socket_address());
TR_ASSERT(!std::empty(nh));
if (was_connectable)
{
TR_ASSERT(nh.key() == nh.mapped().listen_socket_address());
}
else
{
++stats.known_peer_from_count[nh.mapped().from_first()];
TR_ASSERT(nh.key().address() == nh.mapped().listen_address());
}
nh.key().port_ = event.port;
[[maybe_unused]] auto const inserted = connectable_pool.insert(std::move(nh)).inserted;
TR_ASSERT(inserted);
info_this.set_listen_port(event.port);
// set new listen port
info_this->set_listen_port(event.port);
// insert or replace the peer info ptr at the target location
++stats.known_peer_from_count[info_this->from_first()];
connectable_pool.insert_or_assign(info_this->listen_socket_address(), std::move(info_this));
EXIT:
mark_all_seeds_flag_dirty(); mark_all_seeds_flag_dirty();
} }
bool on_got_port_duplicate_connection(tr_peerMsgs* const msgs, Pool::iterator& it_that, bool was_connectable) bool on_got_port_duplicate_connection(tr_peerMsgs* const msgs, std::shared_ptr<tr_peer_info> info_that)
{ {
auto& info_this = *msgs->peer_info; auto const info_this = msgs->peer_info;
auto& info_that = it_that->second;
TR_ASSERT(info_that.is_connected()); TR_ASSERT(info_that->is_connected());
if (CompareAtomsByUsefulness(info_this, info_that)) if (CompareAtomsByUsefulness(*info_this, *info_that))
{ {
auto it = std::find_if( auto const it = std::find_if(
std::begin(peers), std::begin(peers),
std::end(peers), std::end(peers),
[&info_that](tr_peerMsgs const* const peer) { return peer->peer_info == &info_that; }); [&info_that](tr_peerMsgs const* const peer) { return peer->peer_info == info_that; });
TR_ASSERT(it != std::end(peers)); TR_ASSERT(it != std::end(peers));
(*it)->do_purge = true; (*it)->do_purge = true;
--stats.known_peer_from_count[info_that.from_first()];
// Note that it_that is invalid after this point
graveyard_pool.insert(connectable_pool.extract(it_that));
return false; return false;
} }
info_that.merge(info_this); info_that->merge(*info_this);
msgs->do_purge = true; msgs->do_purge = true;
stats.known_peer_from_count[info_this->from_first()] -= connectable_pool.erase(info_this->listen_socket_address());
if (was_connectable)
{
--stats.known_peer_from_count[info_this.from_first()];
graveyard_pool.insert(connectable_pool.extract(info_this.listen_socket_address()));
}
mark_all_seeds_flag_dirty();
return true; return true;
} }
@ -958,10 +931,6 @@ private:
std::array<libtransmission::ObserverTag, 8> const tags_; std::array<libtransmission::ObserverTag, 8> const tags_;
// tr_peerMsgs hold pointers to the items in these containers,
// therefore references to elements within cannot invalidate
Pool graveyard_pool;
mutable std::optional<bool> pool_is_all_seeds_; mutable std::optional<bool> pool_is_all_seeds_;
bool is_endgame_ = false; bool is_endgame_ = false;
@ -1171,12 +1140,14 @@ private:
since the blocklist has changed, erase that cached value */ since the blocklist has changed, erase that cached value */
for (auto* const tor : torrents_) for (auto* const tor : torrents_)
{ {
for (auto& pool : { std::ref(tor->swarm->connectable_pool), std::ref(tor->swarm->incoming_pool) }) for (auto const& [socket_address, peer_info] : tor->swarm->connectable_pool)
{ {
for (auto& [socket_address, atom] : pool.get()) peer_info->set_blocklisted_dirty();
{ }
atom.set_blocklisted_dirty();
} for (auto* const peer : tor->swarm->peers)
{
peer->peer_info->set_blocklisted_dirty();
} }
} }
} }
@ -1291,22 +1262,26 @@ namespace
{ {
namespace handshake_helpers 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,
std::shared_ptr<tr_peer_info> peer_info,
tr_interned_string client)
{ {
TR_ASSERT(peer_info != nullptr); TR_ASSERT(peer_info);
TR_ASSERT(tor.swarm != nullptr); TR_ASSERT(tor.swarm != nullptr);
tr_swarm* swarm = tor.swarm; tr_swarm* swarm = tor.swarm;
auto* peer = tr_peerMsgs::create(tor, peer_info, std::move(io), client, &tr_swarm::peer_callback_bt, swarm); auto* const
msgs = tr_peerMsgs::create(tor, std::move(peer_info), std::move(io), client, &tr_swarm::peer_callback_bt, swarm);
swarm->peers.push_back(peer); swarm->peers.push_back(msgs);
++swarm->stats.peer_count; ++swarm->stats.peer_count;
++swarm->stats.peer_from_count[peer_info->from_first()]; ++swarm->stats.peer_from_count[msgs->peer_info->from_first()];
TR_ASSERT(swarm->stats.peer_count == swarm->peerCount()); TR_ASSERT(swarm->stats.peer_count == swarm->peerCount());
TR_ASSERT(swarm->stats.peer_from_count[peer_info->from_first()] <= swarm->stats.peer_count); TR_ASSERT(swarm->stats.peer_from_count[msgs->peer_info->from_first()] <= swarm->stats.peer_count);
} }
/* FIXME: this is kind of a mess. */ /* FIXME: this is kind of a mess. */
@ -1317,20 +1292,20 @@ void create_bit_torrent_peer(tr_torrent& tor, std::shared_ptr<tr_peerIo> io, tr_
TR_ASSERT(result.io != nullptr); TR_ASSERT(result.io != nullptr);
auto const& socket_address = result.io->socket_address(); auto const& socket_address = result.io->socket_address();
auto* const swarm = manager->get_existing_swarm(result.io->torrent_hash()); auto* const swarm = manager->get_existing_swarm(result.io->torrent_hash());
auto* info = swarm != nullptr ? swarm->get_existing_peer_info(socket_address) : nullptr; auto info = swarm != nullptr ? swarm->get_existing_peer_info(socket_address) : std::shared_ptr<tr_peer_info>{};
if (result.io->is_incoming()) if (result.io->is_incoming())
{ {
manager->incoming_handshakes.erase(socket_address); manager->incoming_handshakes.erase(socket_address);
} }
else if (info != nullptr) else if (info)
{ {
info->destroy_handshake(); info->destroy_handshake();
} }
if (!result.is_connected || swarm == nullptr || !swarm->is_running) if (!result.is_connected || swarm == nullptr || !swarm->is_running)
{ {
if (info != nullptr && !info->is_connected()) if (info && !info->is_connected())
{ {
info->on_connection_failed(); info->on_connection_failed();
@ -1351,10 +1326,10 @@ void create_bit_torrent_peer(tr_torrent& tor, std::shared_ptr<tr_peerIo> io, tr_
if (result.io->is_incoming()) if (result.io->is_incoming())
{ {
info = &swarm->ensure_info_exists(socket_address, 0U, TR_PEER_FROM_INCOMING, false); info = std::make_shared<tr_peer_info>(socket_address.address(), 0U, TR_PEER_FROM_INCOMING);
} }
if (info == nullptr) if (!info)
{ {
return false; return false;
} }
@ -1395,7 +1370,7 @@ void create_bit_torrent_peer(tr_torrent& tor, std::shared_ptr<tr_peerIo> io, tr_
} }
result.io->set_bandwidth(&swarm->tor->bandwidth()); 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, std::move(info), client);
return true; return true;
} }
@ -1444,7 +1419,7 @@ size_t tr_peerMgrAddPex(tr_torrent* tor, tr_peer_from from, tr_pex const* pex, s
{ {
// we store this peer since it is supposedly connectable (socket address should be the peer's listening address) // we store this peer since it is supposedly connectable (socket address should be the peer's listening address)
// don't care about non-connectable peers that we are not connected to // don't care about non-connectable peers that we are not connected to
s->ensure_info_exists(pex->socket_address, pex->flags, from, true); s->ensure_info_exists(pex->socket_address, pex->flags, from);
++n_used; ++n_used;
} }
} }
@ -1556,7 +1531,7 @@ std::vector<tr_pex> tr_peerMgrGetPeers(tr_torrent const* tor, uint8_t address_ty
{ {
if (peer->socket_address().address().type == address_type) if (peer->socket_address().address().type == address_type)
{ {
infos.emplace_back(peer->peer_info); infos.emplace_back(peer->peer_info.get());
} }
} }
} }
@ -1566,10 +1541,10 @@ std::vector<tr_pex> tr_peerMgrGetPeers(tr_torrent const* tor, uint8_t address_ty
infos.reserve(std::size(pool)); infos.reserve(std::size(pool));
for (auto const& [socket_address, peer_info] : pool) for (auto const& [socket_address, peer_info] : pool)
{ {
TR_ASSERT(socket_address == peer_info.listen_socket_address()); TR_ASSERT(socket_address == peer_info->listen_socket_address());
if (socket_address.address().type == address_type && is_peer_interesting(tor, peer_info)) if (socket_address.address().type == address_type && is_peer_interesting(tor, *peer_info))
{ {
infos.emplace_back(&peer_info); infos.emplace_back(peer_info.get());
} }
} }
} }
@ -2151,7 +2126,7 @@ auto constexpr MaxUploadIdleSecs = time_t{ 60 * 5 };
} }
auto const* tor = s->tor; auto const* tor = s->tor;
auto const* const info = peer->peer_info; auto const& info = peer->peer_info;
/* disconnect if we're both seeds and enough time has passed for PEX */ /* disconnect if we're both seeds and enough time has passed for PEX */
if (tor->is_done() && peer->is_seed()) if (tor->is_done() && peer->is_seed())
@ -2195,7 +2170,7 @@ void close_peer(tr_peerMsgs* peer)
constexpr struct constexpr struct
{ {
[[nodiscard]] constexpr static int compare(tr_peerMsgs const* a, tr_peerMsgs const* b) // <=> [[nodiscard]] static int compare(tr_peerMsgs const* a, tr_peerMsgs const* b) // <=>
{ {
if (a->do_purge != b->do_purge) if (a->do_purge != b->do_purge)
{ {
@ -2205,7 +2180,7 @@ constexpr struct
return -a->peer_info->compare_by_piece_data_time(*b->peer_info); return -a->peer_info->compare_by_piece_data_time(*b->peer_info);
} }
[[nodiscard]] constexpr bool operator()(tr_peerMsgs const* a, tr_peerMsgs const* b) const // less than [[nodiscard]] bool operator()(tr_peerMsgs const* a, tr_peerMsgs const* b) const // less than
{ {
return compare(a, b) < 0; return compare(a, b) < 0;
} }
@ -2419,22 +2394,6 @@ namespace connect_helpers
return true; return true;
} }
struct peer_candidate
{
peer_candidate() = default;
peer_candidate(uint64_t score_in, tr_torrent const* const tor_in, tr_peer_info const* const peer_info_in)
: score{ score_in }
, tor{ tor_in }
, peer_info{ peer_info_in }
{
}
uint64_t score;
tr_torrent const* tor;
tr_peer_info const* peer_info;
};
[[nodiscard]] constexpr uint64_t addValToKey(uint64_t value, unsigned int width, uint64_t addme) [[nodiscard]] constexpr uint64_t addValToKey(uint64_t value, unsigned int width, uint64_t addme)
{ {
value <<= width; value <<= width;
@ -2506,6 +2465,22 @@ struct peer_candidate
void get_peer_candidates(size_t global_peer_limit, tr_torrents& torrents, tr_peerMgr::OutboundCandidates& setme) void get_peer_candidates(size_t global_peer_limit, tr_torrents& torrents, tr_peerMgr::OutboundCandidates& setme)
{ {
struct peer_candidate
{
peer_candidate() = default;
peer_candidate(uint64_t score_in, tr_torrent const* const tor_in, tr_peer_info const* const peer_info_in)
: score{ score_in }
, tor{ tor_in }
, peer_info{ peer_info_in }
{
}
uint64_t score;
tr_torrent const* tor;
tr_peer_info const* peer_info;
};
setme.clear(); setme.clear();
auto const now = tr_time(); auto const now = tr_time();
@ -2551,24 +2526,24 @@ void get_peer_candidates(size_t global_peer_limit, tr_torrents& torrents, tr_pee
continue; continue;
} }
for (auto const& [socket_address, atom] : swarm->connectable_pool) for (auto const& [socket_address, peer_info] : swarm->connectable_pool)
{ {
if (is_peer_candidate(tor, atom, now)) if (is_peer_candidate(tor, *peer_info, now))
{ {
candidates.emplace_back(getPeerCandidateScore(tor, atom, salter()), tor, &atom); candidates.emplace_back(getPeerCandidateScore(tor, *peer_info, salter()), tor, peer_info.get());
} }
} }
} }
// only keep the best `max` candidates // only keep the best `max` candidates
if (auto const max = tr_peerMgr::OutboundCandidates::requested_inline_size; max < std::size(candidates)) if (static auto constexpr Max = tr_peerMgr::OutboundCandidates::requested_inline_size; Max < std::size(candidates))
{ {
std::partial_sort( std::partial_sort(
std::begin(candidates), std::begin(candidates),
std::begin(candidates) + max, std::begin(candidates) + Max,
std::end(candidates), std::end(candidates),
[](auto const& a, auto const& b) { return a.score < b.score; }); [](auto const& a, auto const& b) { return a.score < b.score; });
candidates.resize(max); candidates.resize(Max);
} }
// put the best candidates at the end of the list // put the best candidates at the end of the list
@ -2638,14 +2613,13 @@ void tr_peerMgr::make_new_peer_connections()
// initiate connections to the last N candidates // initiate connections to the last N candidates
auto const n_this_pass = std::min(std::size(candidates), MaxConnectionsPerPulse); auto const n_this_pass = std::min(std::size(candidates), MaxConnectionsPerPulse);
auto const it_end = std::crbegin(candidates) + n_this_pass; for (auto it = std::crbegin(candidates), end = std::crbegin(candidates) + n_this_pass; it != end; ++it)
for (auto it = std::crbegin(candidates); it != it_end; ++it)
{ {
auto const& [tor_id, sock_addr] = *it; auto const& [tor_id, sock_addr] = *it;
if (auto* const tor = torrents_.get(tor_id); tor != nullptr) if (auto* const tor = torrents_.get(tor_id); tor != nullptr)
{ {
if (auto* const peer_info = tor->swarm->get_existing_peer_info(sock_addr); peer_info != nullptr) if (auto const& peer_info = tor->swarm->get_existing_peer_info(sock_addr))
{ {
initiate_connection(this, tor->swarm, *peer_info); initiate_connection(this, tor->swarm, *peer_info);
} }
@ -2660,7 +2634,7 @@ void HandshakeMediator::set_utp_failed(tr_sha1_digest_t const& info_hash, tr_soc
{ {
if (auto* const tor = torrents_.get(info_hash); tor != nullptr) if (auto* const tor = torrents_.get(info_hash); tor != nullptr)
{ {
if (auto* const peer_info = tor->swarm->get_existing_peer_info(socket_address); peer_info != nullptr) if (auto const& peer_info = tor->swarm->get_existing_peer_info(socket_address))
{ {
peer_info->set_utp_supported(false); peer_info->set_utp_supported(false);
} }

View File

@ -305,12 +305,12 @@ class tr_peerMsgsImpl final : public tr_peerMsgs
public: public:
tr_peerMsgsImpl( tr_peerMsgsImpl(
tr_torrent& torrent_in, tr_torrent& torrent_in,
tr_peer_info* const peer_info_in, std::shared_ptr<tr_peer_info> peer_info_in,
std::shared_ptr<tr_peerIo> io_in, std::shared_ptr<tr_peerIo> io_in,
tr_interned_string client, tr_interned_string client,
tr_peer_callback_bt callback, tr_peer_callback_bt callback,
void* callback_data) void* callback_data)
: tr_peerMsgs{ torrent_in, peer_info_in, client, io_in->is_encrypted(), io_in->is_incoming(), io_in->is_utp() } : tr_peerMsgs{ torrent_in, std::move(peer_info_in), client, io_in->is_encrypted(), io_in->is_incoming(), io_in->is_utp() }
, tor_{ torrent_in } , tor_{ torrent_in }
, io_{ std::move(io_in) } , io_{ std::move(io_in) }
, have_{ torrent_in.piece_count() } , have_{ torrent_in.piece_count() }
@ -2054,13 +2054,13 @@ size_t tr_peerMsgsImpl::max_available_reqs() const
tr_peerMsgs::tr_peerMsgs( tr_peerMsgs::tr_peerMsgs(
tr_torrent const& tor, tr_torrent const& tor,
tr_peer_info* peer_info_in, std::shared_ptr<tr_peer_info> peer_info_in,
tr_interned_string user_agent, tr_interned_string user_agent,
bool connection_is_encrypted, bool connection_is_encrypted,
bool connection_is_incoming, bool connection_is_incoming,
bool connection_is_utp) bool connection_is_utp)
: tr_peer{ tor } : tr_peer{ tor }
, peer_info{ peer_info_in } , peer_info{ std::move(peer_info_in) }
, user_agent_{ user_agent } , user_agent_{ user_agent }
, connection_is_encrypted_{ connection_is_encrypted } , connection_is_encrypted_{ connection_is_encrypted }
, connection_is_incoming_{ connection_is_incoming } , connection_is_incoming_{ connection_is_incoming }
@ -2079,11 +2079,11 @@ tr_peerMsgs::~tr_peerMsgs()
tr_peerMsgs* tr_peerMsgs::create( tr_peerMsgs* tr_peerMsgs::create(
tr_torrent& torrent, tr_torrent& torrent,
tr_peer_info* const peer_info, std::shared_ptr<tr_peer_info> peer_info,
std::shared_ptr<tr_peerIo> io, std::shared_ptr<tr_peerIo> io,
tr_interned_string user_agent, tr_interned_string user_agent,
tr_peer_callback_bt callback, tr_peer_callback_bt callback,
void* callback_data) void* callback_data)
{ {
return new tr_peerMsgsImpl{ torrent, peer_info, std::move(io), user_agent, callback, callback_data }; return new tr_peerMsgsImpl{ torrent, std::move(peer_info), std::move(io), user_agent, callback, callback_data };
} }

View File

@ -37,7 +37,7 @@ class tr_peerMsgs : public tr_peer
public: public:
tr_peerMsgs( tr_peerMsgs(
tr_torrent const& tor, tr_torrent const& tor,
tr_peer_info* peer_info_in, std::shared_ptr<tr_peer_info> peer_info_in,
tr_interned_string user_agent, tr_interned_string user_agent,
bool connection_is_encrypted, bool connection_is_encrypted,
bool connection_is_incoming, bool connection_is_incoming,
@ -108,7 +108,7 @@ public:
static tr_peerMsgs* create( static tr_peerMsgs* create(
tr_torrent& torrent, tr_torrent& torrent,
tr_peer_info* peer_info, std::shared_ptr<tr_peer_info> peer_info,
std::shared_ptr<tr_peerIo> io, std::shared_ptr<tr_peerIo> io,
tr_interned_string user_agent, tr_interned_string user_agent,
tr_peer_callback_bt callback, tr_peer_callback_bt callback,
@ -146,8 +146,7 @@ protected:
} }
public: public:
// TODO(tearfur): change this to reference std::shared_ptr<tr_peer_info> const peer_info;
tr_peer_info* const peer_info;
private: private:
static inline auto n_peers = std::atomic<size_t>{}; static inline auto n_peers = std::atomic<size_t>{};