fix: crash in peer stats (#5279)
This commit is contained in:
parent
6156d90917
commit
d445c7f061
|
@ -274,8 +274,6 @@ struct tr_swarm_stats
|
|||
|
||||
tr_swarm_stats tr_swarmGetStats(tr_swarm const* swarm);
|
||||
|
||||
void tr_swarmIncrementActivePeers(tr_swarm* swarm, tr_direction direction, bool is_active);
|
||||
|
||||
// ---
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -369,7 +369,7 @@ public:
|
|||
[&now](auto const& webseed) { return webseed->isTransferringPieces(now, TR_DOWN, nullptr); });
|
||||
}
|
||||
|
||||
[[nodiscard]] auto peerCount() const noexcept
|
||||
[[nodiscard]] TR_CONSTEXPR20 auto peerCount() const noexcept
|
||||
{
|
||||
return std::size(peers);
|
||||
}
|
||||
|
@ -977,7 +977,7 @@ namespace
|
|||
{
|
||||
namespace handshake_helpers
|
||||
{
|
||||
void create_bit_torrent_peer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io, struct peer_atom* atom, tr_quark client)
|
||||
void create_bit_torrent_peer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io, struct peer_atom* atom, tr_interned_string client)
|
||||
{
|
||||
TR_ASSERT(atom != nullptr);
|
||||
TR_ASSERT(tr_isTorrent(tor));
|
||||
|
@ -985,8 +985,7 @@ void create_bit_torrent_peer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io, str
|
|||
|
||||
tr_swarm* swarm = tor->swarm;
|
||||
|
||||
auto* peer = tr_peerMsgsNew(tor, atom, std::move(io), &tr_swarm::peerCallbackFunc, swarm);
|
||||
peer->client = client;
|
||||
auto* peer = tr_peerMsgsNew(tor, atom, std::move(io), client, &tr_swarm::peerCallbackFunc, swarm);
|
||||
atom->is_connected = true;
|
||||
|
||||
swarm->peers.push_back(peer);
|
||||
|
@ -996,11 +995,6 @@ void create_bit_torrent_peer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io, str
|
|||
|
||||
TR_ASSERT(swarm->stats.peer_count == swarm->peerCount());
|
||||
TR_ASSERT(swarm->stats.peer_from_count[atom->fromFirst] <= swarm->stats.peer_count);
|
||||
|
||||
// TODO is this needed?
|
||||
// isn't it already initialized in tr_peerMsgsImpl's ctor?
|
||||
peer->update_active(TR_UP);
|
||||
peer->update_active(TR_DOWN);
|
||||
}
|
||||
|
||||
/* FIXME: this is kind of a mess. */
|
||||
|
@ -1084,12 +1078,12 @@ void create_bit_torrent_peer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io, str
|
|||
}
|
||||
else
|
||||
{
|
||||
auto client = tr_quark{ TR_KEY_NONE };
|
||||
auto client = tr_interned_string{};
|
||||
if (result.peer_id)
|
||||
{
|
||||
auto buf = std::array<char, 128>{};
|
||||
tr_clientForId(std::data(buf), sizeof(buf), *result.peer_id);
|
||||
client = tr_quark_new(std::data(buf));
|
||||
client = tr_interned_string{ tr_quark_new(std::data(buf)) };
|
||||
}
|
||||
|
||||
result.io->set_bandwidth(&s->tor->bandwidth_);
|
||||
|
@ -1324,10 +1318,11 @@ std::vector<tr_pex> tr_peerMgrGetPeers(tr_torrent const* tor, uint8_t address_ty
|
|||
auto atoms = std::vector<peer_atom const*>{};
|
||||
if (list_mode == TR_PEERS_CONNECTED) /* connected peers only */
|
||||
{
|
||||
atoms.reserve(s->peerCount());
|
||||
auto const& peers = s->peers;
|
||||
atoms.reserve(std::size(peers));
|
||||
std::transform(
|
||||
std::begin(s->peers),
|
||||
std::end(s->peers),
|
||||
std::begin(peers),
|
||||
std::end(peers),
|
||||
std::back_inserter(atoms),
|
||||
[](auto const* peer) { return peer->atom; });
|
||||
}
|
||||
|
@ -1421,13 +1416,6 @@ void tr_peerMgrOnTorrentGotMetainfo(tr_torrent* tor)
|
|||
swarm->mark_atom_as_seed(*peer->atom);
|
||||
}
|
||||
}
|
||||
|
||||
/* update the bittorrent peers' willingness... */
|
||||
for (auto* peer : swarm->peers)
|
||||
{
|
||||
peer->update_active(TR_UP);
|
||||
peer->update_active(TR_DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
int8_t tr_peerMgrPieceAvailability(tr_torrent const* tor, tr_piece_index_t piece)
|
||||
|
@ -1462,33 +1450,25 @@ void tr_peerMgrTorrentAvailability(tr_torrent const* tor, int8_t* tab, unsigned
|
|||
}
|
||||
}
|
||||
|
||||
tr_swarm_stats tr_swarmGetStats(tr_swarm const* swarm)
|
||||
tr_swarm_stats tr_swarmGetStats(tr_swarm const* const swarm)
|
||||
{
|
||||
TR_ASSERT(swarm != nullptr);
|
||||
|
||||
auto count_active_peers = [&swarm](tr_direction dir)
|
||||
{
|
||||
return std::count_if(
|
||||
std::begin(swarm->peers),
|
||||
std::end(swarm->peers),
|
||||
[dir](auto const& peer) { return peer->is_active(dir); });
|
||||
};
|
||||
|
||||
auto& stats = swarm->stats;
|
||||
stats.active_peer_count[TR_UP] = count_active_peers(TR_UP);
|
||||
stats.active_peer_count[TR_DOWN] = count_active_peers(TR_DOWN);
|
||||
stats.active_webseed_count = swarm->countActiveWebseeds(tr_time_msec());
|
||||
return stats;
|
||||
}
|
||||
|
||||
void tr_swarmIncrementActivePeers(tr_swarm* swarm, tr_direction direction, bool is_active)
|
||||
{
|
||||
int n = swarm->stats.active_peer_count[direction];
|
||||
|
||||
if (is_active)
|
||||
{
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
--n;
|
||||
}
|
||||
|
||||
TR_ASSERT(n >= 0);
|
||||
TR_ASSERT(n <= swarm->stats.peer_count);
|
||||
|
||||
swarm->stats.active_peer_count[direction] = n;
|
||||
}
|
||||
|
||||
/* count how many bytes we want that connected peers have */
|
||||
uint64_t tr_peerMgrGetDesiredAvailable(tr_torrent const* tor)
|
||||
{
|
||||
|
@ -1502,7 +1482,7 @@ uint64_t tr_peerMgrGetDesiredAvailable(tr_torrent const* tor)
|
|||
}
|
||||
|
||||
tr_swarm const* const swarm = tor->swarm;
|
||||
if (swarm == nullptr || swarm->peerCount() == 0U)
|
||||
if (swarm == nullptr || std::empty(swarm->peers))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1547,7 +1527,7 @@ namespace
|
|||
namespace peer_stat_helpers
|
||||
{
|
||||
|
||||
[[nodiscard]] auto getPeerStats(tr_peerMsgs const* peer, time_t now, uint64_t now_msec)
|
||||
[[nodiscard]] auto get_peer_stats(tr_peerMsgs const* peer, time_t now, uint64_t now_msec)
|
||||
{
|
||||
auto stats = tr_peer_stat{};
|
||||
auto const* const atom = peer->atom;
|
||||
|
@ -1555,7 +1535,7 @@ namespace peer_stat_helpers
|
|||
auto const [addr, port] = peer->socketAddress();
|
||||
|
||||
addr.display_name(stats.addr, sizeof(stats.addr));
|
||||
stats.client = peer->client.c_str();
|
||||
stats.client = peer->user_agent().c_str();
|
||||
stats.port = port.host();
|
||||
stats.from = atom->fromFirst;
|
||||
stats.progress = peer->percentDone();
|
||||
|
@ -1563,10 +1543,10 @@ namespace peer_stat_helpers
|
|||
stats.isEncrypted = peer->is_encrypted();
|
||||
stats.rateToPeer_KBps = tr_toSpeedKBps(peer->get_piece_speed_bytes_per_second(now_msec, TR_CLIENT_TO_PEER));
|
||||
stats.rateToClient_KBps = tr_toSpeedKBps(peer->get_piece_speed_bytes_per_second(now_msec, TR_PEER_TO_CLIENT));
|
||||
stats.peerIsChoked = peer->is_peer_choked();
|
||||
stats.peerIsInterested = peer->is_peer_interested();
|
||||
stats.clientIsChoked = peer->is_client_choked();
|
||||
stats.clientIsInterested = peer->is_client_interested();
|
||||
stats.peerIsChoked = peer->peer_is_choked();
|
||||
stats.peerIsInterested = peer->peer_is_interested();
|
||||
stats.clientIsChoked = peer->client_is_choked();
|
||||
stats.clientIsInterested = peer->client_is_interested();
|
||||
stats.isIncoming = peer->is_incoming_connection();
|
||||
stats.isDownloadingFrom = peer->is_active(TR_PEER_TO_CLIENT);
|
||||
stats.isUploadingTo = peer->is_active(TR_CLIENT_TO_PEER);
|
||||
|
@ -1654,16 +1634,17 @@ tr_peer_stat* tr_peerMgrPeerStats(tr_torrent const* tor, size_t* setme_count)
|
|||
TR_ASSERT(tr_isTorrent(tor));
|
||||
TR_ASSERT(tor->swarm->manager != nullptr);
|
||||
|
||||
auto const n = tor->swarm->peerCount();
|
||||
auto const peers = tor->swarm->peers;
|
||||
auto const n = std::size(peers);
|
||||
auto* const ret = new tr_peer_stat[n];
|
||||
|
||||
auto const now = tr_time();
|
||||
auto const now_msec = tr_time_msec();
|
||||
std::transform(
|
||||
std::begin(tor->swarm->peers),
|
||||
std::end(tor->swarm->peers),
|
||||
std::begin(peers),
|
||||
std::end(peers),
|
||||
ret,
|
||||
[&now, &now_msec](auto const* peer) { return getPeerStats(peer, now, now_msec); });
|
||||
[&now, &now_msec](auto const* peer) { return get_peer_stats(peer, now, now_msec); });
|
||||
|
||||
*setme_count = n;
|
||||
return ret;
|
||||
|
@ -1718,7 +1699,7 @@ void updateInterest(tr_swarm* swarm)
|
|||
return;
|
||||
}
|
||||
|
||||
if (auto const peer_count = swarm->peerCount(); peer_count > 0)
|
||||
if (auto const& peers = swarm->peers; !std::empty(peers))
|
||||
{
|
||||
int const n = tor->pieceCount();
|
||||
|
||||
|
@ -1730,7 +1711,7 @@ void updateInterest(tr_swarm* swarm)
|
|||
piece_is_interesting[i] = tor->pieceIsWanted(i) && !tor->hasPiece(i);
|
||||
}
|
||||
|
||||
for (auto* const peer : swarm->peers)
|
||||
for (auto* const peer : peers)
|
||||
{
|
||||
peer->set_interested(isPeerInteresting(tor, piece_is_interesting, peer));
|
||||
}
|
||||
|
@ -1818,8 +1799,8 @@ void rechokeUploads(tr_swarm* s, uint64_t const now)
|
|||
{
|
||||
auto const lock = s->unique_lock();
|
||||
|
||||
auto const peer_count = s->peerCount();
|
||||
auto& peers = s->peers;
|
||||
auto const peer_count = std::size(peers);
|
||||
auto choked = std::vector<ChokeData>{};
|
||||
choked.reserve(peer_count);
|
||||
auto const* const session = s->manager->session;
|
||||
|
@ -1857,8 +1838,8 @@ void rechokeUploads(tr_swarm* s, uint64_t const now)
|
|||
peer,
|
||||
getRateBps(s->tor, peer, now),
|
||||
salter(),
|
||||
peer->is_peer_interested(),
|
||||
peer->is_peer_choked(),
|
||||
peer->peer_is_interested(),
|
||||
peer->peer_is_choked(),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
@ -2071,9 +2052,11 @@ struct ComparePeerByActivity
|
|||
|
||||
[[nodiscard]] auto getPeersToClose(tr_swarm const* const swarm, time_t const now_sec)
|
||||
{
|
||||
auto peers_to_close = std::vector<tr_peer*>{};
|
||||
auto const& peers = swarm->peers;
|
||||
auto const peer_count = std::size(peers);
|
||||
|
||||
auto const peer_count = swarm->peerCount();
|
||||
auto peers_to_close = std::vector<tr_peer*>{};
|
||||
peers_to_close.reserve(peer_count);
|
||||
for (auto* peer : swarm->peers)
|
||||
{
|
||||
if (shouldPeerBeClosed(swarm, peer, peer_count, now_sec))
|
||||
|
|
|
@ -261,7 +261,7 @@ void updateDesiredRequestCount(tr_peerMsgsImpl* msgs);
|
|||
__FILE__, \
|
||||
__LINE__, \
|
||||
(level), \
|
||||
fmt::format(FMT_STRING("{:s} [{:s}]: {:s}"), (msgs)->io->display_name(), (msgs)->client, text), \
|
||||
fmt::format(FMT_STRING("{:s} [{:s}]: {:s}"), (msgs)->io->display_name(), (msgs)->user_agent().sv(), text), \
|
||||
(msgs)->torrent->name()); \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -270,6 +270,8 @@ void updateDesiredRequestCount(tr_peerMsgsImpl* msgs);
|
|||
#define logtrace(msgs, text) myLogMacro(msgs, TR_LOG_TRACE, text)
|
||||
#define logwarn(msgs, text) myLogMacro(msgs, TR_LOG_WARN, text)
|
||||
|
||||
using ReadResult = std::pair<ReadState, size_t /*n_piece_data_bytes_read*/>;
|
||||
|
||||
/**
|
||||
* Low-level communication state information about a connected peer.
|
||||
*
|
||||
|
@ -291,9 +293,10 @@ public:
|
|||
tr_torrent* torrent_in,
|
||||
peer_atom* atom_in,
|
||||
std::shared_ptr<tr_peerIo> io_in,
|
||||
tr_interned_string client,
|
||||
tr_peer_callback callback,
|
||||
void* callback_data)
|
||||
: tr_peerMsgs{ torrent_in, atom_in }
|
||||
: tr_peerMsgs{ torrent_in, atom_in, client, io_in->is_encrypted(), io_in->is_incoming(), io_in->is_utp() }
|
||||
, outMessagesBatchPeriod{ LowPriorityIntervalSecs }
|
||||
, torrent{ torrent_in }
|
||||
, io{ std::move(io_in) }
|
||||
|
@ -331,6 +334,8 @@ public:
|
|||
|
||||
io->set_callbacks(canRead, didWrite, gotError, this);
|
||||
updateDesiredRequestCount(this);
|
||||
|
||||
update_active();
|
||||
}
|
||||
|
||||
tr_peerMsgsImpl(tr_peerMsgsImpl&&) = delete;
|
||||
|
@ -391,61 +396,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_peer_choked() const noexcept override
|
||||
{
|
||||
return peer_is_choked_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_peer_interested() const noexcept override
|
||||
{
|
||||
return peer_is_interested_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_client_choked() const noexcept override
|
||||
{
|
||||
return client_is_choked_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_client_interested() const noexcept override
|
||||
{
|
||||
return client_is_interested_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_utp_connection() const noexcept override
|
||||
{
|
||||
return io->is_utp();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_encrypted() const override
|
||||
{
|
||||
return io->is_encrypted();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_incoming_connection() const override
|
||||
{
|
||||
return io->is_incoming();
|
||||
}
|
||||
|
||||
[[nodiscard]] tr_bandwidth& bandwidth() noexcept override
|
||||
{
|
||||
return io->bandwidth();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_active(tr_direction direction) const override
|
||||
{
|
||||
TR_ASSERT(tr_isDirection(direction));
|
||||
auto const active = is_active_[direction];
|
||||
TR_ASSERT(active == calculate_active(direction));
|
||||
return active;
|
||||
}
|
||||
|
||||
void update_active(tr_direction direction) override
|
||||
{
|
||||
TR_ASSERT(tr_isDirection(direction));
|
||||
|
||||
set_active(direction, calculate_active(direction));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::pair<tr_address, tr_port> socketAddress() const override
|
||||
{
|
||||
return io->socket_address();
|
||||
|
@ -465,6 +420,8 @@ public:
|
|||
void onTorrentGotMetainfo() noexcept override
|
||||
{
|
||||
invalidatePercentDone();
|
||||
|
||||
update_active();
|
||||
}
|
||||
|
||||
void invalidatePercentDone()
|
||||
|
@ -486,16 +443,16 @@ public:
|
|||
{
|
||||
// TODO logtrace(msgs, "Not changing choke to %d to avoid fibrillation", peer_is_choked);
|
||||
}
|
||||
else if (peer_is_choked_ != peer_is_choked)
|
||||
else if (this->peer_is_choked() != peer_is_choked)
|
||||
{
|
||||
peer_is_choked_ = peer_is_choked;
|
||||
set_peer_choked(peer_is_choked);
|
||||
|
||||
if (peer_is_choked_)
|
||||
if (peer_is_choked)
|
||||
{
|
||||
cancelAllRequestsToClient(this);
|
||||
}
|
||||
|
||||
protocolSendChoke(this, peer_is_choked_);
|
||||
protocolSendChoke(this, peer_is_choked);
|
||||
chokeChangedAt = now;
|
||||
update_active(TR_CLIENT_TO_PEER);
|
||||
}
|
||||
|
@ -516,9 +473,9 @@ public:
|
|||
|
||||
void set_interested(bool interested) override
|
||||
{
|
||||
if (client_is_interested_ != interested)
|
||||
if (client_is_interested() != interested)
|
||||
{
|
||||
client_is_interested_ = interested;
|
||||
set_client_interested(interested);
|
||||
sendInterest(this, interested);
|
||||
update_active(TR_PEER_TO_CLIENT);
|
||||
}
|
||||
|
@ -539,8 +496,8 @@ public:
|
|||
void requestBlocks(tr_block_span_t const* block_spans, size_t n_spans) override
|
||||
{
|
||||
TR_ASSERT(torrent->clientCanDownload());
|
||||
TR_ASSERT(is_client_interested());
|
||||
TR_ASSERT(!is_client_choked());
|
||||
TR_ASSERT(client_is_interested());
|
||||
TR_ASSERT(!client_is_choked());
|
||||
|
||||
for (auto const *span = block_spans, *span_end = span + n_spans; span != span_end; ++span)
|
||||
{
|
||||
|
@ -587,7 +544,7 @@ public:
|
|||
private:
|
||||
[[nodiscard]] size_t maxAvailableReqs() const
|
||||
{
|
||||
if (torrent->isDone() || !torrent->hasMetainfo() || client_is_choked_ || !client_is_interested_)
|
||||
if (torrent->isDone() || !torrent->hasMetainfo() || client_is_choked() || !client_is_interested())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -644,7 +601,7 @@ private:
|
|||
{
|
||||
if (direction == TR_CLIENT_TO_PEER)
|
||||
{
|
||||
return is_peer_interested() && !is_peer_choked();
|
||||
return peer_is_interested() && !peer_is_choked();
|
||||
}
|
||||
|
||||
// TR_PEER_TO_CLIENT
|
||||
|
@ -654,36 +611,25 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
auto const active = is_client_interested() && !is_client_choked();
|
||||
auto const active = client_is_interested() && !client_is_choked();
|
||||
TR_ASSERT(!active || !torrent->isDone());
|
||||
return active;
|
||||
}
|
||||
|
||||
void set_active(tr_direction direction, bool active)
|
||||
void update_active()
|
||||
{
|
||||
// TODO logtrace(msgs, "direction [%d] is_active [%d]", int(direction), int(is_active));
|
||||
auto& val = is_active_[direction];
|
||||
if (val != active)
|
||||
{
|
||||
val = active;
|
||||
|
||||
tr_swarmIncrementActivePeers(torrent->swarm, direction, active);
|
||||
update_active(TR_UP);
|
||||
update_active(TR_DOWN);
|
||||
}
|
||||
|
||||
void update_active(tr_direction direction)
|
||||
{
|
||||
TR_ASSERT(tr_isDirection(direction));
|
||||
|
||||
set_active(direction, calculate_active(direction));
|
||||
}
|
||||
|
||||
public:
|
||||
/* Whether or not we've choked this peer. */
|
||||
bool peer_is_choked_ = true;
|
||||
|
||||
/* whether or not the peer has indicated it will download from us. */
|
||||
bool peer_is_interested_ = false;
|
||||
|
||||
/* whether or not the peer is choking us. */
|
||||
bool client_is_choked_ = true;
|
||||
|
||||
/* whether or not we've indicated to the peer that we would download from them if unchoked. */
|
||||
bool client_is_interested_ = false;
|
||||
|
||||
bool peerSupportsPex = false;
|
||||
bool peerSupportsMetadataXfer = false;
|
||||
bool clientSentLtepHandshake = false;
|
||||
|
@ -746,7 +692,8 @@ public:
|
|||
tr_bitfield have_;
|
||||
|
||||
private:
|
||||
std::array<bool, 2> is_active_ = { false, false };
|
||||
friend ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, libtransmission::Buffer& payload);
|
||||
friend void parseLtepHandshake(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload);
|
||||
|
||||
tr_peer_callback const callback_;
|
||||
void* const callback_data_;
|
||||
|
@ -1086,6 +1033,15 @@ void parseLtepHandshake(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload)
|
|||
pex.flags |= ADDED_F_SEED_FLAG;
|
||||
}
|
||||
|
||||
// http://bittorrent.org/beps/bep_0010.html
|
||||
// Client name and version (as a utf-8 string). This is a much more
|
||||
// reliable way of identifying the client than relying on the
|
||||
// peer id encoding.
|
||||
if (auto sv = std::string_view{}; tr_variantDictFindStrView(&val, TR_KEY_v, &sv))
|
||||
{
|
||||
msgs->set_user_agent(tr_interned_string{ sv });
|
||||
}
|
||||
|
||||
/* get peer's listening port */
|
||||
if (tr_variantDictFindInt(&val, TR_KEY_p, &i))
|
||||
{
|
||||
|
@ -1269,8 +1225,6 @@ void parseLtep(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload)
|
|||
}
|
||||
}
|
||||
|
||||
using ReadResult = std::pair<ReadState, size_t /*n_piece_data_bytes_read*/>;
|
||||
|
||||
ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, libtransmission::Buffer& payload);
|
||||
|
||||
void prefetchPieces(tr_peerMsgsImpl* msgs)
|
||||
|
@ -1294,7 +1248,7 @@ void prefetchPieces(tr_peerMsgsImpl* msgs)
|
|||
|
||||
[[nodiscard]] bool canAddRequestFromPeer(tr_peerMsgsImpl const* const msgs, struct peer_request const& req)
|
||||
{
|
||||
if (msgs->peer_is_choked_)
|
||||
if (msgs->peer_is_choked())
|
||||
{
|
||||
logtrace(msgs, "rejecting request from choked peer");
|
||||
return false;
|
||||
|
@ -1461,7 +1415,7 @@ ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, libtransmissi
|
|||
{
|
||||
case BtPeerMsgs::Choke:
|
||||
logtrace(msgs, "got Choke");
|
||||
msgs->client_is_choked_ = true;
|
||||
msgs->set_client_choked(true);
|
||||
|
||||
if (!fext)
|
||||
{
|
||||
|
@ -1473,20 +1427,20 @@ ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, libtransmissi
|
|||
|
||||
case BtPeerMsgs::Unchoke:
|
||||
logtrace(msgs, "got Unchoke");
|
||||
msgs->client_is_choked_ = false;
|
||||
msgs->set_client_choked(false);
|
||||
msgs->update_active(TR_PEER_TO_CLIENT);
|
||||
updateDesiredRequestCount(msgs);
|
||||
break;
|
||||
|
||||
case BtPeerMsgs::Interested:
|
||||
logtrace(msgs, "got Interested");
|
||||
msgs->peer_is_interested_ = true;
|
||||
msgs->set_peer_interested(true);
|
||||
msgs->update_active(TR_CLIENT_TO_PEER);
|
||||
break;
|
||||
|
||||
case BtPeerMsgs::NotInterested:
|
||||
logtrace(msgs, "got Not Interested");
|
||||
msgs->peer_is_interested_ = false;
|
||||
msgs->set_peer_interested(false);
|
||||
msgs->update_active(TR_CLIENT_TO_PEER);
|
||||
break;
|
||||
|
||||
|
@ -1888,8 +1842,8 @@ void updateBlockRequests(tr_peerMsgsImpl* msgs)
|
|||
return;
|
||||
}
|
||||
|
||||
TR_ASSERT(msgs->is_client_interested());
|
||||
TR_ASSERT(!msgs->is_client_choked());
|
||||
TR_ASSERT(msgs->client_is_interested());
|
||||
TR_ASSERT(!msgs->client_is_choked());
|
||||
|
||||
if (auto const requests = tr_peerMgrGetNextRequests(tor, msgs, n_wanted); !std::empty(requests))
|
||||
{
|
||||
|
@ -2272,8 +2226,9 @@ tr_peerMsgs* tr_peerMsgsNew(
|
|||
tr_torrent* torrent,
|
||||
peer_atom* atom,
|
||||
std::shared_ptr<tr_peerIo> io,
|
||||
tr_interned_string user_agent,
|
||||
tr_peer_callback callback,
|
||||
void* callback_data)
|
||||
{
|
||||
return new tr_peerMsgsImpl(torrent, atom, std::move(io), callback, callback_data);
|
||||
return new tr_peerMsgsImpl(torrent, atom, std::move(io), user_agent, callback, callback_data);
|
||||
}
|
||||
|
|
|
@ -10,19 +10,16 @@
|
|||
#endif
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint> // int8_t
|
||||
#include <cstddef> // size_t
|
||||
#include <ctime> // time_t
|
||||
#include <cstddef> // for size_t
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <utility> // for std::pair<>
|
||||
|
||||
#include "bitfield.h"
|
||||
#include "peer-common.h"
|
||||
#include "torrent.h"
|
||||
#include "peer-common.h" // for tr_peer
|
||||
|
||||
class tr_peer;
|
||||
class tr_peerIo;
|
||||
struct tr_address;
|
||||
struct tr_torrent;
|
||||
|
||||
/**
|
||||
* @addtogroup peers Peers
|
||||
|
@ -32,31 +29,73 @@ struct tr_address;
|
|||
class tr_peerMsgs : public tr_peer
|
||||
{
|
||||
public:
|
||||
tr_peerMsgs(tr_torrent const* tor, peer_atom* atom_in)
|
||||
tr_peerMsgs(
|
||||
tr_torrent const* tor,
|
||||
peer_atom* atom_in,
|
||||
tr_interned_string user_agent,
|
||||
bool connection_is_encrypted,
|
||||
bool connection_is_incoming,
|
||||
bool connection_is_utp)
|
||||
: tr_peer{ tor, atom_in }
|
||||
, have_{ tor->pieceCount() }
|
||||
, user_agent_{ user_agent }
|
||||
, connection_is_encrypted_{ connection_is_encrypted }
|
||||
, connection_is_incoming_{ connection_is_incoming }
|
||||
, connection_is_utp_{ connection_is_utp }
|
||||
{
|
||||
++n_peers;
|
||||
}
|
||||
|
||||
virtual ~tr_peerMsgs() override;
|
||||
|
||||
[[nodiscard]] static size_t size() noexcept
|
||||
[[nodiscard]] static auto size() noexcept
|
||||
{
|
||||
return n_peers.load();
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool is_peer_choked() const noexcept = 0;
|
||||
[[nodiscard]] virtual bool is_peer_interested() const noexcept = 0;
|
||||
[[nodiscard]] virtual bool is_client_choked() const noexcept = 0;
|
||||
[[nodiscard]] virtual bool is_client_interested() const noexcept = 0;
|
||||
[[nodiscard]] constexpr auto client_is_choked() const noexcept
|
||||
{
|
||||
return client_is_choked_;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool is_utp_connection() const noexcept = 0;
|
||||
[[nodiscard]] virtual bool is_encrypted() const = 0;
|
||||
[[nodiscard]] virtual bool is_incoming_connection() const = 0;
|
||||
[[nodiscard]] constexpr auto client_is_interested() const noexcept
|
||||
{
|
||||
return client_is_interested_;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool is_active(tr_direction direction) const = 0;
|
||||
virtual void update_active(tr_direction direction) = 0;
|
||||
[[nodiscard]] constexpr auto peer_is_choked() const noexcept
|
||||
{
|
||||
return peer_is_choked_;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto peer_is_interested() const noexcept
|
||||
{
|
||||
return peer_is_interested_;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto is_encrypted() const noexcept
|
||||
{
|
||||
return connection_is_encrypted_;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto is_incoming_connection() const noexcept
|
||||
{
|
||||
return connection_is_incoming_;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto is_utp_connection() const noexcept
|
||||
{
|
||||
return connection_is_utp_;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto const& user_agent() const noexcept
|
||||
{
|
||||
return user_agent_;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto is_active(tr_direction direction) const noexcept
|
||||
{
|
||||
return is_active_[direction];
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::pair<tr_address, tr_port> socketAddress() const = 0;
|
||||
|
||||
|
@ -71,20 +110,68 @@ public:
|
|||
|
||||
virtual void on_piece_completed(tr_piece_index_t) = 0;
|
||||
|
||||
/// The client name. This is the app name derived from the `v` string in LTEP's handshake dictionary
|
||||
tr_interned_string client;
|
||||
|
||||
protected:
|
||||
tr_bitfield have_;
|
||||
constexpr void set_client_choked(bool val) noexcept
|
||||
{
|
||||
client_is_choked_ = val;
|
||||
}
|
||||
|
||||
constexpr void set_client_interested(bool val) noexcept
|
||||
{
|
||||
client_is_interested_ = val;
|
||||
}
|
||||
|
||||
constexpr void set_peer_choked(bool val) noexcept
|
||||
{
|
||||
peer_is_choked_ = val;
|
||||
}
|
||||
|
||||
constexpr void set_peer_interested(bool val) noexcept
|
||||
{
|
||||
peer_is_interested_ = val;
|
||||
}
|
||||
|
||||
constexpr void set_active(tr_direction direction, bool active) noexcept
|
||||
{
|
||||
is_active_[direction] = active;
|
||||
}
|
||||
|
||||
constexpr void set_user_agent(tr_interned_string val) noexcept
|
||||
{
|
||||
user_agent_ = val;
|
||||
}
|
||||
|
||||
private:
|
||||
static inline auto n_peers = std::atomic<size_t>{};
|
||||
|
||||
// What software the peer is running.
|
||||
// Derived from the `v` string in LTEP's handshake dictionary, when available.
|
||||
tr_interned_string user_agent_;
|
||||
|
||||
bool const connection_is_encrypted_;
|
||||
bool const connection_is_incoming_;
|
||||
bool const connection_is_utp_;
|
||||
|
||||
std::array<bool, 2> is_active_ = {};
|
||||
|
||||
// whether or not the peer is choking us.
|
||||
bool client_is_choked_ = true;
|
||||
|
||||
// whether or not we've indicated to the peer that we would download from them if unchoked
|
||||
bool client_is_interested_ = false;
|
||||
|
||||
// whether or not we've choked this peer
|
||||
bool peer_is_choked_ = true;
|
||||
|
||||
// whether or not the peer has indicated it will download from us
|
||||
bool peer_is_interested_ = false;
|
||||
};
|
||||
|
||||
tr_peerMsgs* tr_peerMsgsNew(
|
||||
tr_torrent* torrent,
|
||||
peer_atom* atom,
|
||||
std::shared_ptr<tr_peerIo> io,
|
||||
tr_interned_string user_agent,
|
||||
tr_peer_callback callback,
|
||||
void* callback_data);
|
||||
|
||||
|
|
Loading…
Reference in New Issue