Compare commits

...

12 Commits

Author SHA1 Message Date
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
Pooyan Khanjankhani 821a6816ef
doc: fix typo (#6790) 2024-04-21 18:21:17 -05:00
Dzmitry Neviadomski ef18816b7f
Fix code style script path in CONTRIBUTING.md (#6787)
Signed-off-by: Dzmitry Neviadomski <nevack.d@gmail.com>
2024-04-21 07:36:13 -05:00
Dzmitry Neviadomski 0e25584e78
Make std::hash specialization for tr_socket_address a struct (#6788)
To be in line with std::hash declaration

See https://en.cppreference.com/w/cpp/utility/hash

Signed-off-by: Dzmitry Neviadomski <nevack.d@gmail.com>
2024-04-20 21:01:47 -05:00
6 changed files with 147 additions and 174 deletions

View File

@ -41,7 +41,7 @@ On macOS, Transmission is usually built with Xcode. Everywhere else, it's CMake
- Prefer `enum class` over `enum` - Prefer `enum class` over `enum`
- Prefer new-style headers, e.g. `<cstring>` over `<string.h>` - Prefer new-style headers, e.g. `<cstring>` over `<string.h>`
- Fix any warnings in new code before merging - Fix any warnings in new code before merging
- Run `./code-style.sh` on your code to ensure the whole codebase has consistent indentation. - Run `./code_style.sh` on your code to ensure the whole codebase has consistent indentation.
Note that Transmission existed in C for over a decade and those idioms don't change overnight. "Follow the C++ core guidelines" can be difficult when working with older code, and the maintainers will understand that when reviewing your PRs. :smiley: Note that Transmission existed in C for over a decade and those idioms don't change overnight. "Follow the C++ core guidelines" can be difficult when working with older code, and the maintainers will understand that when reviewing your PRs. :smiley:

View File

@ -404,7 +404,7 @@ struct tr_socket_address
}; };
template<> template<>
class std::hash<tr_socket_address> struct std::hash<tr_socket_address>
{ {
public: public:
std::size_t operator()(tr_socket_address const& socket_address) const noexcept std::size_t operator()(tr_socket_address const& socket_address) const noexcept

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>{};

View File

@ -150,7 +150,7 @@ Get a file list for the current torrent(s)
.It Fl g Fl -get Ar all | file-index | files .It Fl g Fl -get Ar all | file-index | files
Mark file(s) for download. Mark file(s) for download.
.Ar all .Ar all
marks all all of the torrent's files for downloading, marks all of the torrent's files for downloading,
.Ar file-index .Ar file-index
adds a single file to the download list, and adds a single file to the download list, and
.Ar files .Ar files