mirror of
https://github.com/transmission/transmission
synced 2025-03-04 02:28:03 +00:00
refactor: use namespaces in peer-msgs.cc (#3370)
This commit is contained in:
parent
e683cd504c
commit
5407c89237
1 changed files with 251 additions and 191 deletions
|
@ -49,16 +49,6 @@
|
|||
#include "utils.h"
|
||||
#include "webseed.h"
|
||||
|
||||
// an optimistically unchoked peer is immune from rechoking
|
||||
// for this many calls to rechokeUploads().
|
||||
static auto constexpr OptimisticUnchokeMultiplier = uint8_t{ 4 };
|
||||
|
||||
// when many peers are available, keep idle ones this long
|
||||
static auto constexpr MinUploadIdleSecs = int{ 60 };
|
||||
|
||||
// when few peers are available, keep idle ones this long
|
||||
static auto constexpr MaxUploadIdleSecs = int{ 60 * 5 };
|
||||
|
||||
// use for bitwise operations w/peer_atom.flags2
|
||||
static auto constexpr MyflagBanned = int{ 1 };
|
||||
|
||||
|
@ -67,9 +57,6 @@ static auto constexpr MyflagBanned = int{ 1 };
|
|||
// if they try to connect to us it's okay
|
||||
static auto constexpr MyflagUnreachable = int{ 2 };
|
||||
|
||||
// how long we'll let requests we've made linger before we cancel them
|
||||
static auto constexpr RequestTtlSecs = int{ 90 };
|
||||
|
||||
static auto constexpr CancelHistorySec = int{ 60 };
|
||||
|
||||
/**
|
||||
|
@ -301,11 +288,94 @@ public:
|
|||
rebuildWebseeds();
|
||||
}
|
||||
|
||||
void cancelOldRequests()
|
||||
{
|
||||
auto const now = tr_time();
|
||||
auto const oldest = now - RequestTtlSecs;
|
||||
|
||||
for (auto const& [block, peer] : active_requests.sentBefore(oldest))
|
||||
{
|
||||
maybeSendCancelRequest(peer, block, nullptr);
|
||||
active_requests.remove(block, peer);
|
||||
}
|
||||
}
|
||||
|
||||
void cancelAllRequestsForBlock(tr_block_index_t block, tr_peer const* no_notify)
|
||||
{
|
||||
for (auto* peer : active_requests.remove(block))
|
||||
{
|
||||
maybeSendCancelRequest(peer, block, no_notify);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] auto unique_lock() const
|
||||
{
|
||||
return tor->unique_lock();
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t countActiveWebseeds() const noexcept
|
||||
{
|
||||
if (!tor->isRunning || tor->isDone())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto const now = tr_time_msec();
|
||||
|
||||
return std::count_if(
|
||||
std::begin(webseeds),
|
||||
std::end(webseeds),
|
||||
[&now](auto const& webseed) { return webseed->isTransferringPieces(now, TR_DOWN, nullptr); });
|
||||
}
|
||||
|
||||
[[nodiscard]] auto peerCount() const noexcept
|
||||
{
|
||||
return std::size(peers);
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
auto const lock = unique_lock();
|
||||
|
||||
is_running = false;
|
||||
removeAllPeers();
|
||||
outgoing_handshakes.abortAll();
|
||||
}
|
||||
|
||||
void removePeer(tr_peer* peer)
|
||||
{
|
||||
auto const lock = unique_lock();
|
||||
|
||||
auto* const atom = peer->atom;
|
||||
TR_ASSERT(atom != nullptr);
|
||||
|
||||
atom->time = tr_time();
|
||||
|
||||
if (auto iter = std::find(std::begin(peers), std::end(peers), peer); iter != std::end(peers))
|
||||
{
|
||||
peers.erase(iter);
|
||||
}
|
||||
|
||||
--stats.peer_count;
|
||||
--stats.peer_from_count[atom->fromFirst];
|
||||
|
||||
TR_ASSERT(stats.peer_count == peerCount());
|
||||
|
||||
delete peer;
|
||||
}
|
||||
|
||||
void removeAllPeers()
|
||||
{
|
||||
auto tmp = peers;
|
||||
|
||||
for (auto* peer : tmp)
|
||||
{
|
||||
removePeer(peer);
|
||||
}
|
||||
|
||||
TR_ASSERT(stats.peer_count == 0);
|
||||
}
|
||||
|
||||
void updateEndgame()
|
||||
{
|
||||
/* we consider ourselves to be in endgame if the number of bytes
|
||||
|
@ -391,9 +461,22 @@ public:
|
|||
ActiveRequests active_requests;
|
||||
|
||||
private:
|
||||
static void maybeSendCancelRequest(tr_peer* peer, tr_block_index_t block, tr_peer const* muted)
|
||||
{
|
||||
auto* msgs = dynamic_cast<tr_peerMsgs*>(peer);
|
||||
if (msgs != nullptr && msgs != muted)
|
||||
{
|
||||
peer->cancels_sent_to_peer.add(tr_time(), 1);
|
||||
msgs->cancel_block_request(block);
|
||||
}
|
||||
}
|
||||
|
||||
// number of bad pieces a peer is allowed to send before we ban them
|
||||
static auto constexpr MaxBadPiecesPerPeer = int{ 5 };
|
||||
|
||||
// how long we'll let requests we've made linger before we cancel them
|
||||
static auto constexpr RequestTtlSecs = int{ 90 };
|
||||
|
||||
mutable std::optional<bool> pool_is_all_seeds_;
|
||||
|
||||
bool is_endgame_ = false;
|
||||
|
@ -542,7 +625,7 @@ static struct peer_atom* getExistingAtom(tr_swarm const* cswarm, tr_address cons
|
|||
static bool peerIsInUse(tr_swarm const* cs, struct peer_atom const* atom)
|
||||
{
|
||||
auto const* const s = const_cast<tr_swarm*>(cs);
|
||||
auto const lock = s->manager->unique_lock();
|
||||
auto const lock = s->unique_lock();
|
||||
|
||||
return atom->is_connected || s->outgoing_handshakes.contains(atom->addr) ||
|
||||
s->manager->incoming_handshakes.contains(atom->addr);
|
||||
|
@ -551,7 +634,7 @@ static bool peerIsInUse(tr_swarm const* cs, struct peer_atom const* atom)
|
|||
static void swarmFree(tr_swarm* s)
|
||||
{
|
||||
TR_ASSERT(s != nullptr);
|
||||
auto const lock = s->manager->unique_lock();
|
||||
auto const lock = s->unique_lock();
|
||||
|
||||
TR_ASSERT(!s->is_running);
|
||||
TR_ASSERT(std::empty(s->outgoing_handshakes));
|
||||
|
@ -562,11 +645,6 @@ static void swarmFree(tr_swarm* s)
|
|||
delete s;
|
||||
}
|
||||
|
||||
static tr_swarm* swarmNew(tr_peerMgr* manager, tr_torrent* tor)
|
||||
{
|
||||
return new tr_swarm{ manager, tor };
|
||||
}
|
||||
|
||||
tr_peerMgr* tr_peerMgrNew(tr_session* session)
|
||||
{
|
||||
return new tr_peerMgr{ session };
|
||||
|
@ -650,21 +728,6 @@ void tr_peerMgrSetUtpFailed(tr_torrent* tor, tr_address const& addr, bool failed
|
|||
*** struct block_request
|
||||
**/
|
||||
|
||||
[[nodiscard]] static uint16_t countActiveWebseeds(tr_swarm* s) noexcept
|
||||
{
|
||||
if (!s->tor->isRunning || s->tor->isDone())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto const now = tr_time_msec();
|
||||
|
||||
return std::count_if(
|
||||
std::begin(s->webseeds),
|
||||
std::end(s->webseeds),
|
||||
[&now](auto const& webseed) { return webseed->isTransferringPieces(now, TR_DOWN, nullptr); });
|
||||
}
|
||||
|
||||
// TODO: if we keep this, add equivalent API to ActiveRequest
|
||||
void tr_peerMgrClientSentRequests(tr_torrent* torrent, tr_peer* peer, tr_block_span_t span)
|
||||
{
|
||||
|
@ -756,43 +819,13 @@ size_t tr_peerMgrCountActiveRequestsToPeer(tr_torrent const* tor, tr_peer const*
|
|||
return tor->swarm->active_requests.count(peer);
|
||||
}
|
||||
|
||||
static void maybeSendCancelRequest(tr_peer* peer, tr_block_index_t block, tr_peer const* muted)
|
||||
{
|
||||
auto* msgs = dynamic_cast<tr_peerMsgs*>(peer);
|
||||
if (msgs != nullptr && msgs != muted)
|
||||
{
|
||||
peer->cancels_sent_to_peer.add(tr_time(), 1);
|
||||
msgs->cancel_block_request(block);
|
||||
}
|
||||
}
|
||||
|
||||
static void cancelAllRequestsForBlock(tr_swarm* swarm, tr_block_index_t block, tr_peer const* no_notify)
|
||||
{
|
||||
for (auto* peer : swarm->active_requests.remove(block))
|
||||
{
|
||||
maybeSendCancelRequest(peer, block, no_notify);
|
||||
}
|
||||
}
|
||||
|
||||
static void tr_swarmCancelOldRequests(tr_swarm* swarm)
|
||||
{
|
||||
auto const now = tr_time();
|
||||
auto const oldest = now - RequestTtlSecs;
|
||||
|
||||
for (auto const& [block, peer] : swarm->active_requests.sentBefore(oldest))
|
||||
{
|
||||
maybeSendCancelRequest(peer, block, nullptr);
|
||||
swarm->active_requests.remove(block, peer);
|
||||
}
|
||||
}
|
||||
|
||||
void tr_peerMgr::refillUpkeep() const
|
||||
{
|
||||
auto const lock = unique_lock();
|
||||
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
tr_swarmCancelOldRequests(tor->swarm);
|
||||
tor->swarm->cancelOldRequests();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -877,7 +910,7 @@ static void peerCallbackFunc(tr_peer* peer, tr_peer_event const* e, void* vs)
|
|||
{
|
||||
TR_ASSERT(peer != nullptr);
|
||||
auto* s = static_cast<tr_swarm*>(vs);
|
||||
auto const lock = s->manager->unique_lock();
|
||||
auto const lock = s->unique_lock();
|
||||
|
||||
switch (e->eventType)
|
||||
{
|
||||
|
@ -955,7 +988,7 @@ static void peerCallbackFunc(tr_peer* peer, tr_peer_event const* e, void* vs)
|
|||
{
|
||||
auto* const tor = s->tor;
|
||||
auto const loc = tor->pieceLoc(e->pieceIndex, e->offset);
|
||||
cancelAllRequestsForBlock(s, loc.block, peer);
|
||||
s->cancelAllRequestsForBlock(loc.block, peer);
|
||||
peer->blocks_sent_to_client.add(tr_time(), 1);
|
||||
tr_torrentGotBlock(tor, loc.block);
|
||||
break;
|
||||
|
@ -1270,10 +1303,13 @@ void tr_peerMgrGotBadPiece(tr_torrent* tor, tr_piece_index_t pieceIndex)
|
|||
tr_announcerAddBytes(tor, TR_ANN_CORRUPT, byteCount);
|
||||
}
|
||||
|
||||
namespace get_peers_helpers
|
||||
{
|
||||
|
||||
/* better goes first */
|
||||
struct CompareAtomsByUsefulness
|
||||
{
|
||||
[[nodiscard]] static int compare(peer_atom const& a, peer_atom const& b) noexcept // <=>
|
||||
[[nodiscard]] constexpr static int compare(peer_atom const& a, peer_atom const& b) noexcept // <=>
|
||||
{
|
||||
if (a.piece_data_time != b.piece_data_time)
|
||||
{
|
||||
|
@ -1293,18 +1329,18 @@ struct CompareAtomsByUsefulness
|
|||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator()(peer_atom const& a, peer_atom const& b) const noexcept
|
||||
[[nodiscard]] constexpr bool operator()(peer_atom const& a, peer_atom const& b) const noexcept
|
||||
{
|
||||
return compare(a, b) < 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator()(peer_atom const* a, peer_atom const* b) const noexcept
|
||||
[[nodiscard]] constexpr bool operator()(peer_atom const* a, peer_atom const* b) const noexcept
|
||||
{
|
||||
return compare(*a, *b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
static bool isAtomInteresting(tr_torrent const* tor, peer_atom const& atom)
|
||||
[[nodiscard]] bool isAtomInteresting(tr_torrent const* tor, peer_atom const& atom)
|
||||
{
|
||||
if (tor->isDone() && atom.isSeed())
|
||||
{
|
||||
|
@ -1329,9 +1365,12 @@ static bool isAtomInteresting(tr_torrent const* tor, peer_atom const& atom)
|
|||
return true;
|
||||
}
|
||||
|
||||
// TODO: return a std::vector
|
||||
} // namespace get_peers_helpers
|
||||
|
||||
std::vector<tr_pex> tr_peerMgrGetPeers(tr_torrent const* tor, uint8_t af, uint8_t list_mode, size_t max_count)
|
||||
{
|
||||
using namespace get_peers_helpers;
|
||||
|
||||
TR_ASSERT(tr_isTorrent(tor));
|
||||
auto const lock = tor->unique_lock();
|
||||
|
||||
|
@ -1403,23 +1442,11 @@ void tr_peerMgrStartTorrent(tr_torrent* tor)
|
|||
swarm->manager->rechokeSoon();
|
||||
}
|
||||
|
||||
static void removeAllPeers(tr_swarm* /*swarm*/);
|
||||
|
||||
static void stopSwarm(tr_swarm* swarm)
|
||||
{
|
||||
swarm->is_running = false;
|
||||
|
||||
removeAllPeers(swarm);
|
||||
|
||||
swarm->outgoing_handshakes.abortAll();
|
||||
}
|
||||
|
||||
void tr_peerMgrStopTorrent(tr_torrent* tor)
|
||||
{
|
||||
TR_ASSERT(tr_isTorrent(tor));
|
||||
auto const lock = tor->unique_lock();
|
||||
|
||||
stopSwarm(tor->swarm);
|
||||
tor->swarm->stop();
|
||||
}
|
||||
|
||||
void tr_peerMgrAddTorrent(tr_peerMgr* manager, tr_torrent* tor)
|
||||
|
@ -1428,7 +1455,7 @@ void tr_peerMgrAddTorrent(tr_peerMgr* manager, tr_torrent* tor)
|
|||
auto const lock = tor->unique_lock();
|
||||
TR_ASSERT(tor->swarm == nullptr);
|
||||
|
||||
tor->swarm = swarmNew(manager, tor);
|
||||
tor->swarm = new tr_swarm{ manager, tor };
|
||||
}
|
||||
|
||||
void tr_peerMgrRemoveTorrent(tr_torrent* tor)
|
||||
|
@ -1436,7 +1463,7 @@ void tr_peerMgrRemoveTorrent(tr_torrent* tor)
|
|||
TR_ASSERT(tr_isTorrent(tor));
|
||||
auto const lock = tor->unique_lock();
|
||||
|
||||
stopSwarm(tor->swarm);
|
||||
tor->swarm->stop();
|
||||
swarmFree(tor->swarm);
|
||||
}
|
||||
|
||||
|
@ -1594,7 +1621,10 @@ tr_webseed_view tr_peerMgrWebseed(tr_torrent const* tor, size_t i)
|
|||
return i >= n ? tr_webseed_view{} : tr_webseedView(tor->swarm->webseeds[i].get());
|
||||
}
|
||||
|
||||
static auto getPeerStats(tr_peerMsgs const* peer, time_t now, uint64_t now_msec)
|
||||
namespace peer_stat_helpers
|
||||
{
|
||||
|
||||
[[nodiscard]] auto getPeerStats(tr_peerMsgs const* peer, time_t now, uint64_t now_msec)
|
||||
{
|
||||
auto stats = tr_peer_stat{};
|
||||
auto const* const atom = peer->atom;
|
||||
|
@ -1691,8 +1721,12 @@ static auto getPeerStats(tr_peerMsgs const* peer, time_t now, uint64_t now_msec)
|
|||
return stats;
|
||||
}
|
||||
|
||||
struct tr_peer_stat* tr_peerMgrPeerStats(tr_torrent const* tor, int* setme_count)
|
||||
} // namespace peer_stat_helpers
|
||||
|
||||
tr_peer_stat* tr_peerMgrPeerStats(tr_torrent const* tor, int* setme_count)
|
||||
{
|
||||
using namespace peer_stat_helpers;
|
||||
|
||||
TR_ASSERT(tr_isTorrent(tor));
|
||||
TR_ASSERT(tor->swarm->manager != nullptr);
|
||||
|
||||
|
@ -1711,11 +1745,6 @@ struct tr_peer_stat* tr_peerMgrPeerStats(tr_torrent const* tor, int* setme_count
|
|||
return ret;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
****
|
||||
***/
|
||||
|
||||
void tr_peerMgrClearInterest(tr_torrent* tor)
|
||||
{
|
||||
TR_ASSERT(tr_isTorrent(tor));
|
||||
|
@ -1725,8 +1754,16 @@ void tr_peerMgrClearInterest(tr_torrent* tor)
|
|||
std::for_each(std::begin(peers), std::end(peers), [](auto* const peer) { peer->set_interested(false); });
|
||||
}
|
||||
|
||||
namespace rechoke_downloads_helpers
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
/* does this peer have any pieces that we want? */
|
||||
static bool isPeerInteresting(tr_torrent* const tor, bool const* const piece_is_interesting, tr_peerMsgs const* const peer)
|
||||
[[nodiscard]] bool isPeerInteresting(
|
||||
tr_torrent* const tor,
|
||||
bool const* const piece_is_interesting,
|
||||
tr_peerMsgs const* const peer)
|
||||
{
|
||||
/* these cases should have already been handled by the calling code... */
|
||||
TR_ASSERT(!tor->isDone());
|
||||
|
@ -1762,7 +1799,7 @@ struct tr_rechoke_info
|
|||
int rechoke_state;
|
||||
};
|
||||
|
||||
static constexpr int compare_rechoke_info(void const* va, void const* vb)
|
||||
[[nodiscard]] constexpr int compare_rechoke_info(void const* va, void const* vb)
|
||||
{
|
||||
auto const* const a = static_cast<struct tr_rechoke_info const*>(va);
|
||||
auto const* const b = static_cast<struct tr_rechoke_info const*>(vb);
|
||||
|
@ -1775,8 +1812,10 @@ static constexpr int compare_rechoke_info(void const* va, void const* vb)
|
|||
return a->salt - b->salt;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/* determines who we send "interested" messages to */
|
||||
static void rechokeDownloads(tr_swarm* s)
|
||||
void rechokeDownloads(tr_swarm* s)
|
||||
{
|
||||
static auto constexpr MinInterestingPeers = uint16_t{ 5 };
|
||||
|
||||
|
@ -1945,10 +1984,29 @@ static void rechokeDownloads(tr_swarm* s)
|
|||
tr_free(rechoke);
|
||||
}
|
||||
|
||||
} // namespace rechoke_downloads_helpers
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
[[nodiscard]] static inline bool isBandwidthMaxedOut(Bandwidth const& b, uint64_t const now_msec, tr_direction dir)
|
||||
{
|
||||
if (!b.isLimited(dir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int const got = b.getPieceSpeedBytesPerSecond(now_msec, dir);
|
||||
unsigned int const want = b.getDesiredSpeedBytesPerSecond(dir);
|
||||
return got >= want;
|
||||
}
|
||||
|
||||
namespace rechoke_uploads_helpers
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
struct ChokeData
|
||||
{
|
||||
bool isInterested;
|
||||
|
@ -1959,22 +2017,22 @@ struct ChokeData
|
|||
tr_peerMsgs* msgs;
|
||||
};
|
||||
|
||||
static int compareChoke(void const* va, void const* vb)
|
||||
[[nodiscard]] constexpr int compareChoke(void const* va, void const* vb) noexcept
|
||||
{
|
||||
auto const* const a = static_cast<struct ChokeData const*>(va);
|
||||
auto const* const b = static_cast<struct ChokeData const*>(vb);
|
||||
|
||||
if (a->rate != b->rate) /* prefer higher overall speeds */
|
||||
if (a->rate != b->rate) // prefer higher overall speeds
|
||||
{
|
||||
return a->rate > b->rate ? -1 : 1;
|
||||
}
|
||||
|
||||
if (a->wasChoked != b->wasChoked) /* prefer unchoked */
|
||||
if (a->wasChoked != b->wasChoked) // prefer unchoked
|
||||
{
|
||||
return a->wasChoked ? 1 : -1;
|
||||
}
|
||||
|
||||
if (a->salt != b->salt) /* random order */
|
||||
if (a->salt != b->salt) // random order
|
||||
{
|
||||
return a->salt - b->salt;
|
||||
}
|
||||
|
@ -1983,14 +2041,14 @@ static int compareChoke(void const* va, void const* vb)
|
|||
}
|
||||
|
||||
/* is this a new connection? */
|
||||
static bool isNew(tr_peerMsgs const* msgs)
|
||||
[[nodiscard]] bool isNew(tr_peerMsgs const* msgs)
|
||||
{
|
||||
auto constexpr CutoffSecs = time_t{ 45 };
|
||||
return msgs != nullptr && !msgs->is_connection_older_than(tr_time() - CutoffSecs);
|
||||
}
|
||||
|
||||
/* get a rate for deciding which peers to choke and unchoke. */
|
||||
static auto getRateBps(tr_torrent const* tor, tr_peer const* peer, uint64_t now)
|
||||
[[nodiscard]] auto getRateBps(tr_torrent const* tor, tr_peer const* peer, uint64_t now)
|
||||
{
|
||||
if (tor->isDone())
|
||||
{
|
||||
|
@ -2008,21 +2066,15 @@ static auto getRateBps(tr_torrent const* tor, tr_peer const* peer, uint64_t now)
|
|||
return tr_peerGetPieceSpeed_Bps(peer, now, TR_PEER_TO_CLIENT);
|
||||
}
|
||||
|
||||
static inline bool isBandwidthMaxedOut(Bandwidth const& b, uint64_t const now_msec, tr_direction dir)
|
||||
{
|
||||
if (!b.isLimited(dir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// an optimistically unchoked peer is immune from rechoking
|
||||
// for this many calls to rechokeUploads().
|
||||
auto constexpr OptimisticUnchokeMultiplier = uint8_t{ 4 };
|
||||
|
||||
unsigned int const got = b.getPieceSpeedBytesPerSecond(now_msec, dir);
|
||||
unsigned int const want = b.getDesiredSpeedBytesPerSecond(dir);
|
||||
return got >= want;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
static void rechokeUploads(tr_swarm* s, uint64_t const now)
|
||||
void rechokeUploads(tr_swarm* s, uint64_t const now)
|
||||
{
|
||||
auto const lock = s->manager->unique_lock();
|
||||
auto const lock = s->unique_lock();
|
||||
|
||||
auto const peerCount = s->peerCount();
|
||||
auto& peers = s->peers;
|
||||
|
@ -2139,8 +2191,13 @@ static void rechokeUploads(tr_swarm* s, uint64_t const now)
|
|||
tr_free(choke);
|
||||
}
|
||||
|
||||
} // namespace rechoke_uploads_helpers
|
||||
|
||||
void tr_peerMgr::rechokePulse() const
|
||||
{
|
||||
using namespace rechoke_downloads_helpers;
|
||||
using namespace rechoke_uploads_helpers;
|
||||
|
||||
auto const lock = unique_lock();
|
||||
auto const now = tr_time_msec();
|
||||
|
||||
|
@ -2165,7 +2222,17 @@ void tr_peerMgr::rechokePulse() const
|
|||
****
|
||||
***/
|
||||
|
||||
static bool shouldPeerBeClosed(tr_swarm const* s, tr_peerMsgs const* peer, int peerCount, time_t const now)
|
||||
namespace disconnect_helpers
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// when many peers are available, keep idle ones this long
|
||||
auto constexpr MinUploadIdleSecs = int{ 60 };
|
||||
|
||||
// when few peers are available, keep idle ones this long
|
||||
auto constexpr MaxUploadIdleSecs = int{ 60 * 5 };
|
||||
|
||||
[[nodiscard]] bool shouldPeerBeClosed(tr_swarm const* s, tr_peerMsgs const* peer, int peerCount, time_t const now)
|
||||
{
|
||||
/* if it's marked for purging, close it */
|
||||
if (peer->do_purge)
|
||||
|
@ -2208,30 +2275,7 @@ static bool shouldPeerBeClosed(tr_swarm const* s, tr_peerMsgs const* peer, int p
|
|||
return false;
|
||||
}
|
||||
|
||||
static void removePeer(tr_peer* peer)
|
||||
{
|
||||
auto* const s = peer->swarm;
|
||||
auto const lock = s->manager->unique_lock();
|
||||
|
||||
auto* const atom = peer->atom;
|
||||
TR_ASSERT(atom != nullptr);
|
||||
|
||||
atom->time = tr_time();
|
||||
|
||||
if (auto iter = std::find(std::begin(s->peers), std::end(s->peers), peer); iter != std::end(s->peers))
|
||||
{
|
||||
s->peers.erase(iter);
|
||||
}
|
||||
|
||||
--s->stats.peer_count;
|
||||
--s->stats.peer_from_count[atom->fromFirst];
|
||||
|
||||
TR_ASSERT(s->stats.peer_count == s->peerCount());
|
||||
|
||||
delete peer;
|
||||
}
|
||||
|
||||
static void closePeer(tr_peer* peer)
|
||||
void closePeer(tr_peer* peer)
|
||||
{
|
||||
TR_ASSERT(peer != nullptr);
|
||||
auto const* const s = peer->swarm;
|
||||
|
@ -2251,46 +2295,12 @@ static void closePeer(tr_peer* peer)
|
|||
}
|
||||
|
||||
tr_logAddTraceSwarm(s, fmt::format("removing bad peer {}", peer->readable()));
|
||||
removePeer(peer);
|
||||
}
|
||||
|
||||
static void removeAllPeers(tr_swarm* swarm)
|
||||
{
|
||||
auto tmp = swarm->peers;
|
||||
std::for_each(std::begin(tmp), std::end(tmp), removePeer);
|
||||
|
||||
TR_ASSERT(swarm->stats.peer_count == 0);
|
||||
}
|
||||
|
||||
static auto getPeersToClose(tr_swarm* swarm, time_t const now_sec)
|
||||
{
|
||||
auto peers_to_close = std::vector<tr_peer*>{};
|
||||
|
||||
auto const peer_count = swarm->peerCount();
|
||||
for (auto* peer : swarm->peers)
|
||||
{
|
||||
if (shouldPeerBeClosed(swarm, peer, peer_count, now_sec))
|
||||
{
|
||||
peers_to_close.push_back(peer);
|
||||
}
|
||||
}
|
||||
|
||||
return peers_to_close;
|
||||
}
|
||||
|
||||
static void closeBadPeers(tr_swarm* s, time_t const now_sec)
|
||||
{
|
||||
auto const lock = s->manager->unique_lock();
|
||||
|
||||
for (auto* peer : getPeersToClose(s, now_sec))
|
||||
{
|
||||
closePeer(peer);
|
||||
}
|
||||
peer->swarm->removePeer(peer);
|
||||
}
|
||||
|
||||
struct ComparePeerByActivity
|
||||
{
|
||||
static int compare(tr_peer const* a, tr_peer const* b) // <=>
|
||||
[[nodiscard]] constexpr static int compare(tr_peer const* a, tr_peer const* b) // <=>
|
||||
{
|
||||
if (a->do_purge != b->do_purge)
|
||||
{
|
||||
|
@ -2312,13 +2322,41 @@ struct ComparePeerByActivity
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool operator()(tr_peer const* a, tr_peer const* b) const // less then
|
||||
[[nodiscard]] constexpr bool operator()(tr_peer const* a, tr_peer const* b) const // less then
|
||||
{
|
||||
return compare(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
static void enforceTorrentPeerLimit(tr_swarm* swarm)
|
||||
[[nodiscard]] auto getPeersToClose(tr_swarm* swarm, time_t const now_sec)
|
||||
{
|
||||
auto peers_to_close = std::vector<tr_peer*>{};
|
||||
|
||||
auto const peer_count = swarm->peerCount();
|
||||
for (auto* peer : swarm->peers)
|
||||
{
|
||||
if (shouldPeerBeClosed(swarm, peer, peer_count, now_sec))
|
||||
{
|
||||
peers_to_close.push_back(peer);
|
||||
}
|
||||
}
|
||||
|
||||
return peers_to_close;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void closeBadPeers(tr_swarm* s, time_t const now_sec)
|
||||
{
|
||||
auto const lock = s->unique_lock();
|
||||
|
||||
for (auto* peer : getPeersToClose(s, now_sec))
|
||||
{
|
||||
closePeer(peer);
|
||||
}
|
||||
}
|
||||
|
||||
void enforceTorrentPeerLimit(tr_swarm* swarm)
|
||||
{
|
||||
// do we have too many peers?
|
||||
auto const n = swarm->peerCount();
|
||||
|
@ -2334,7 +2372,7 @@ static void enforceTorrentPeerLimit(tr_swarm* swarm)
|
|||
std::for_each(std::begin(peers) + max, std::end(peers), closePeer);
|
||||
}
|
||||
|
||||
static void enforceSessionPeerLimit(tr_session* session)
|
||||
void enforceSessionPeerLimit(tr_session* session)
|
||||
{
|
||||
// do we have too many peers?
|
||||
auto const& torrents = session->torrents();
|
||||
|
@ -2362,16 +2400,20 @@ static void enforceSessionPeerLimit(tr_session* session)
|
|||
std::for_each(std::begin(peers) + max, std::end(peers), closePeer);
|
||||
}
|
||||
|
||||
} // namespace disconnect_helpers
|
||||
|
||||
void tr_peerMgr::reconnectPulse()
|
||||
{
|
||||
time_t const now_sec = tr_time();
|
||||
using namespace disconnect_helpers;
|
||||
|
||||
auto const now_sec = tr_time();
|
||||
|
||||
// remove crappy peers
|
||||
for (auto* const tor : session->torrents())
|
||||
{
|
||||
if (!tor->swarm->is_running)
|
||||
{
|
||||
removeAllPeers(tor->swarm);
|
||||
tor->swarm->removeAllPeers();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2402,7 +2444,10 @@ void tr_peerMgr::reconnectPulse()
|
|||
*****
|
||||
****/
|
||||
|
||||
static void pumpAllPeers(tr_peerMgr* mgr)
|
||||
namespace bandwidth_helpers
|
||||
{
|
||||
|
||||
void pumpAllPeers(tr_peerMgr* mgr)
|
||||
{
|
||||
for (auto* const tor : mgr->session->torrents())
|
||||
{
|
||||
|
@ -2413,7 +2458,7 @@ static void pumpAllPeers(tr_peerMgr* mgr)
|
|||
}
|
||||
}
|
||||
|
||||
static void queuePulse(tr_session* session, tr_direction dir)
|
||||
void queuePulse(tr_session* session, tr_direction dir)
|
||||
{
|
||||
TR_ASSERT(tr_isSession(session));
|
||||
TR_ASSERT(tr_isDirection(dir));
|
||||
|
@ -2434,8 +2479,12 @@ static void queuePulse(tr_session* session, tr_direction dir)
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace bandwidth_helpers
|
||||
|
||||
void tr_peerMgr::bandwidthPulse()
|
||||
{
|
||||
using namespace bandwidth_helpers;
|
||||
|
||||
auto const lock = unique_lock();
|
||||
|
||||
pumpAllPeers(this);
|
||||
|
@ -2465,7 +2514,7 @@ void tr_peerMgr::bandwidthPulse()
|
|||
}
|
||||
|
||||
/* update the torrent's stats */
|
||||
tor->swarm->stats.active_webseed_count = countActiveWebseeds(tor->swarm);
|
||||
tor->swarm->stats.active_webseed_count = tor->swarm->countActiveWebseeds();
|
||||
}
|
||||
|
||||
/* pump the queues */
|
||||
|
@ -2481,8 +2530,13 @@ void tr_peerMgr::bandwidthPulse()
|
|||
****
|
||||
***/
|
||||
|
||||
namespace connect_helpers
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
/* is this atom someone that we'd want to initiate a connection to? */
|
||||
static bool isPeerCandidate(tr_torrent const* tor, peer_atom const& atom, time_t const now)
|
||||
[[nodiscard]] bool isPeerCandidate(tr_torrent const* tor, peer_atom const& atom, time_t const now)
|
||||
{
|
||||
// have we already tried and failed to connect?
|
||||
if (auto const reachable = atom.isReachable(); reachable && !*reachable)
|
||||
|
@ -2530,12 +2584,12 @@ struct peer_candidate
|
|||
peer_atom* atom;
|
||||
};
|
||||
|
||||
static bool torrentWasRecentlyStarted(tr_torrent const* tor)
|
||||
[[nodiscard]] bool torrentWasRecentlyStarted(tr_torrent const* tor)
|
||||
{
|
||||
return difftime(tr_time(), tor->startDate) < 120;
|
||||
}
|
||||
|
||||
static constexpr uint64_t addValToKey(uint64_t value, int width, uint64_t addme)
|
||||
[[nodiscard]] constexpr uint64_t addValToKey(uint64_t value, int width, uint64_t addme)
|
||||
{
|
||||
value = value << (uint64_t)width;
|
||||
value |= addme;
|
||||
|
@ -2543,7 +2597,7 @@ static constexpr uint64_t addValToKey(uint64_t value, int width, uint64_t addme)
|
|||
}
|
||||
|
||||
/* smaller value is better */
|
||||
static uint64_t getPeerCandidateScore(tr_torrent const* tor, peer_atom const& atom, uint8_t salt)
|
||||
[[nodiscard]] uint64_t getPeerCandidateScore(tr_torrent const* tor, peer_atom const& atom, uint8_t salt)
|
||||
{
|
||||
auto i = uint64_t{};
|
||||
auto score = uint64_t{};
|
||||
|
@ -2601,8 +2655,10 @@ static uint64_t getPeerCandidateScore(tr_torrent const* tor, peer_atom const& at
|
|||
return score;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/** @return an array of all the atoms we might want to connect to */
|
||||
static std::vector<peer_candidate> getPeerCandidates(tr_session* session, size_t max)
|
||||
[[nodiscard]] std::vector<peer_candidate> getPeerCandidates(tr_session* session, size_t max)
|
||||
{
|
||||
auto const now = tr_time();
|
||||
auto const now_msec = tr_time_msec();
|
||||
|
@ -2680,7 +2736,7 @@ static std::vector<peer_candidate> getPeerCandidates(tr_session* session, size_t
|
|||
return candidates;
|
||||
}
|
||||
|
||||
static void initiateConnection(tr_peerMgr* mgr, tr_swarm* s, peer_atom& atom)
|
||||
void initiateConnection(tr_peerMgr* mgr, tr_swarm* s, peer_atom& atom)
|
||||
{
|
||||
time_t const now = tr_time();
|
||||
bool utp = tr_sessionIsUTPEnabled(mgr->session) && !atom.utp_failed;
|
||||
|
@ -2726,8 +2782,12 @@ static void initiateConnection(tr_peerMgr* mgr, tr_swarm* s, peer_atom& atom)
|
|||
atom.time = now;
|
||||
}
|
||||
|
||||
} // namespace connect_helpers
|
||||
|
||||
void tr_peerMgr::makeNewPeerConnections(size_t max)
|
||||
{
|
||||
using namespace connect_helpers;
|
||||
|
||||
for (auto& candidate : getPeerCandidates(session, max))
|
||||
{
|
||||
initiateConnection(this, candidate.tor->swarm, *candidate.atom);
|
||||
|
|
Loading…
Add table
Reference in a new issue