diff --git a/gtk/DetailsDialog.cc b/gtk/DetailsDialog.cc index 637db8530..59165a55f 100644 --- a/gtk/DetailsDialog.cc +++ b/gtk/DetailsDialog.cc @@ -1088,17 +1088,17 @@ public: Gtk::TreeModelColumn upload_rate_string; Gtk::TreeModelColumn client; Gtk::TreeModelColumn progress; - Gtk::TreeModelColumn upload_request_count_number; + Gtk::TreeModelColumn upload_request_count_number; Gtk::TreeModelColumn upload_request_count_string; - Gtk::TreeModelColumn download_request_count_number; + Gtk::TreeModelColumn download_request_count_number; Gtk::TreeModelColumn download_request_count_string; - Gtk::TreeModelColumn blocks_downloaded_count_number; + Gtk::TreeModelColumn blocks_downloaded_count_number; Gtk::TreeModelColumn blocks_downloaded_count_string; - Gtk::TreeModelColumn blocks_uploaded_count_number; + Gtk::TreeModelColumn blocks_uploaded_count_number; Gtk::TreeModelColumn blocks_uploaded_count_string; - Gtk::TreeModelColumn reqs_cancelled_by_client_count_number; + Gtk::TreeModelColumn reqs_cancelled_by_client_count_number; Gtk::TreeModelColumn reqs_cancelled_by_client_count_string; - Gtk::TreeModelColumn reqs_cancelled_by_peer_count_number; + Gtk::TreeModelColumn reqs_cancelled_by_peer_count_number; Gtk::TreeModelColumn reqs_cancelled_by_peer_count_string; Gtk::TreeModelColumn encryption_stock_id; Gtk::TreeModelColumn flags; @@ -1111,21 +1111,13 @@ void initPeerRow( Gtk::TreeModel::iterator const& iter, std::string_view const key, std::string_view const torrent_name, - tr_peer_stat const* peer) + tr_peer_stat const& peer) { - g_return_if_fail(peer != nullptr); - - char const* client = peer->client; - if (client == nullptr || g_strcmp0(client, "Unknown Client") == 0) - { - client = ""; - } - auto peer_addr4 = in_addr(); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) auto const* const peer_addr4_octets = reinterpret_cast(&peer_addr4.s_addr); - auto const collated_name = inet_pton(AF_INET, std::data(peer->addr), &peer_addr4) != 1 ? - std::data(peer->addr) : + auto const collated_name = inet_pton(AF_INET, peer.addr.c_str(), &peer_addr4) != 1 ? + peer.addr : fmt::format( "{:03}", fmt::join( @@ -1134,20 +1126,18 @@ void initPeerRow( peer_addr4_octets + sizeof(peer_addr4.s_addr), // TODO(C++20): Use std::span ".")); - (*iter)[peer_cols.address] = std::data(peer->addr); + (*iter)[peer_cols.address] = peer.addr; (*iter)[peer_cols.address_collated] = collated_name; - (*iter)[peer_cols.client] = client; - (*iter)[peer_cols.encryption_stock_id] = peer->isEncrypted ? "lock" : ""; + (*iter)[peer_cols.client] = peer.user_agent; + (*iter)[peer_cols.encryption_stock_id] = peer.is_encrypted ? "lock" : ""; (*iter)[peer_cols.key] = std::string(key); (*iter)[peer_cols.torrent_name] = std::string(torrent_name); } -void refreshPeerRow(Gtk::TreeModel::iterator const& iter, tr_peer_stat const* peer) +void refreshPeerRow(Gtk::TreeModel::iterator const& iter, tr_peer_stat const& peer) { - g_return_if_fail(peer != nullptr); - - auto const down_speed = Speed{ peer->rateToClient_KBps, Speed::Units::KByps }; - auto const up_speed = Speed{ peer->rateToPeer_KBps, Speed::Units::KByps }; + auto const down_speed = peer.rate_to_client; + auto const up_speed = peer.rate_to_peer; auto blocks_to_client = std::string{}; auto blocks_to_peer = std::string{}; @@ -1158,64 +1148,64 @@ void refreshPeerRow(Gtk::TreeModel::iterator const& iter, tr_peer_stat const* pe auto up_count = std::string{}; auto up_speed_string = std::string{}; - if (peer->rateToPeer_KBps > 0.01) + if (peer.rate_to_peer.base_quantity() > 0U) { up_speed_string = up_speed.to_string(); } - if (peer->rateToClient_KBps > 0) + if (peer.rate_to_client.base_quantity() > 0U) { down_speed_string = down_speed.to_string(); } - if (peer->activeReqsToPeer > 0) + if (peer.active_reqs_to_peer > 0) { - down_count = std::to_string(peer->activeReqsToPeer); + down_count = std::to_string(peer.active_reqs_to_peer); } - if (peer->activeReqsToClient > 0) + if (peer.active_reqs_to_client > 0) { - up_count = std::to_string(peer->activeReqsToClient); + up_count = std::to_string(peer.active_reqs_to_client); } - if (peer->blocksToPeer > 0) + if (peer.blocks_to_peer > 0) { - blocks_to_peer = std::to_string(peer->blocksToPeer); + blocks_to_peer = std::to_string(peer.blocks_to_peer); } - if (peer->blocksToClient > 0) + if (peer.blocks_to_client > 0) { - blocks_to_client = std::to_string(peer->blocksToClient); + blocks_to_client = std::to_string(peer.blocks_to_client); } - if (peer->cancelsToPeer > 0) + if (peer.cancels_to_peer > 0) { - cancelled_by_client = std::to_string(peer->cancelsToPeer); + cancelled_by_client = std::to_string(peer.cancels_to_peer); } - if (peer->cancelsToClient > 0) + if (peer.cancels_to_client > 0) { - cancelled_by_peer = std::to_string(peer->cancelsToClient); + cancelled_by_peer = std::to_string(peer.cancels_to_client); } - (*iter)[peer_cols.progress] = static_cast(100.0 * peer->progress); - (*iter)[peer_cols.upload_request_count_number] = peer->activeReqsToClient; + (*iter)[peer_cols.progress] = static_cast(100.0 * peer.progress); + (*iter)[peer_cols.upload_request_count_number] = peer.active_reqs_to_client; (*iter)[peer_cols.upload_request_count_string] = up_count; - (*iter)[peer_cols.download_request_count_number] = peer->activeReqsToPeer; + (*iter)[peer_cols.download_request_count_number] = peer.active_reqs_to_peer; (*iter)[peer_cols.download_request_count_string] = down_count; (*iter)[peer_cols.download_rate_speed] = down_speed; (*iter)[peer_cols.download_rate_string] = down_speed_string; (*iter)[peer_cols.upload_rate_speed] = up_speed; (*iter)[peer_cols.upload_rate_string] = up_speed_string; - (*iter)[peer_cols.flags] = std::data(peer->flagStr); + (*iter)[peer_cols.flags] = peer.flag_str; (*iter)[peer_cols.was_updated] = true; - (*iter)[peer_cols.blocks_downloaded_count_number] = peer->blocksToClient; + (*iter)[peer_cols.blocks_downloaded_count_number] = peer.blocks_to_client; (*iter)[peer_cols.blocks_downloaded_count_string] = blocks_to_client; - (*iter)[peer_cols.blocks_uploaded_count_number] = peer->blocksToPeer; + (*iter)[peer_cols.blocks_uploaded_count_number] = peer.blocks_to_peer; (*iter)[peer_cols.blocks_uploaded_count_string] = blocks_to_peer; - (*iter)[peer_cols.reqs_cancelled_by_client_count_number] = peer->cancelsToPeer; + (*iter)[peer_cols.reqs_cancelled_by_client_count_number] = peer.cancels_to_peer; (*iter)[peer_cols.reqs_cancelled_by_client_count_string] = cancelled_by_client; - (*iter)[peer_cols.reqs_cancelled_by_peer_count_number] = peer->cancelsToClient; + (*iter)[peer_cols.reqs_cancelled_by_peer_count_number] = peer.cancels_to_client; (*iter)[peer_cols.reqs_cancelled_by_peer_count_string] = cancelled_by_peer; } @@ -1227,16 +1217,12 @@ void DetailsDialog::Impl::refreshPeerList(std::vector const& torren auto const& store = peer_store_; /* step 1: get all the peers */ - std::vector peers; - std::vector peerCount; + std::vector> peers; peers.reserve(torrents.size()); - peerCount.reserve(torrents.size()); for (auto const* const torrent : torrents) { - size_t count = 0; - peers.push_back(tr_torrentPeers(torrent, &count)); - peerCount.push_back(count); + peers.push_back(tr_torrentPeers(torrent)); } /* step 2: mark all the peers in the list as not-updated */ @@ -1245,25 +1231,25 @@ void DetailsDialog::Impl::refreshPeerList(std::vector const& torren row[peer_cols.was_updated] = false; } - auto make_key = [](tr_torrent const* tor, tr_peer_stat const* ps) + auto make_key = [](tr_torrent const* tor, tr_peer_stat const& ps) { - return fmt::format("{:d}.{:s}", tr_torrentId(tor), ps->addr); + return fmt::format("{:d}.{:s}", tr_torrentId(tor), ps.addr); }; /* step 3: add any new peers */ for (size_t i = 0; i < torrents.size(); ++i) { auto const* tor = torrents.at(i); + auto const& torrent_peers = peers.at(i); - for (size_t j = 0; j < peerCount[i]; ++j) + for (auto const& peer : torrent_peers) { - auto const* s = &peers.at(i)[j]; - auto const key = make_key(tor, s); + auto const key = make_key(tor, peer); if (hash.find(key) == hash.end()) { auto const iter = store->append(); - initPeerRow(iter, key, tr_torrentName(tor), s); + initPeerRow(iter, key, tr_torrentName(tor), peer); hash.try_emplace(key, Gtk::TreeRowReference(store, store->get_path(iter))); } } @@ -1273,12 +1259,12 @@ void DetailsDialog::Impl::refreshPeerList(std::vector const& torren for (size_t i = 0; i < torrents.size(); ++i) { auto const* tor = torrents.at(i); + auto const& torrent_peers = peers.at(i); - for (size_t j = 0; j < peerCount[i]; ++j) + for (auto const& peer : torrent_peers) { - auto const* s = &peers.at(i)[j]; - auto const key = make_key(tor, s); - refreshPeerRow(store->get_iter(hash.at(key).get_path()), s); + auto const key = make_key(tor, peer); + refreshPeerRow(store->get_iter(hash.at(key).get_path()), peer); } } @@ -1299,12 +1285,6 @@ void DetailsDialog::Impl::refreshPeerList(std::vector const& torren } } } - - /* step 6: cleanup */ - for (size_t i = 0; i < peers.size(); ++i) - { - tr_torrentPeersFree(peers[i], peerCount[i]); - } } void DetailsDialog::Impl::refreshWebseedList(std::vector const& torrents) diff --git a/libtransmission/announcer-http.cc b/libtransmission/announcer-http.cc index 2eb76587c..7ca33fd4e 100644 --- a/libtransmission/announcer-http.cc +++ b/libtransmission/announcer-http.cc @@ -234,16 +234,14 @@ void announce_url_new(tr_urlbuf& url, tr_session const* session, tr_announce_req if (auto ipv4_addr = session->global_address(TR_AF_INET); ipv4_addr) { - auto buf = std::array{}; - auto const display_name = ipv4_addr->display_name(std::data(buf), std::size(buf)); + auto const display_name = ipv4_addr->display_name(); fmt::format_to(out, "&ipv4="); tr_urlPercentEncode(out, display_name); } if (auto ipv6_addr = session->global_address(TR_AF_INET6); ipv6_addr) { - auto buf = std::array{}; - auto const display_name = ipv6_addr->display_name(std::data(buf), std::size(buf)); + auto const display_name = ipv6_addr->display_name(); fmt::format_to(out, "&ipv6="); tr_urlPercentEncode(out, display_name); } diff --git a/libtransmission/net.cc b/libtransmission/net.cc index c8d1592a0..48e73aca7 100644 --- a/libtransmission/net.cc +++ b/libtransmission/net.cc @@ -472,20 +472,15 @@ std::optional tr_address::from_string(std::string_view address_sv) } } -std::string_view tr_address::display_name(char* out, size_t outlen) const -{ - TR_ASSERT(is_valid()); - if (auto* name = evutil_inet_ntop(tr_ip_protocol_to_af(type), &addr, out, outlen)) - { - return name; - } - return "Invalid address"sv; -} - [[nodiscard]] std::string tr_address::display_name() const { auto buf = std::array{}; - return std::string{ display_name(std::data(buf), std::size(buf)) }; + TR_ASSERT(is_valid()); + if (auto* name = evutil_inet_ntop(tr_ip_protocol_to_af(type), &addr, std::data(buf), std::size(buf))) + { + return std::string{ name }; + } + return std::string{ "Invalid address" }; } std::pair tr_address::from_compact_ipv4(std::byte const* compact) noexcept diff --git a/libtransmission/net.h b/libtransmission/net.h index d2f737029..76d6848d0 100644 --- a/libtransmission/net.h +++ b/libtransmission/net.h @@ -159,7 +159,6 @@ struct tr_address [[nodiscard]] static std::pair from_compact_ipv6(std::byte const* compact) noexcept; // --- write the text form of the address, e.g. inet_ntop() - std::string_view display_name(char* out, size_t outlen) const; [[nodiscard]] std::string display_name() const; // --- diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index f09c4ecb2..e2330be64 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -1831,121 +1831,118 @@ namespace peer_stat_helpers auto const [addr, port] = peer->socket_address(); - addr.display_name(stats.addr, sizeof(stats.addr)); - stats.client = peer->user_agent().c_str(); + stats.addr = addr.display_name(); + stats.user_agent = peer->user_agent(); stats.peer_id = peer->peer_id(); stats.port = port.host(); stats.from = peer->peer_info->from_first(); stats.progress = peer->percent_done(); - stats.isUTP = peer->is_utp_connection(); - stats.isEncrypted = peer->is_encrypted(); - stats.rateToPeer_KBps = peer->get_piece_speed(now_msec, tr_direction::ClientToPeer).count(Speed::Units::KByps); - stats.rateToClient_KBps = peer->get_piece_speed(now_msec, tr_direction::PeerToClient).count(Speed::Units::KByps); - 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_direction::PeerToClient); - stats.isUploadingTo = peer->is_active(tr_direction::ClientToPeer); - stats.isSeed = peer->is_seed(); + stats.is_utp = peer->is_utp_connection(); + stats.is_encrypted = peer->is_encrypted(); + stats.rate_to_peer = peer->get_piece_speed(now_msec, tr_direction::ClientToPeer); + stats.rate_to_client = peer->get_piece_speed(now_msec, tr_direction::PeerToClient); + stats.peer_is_choked = peer->peer_is_choked(); + stats.peer_is_interested = peer->peer_is_interested(); + stats.client_is_choked = peer->client_is_choked(); + stats.client_is_interested = peer->client_is_interested(); + stats.is_incoming = peer->is_incoming_connection(); + stats.is_downloading_from = peer->is_active(tr_direction::PeerToClient); + stats.is_uploading_to = peer->is_active(tr_direction::ClientToPeer); + stats.is_seed = peer->is_seed(); - stats.blocksToPeer = peer->blocks_sent_to_peer.count(now, CancelHistorySec); - stats.blocksToClient = peer->blocks_sent_to_client.count(now, CancelHistorySec); - stats.cancelsToPeer = peer->cancels_sent_to_peer.count(now, CancelHistorySec); - stats.cancelsToClient = peer->cancels_sent_to_client.count(now, CancelHistorySec); + stats.blocks_to_peer = peer->blocks_sent_to_peer.count(now, CancelHistorySec); + stats.blocks_to_client = peer->blocks_sent_to_client.count(now, CancelHistorySec); + stats.cancels_to_peer = peer->cancels_sent_to_peer.count(now, CancelHistorySec); + stats.cancels_to_client = peer->cancels_sent_to_client.count(now, CancelHistorySec); stats.bytes_to_peer = peer->bytes_sent_to_peer.count(now, CancelHistorySec); stats.bytes_to_client = peer->bytes_sent_to_client.count(now, CancelHistorySec); - stats.activeReqsToPeer = peer->active_req_count(tr_direction::ClientToPeer); - stats.activeReqsToClient = peer->active_req_count(tr_direction::PeerToClient); + stats.active_reqs_to_peer = peer->active_req_count(tr_direction::ClientToPeer); + stats.active_reqs_to_client = peer->active_req_count(tr_direction::PeerToClient); - char* pch = stats.flagStr; + stats.flag_str.clear(); + stats.flag_str.reserve(9); - if (stats.isUTP) + if (stats.is_utp) { - *pch++ = 'T'; + stats.flag_str.push_back('T'); } if (peer->swarm->optimistic == peer) { - *pch++ = 'O'; + stats.flag_str.push_back('O'); } - if (stats.isDownloadingFrom) + if (stats.is_downloading_from) { - *pch++ = 'D'; + stats.flag_str.push_back('D'); } - else if (stats.clientIsInterested) + else if (stats.client_is_interested) { - *pch++ = 'd'; + stats.flag_str.push_back('d'); } - if (stats.isUploadingTo) + if (stats.is_uploading_to) { - *pch++ = 'U'; + stats.flag_str.push_back('U'); } - else if (stats.peerIsInterested) + else if (stats.peer_is_interested) { - *pch++ = 'u'; + stats.flag_str.push_back('u'); } - if (!stats.clientIsChoked && !stats.clientIsInterested) + if (!stats.client_is_choked && !stats.client_is_interested) { - *pch++ = 'K'; + stats.flag_str.push_back('K'); } - if (!stats.peerIsChoked && !stats.peerIsInterested) + if (!stats.peer_is_choked && !stats.peer_is_interested) { - *pch++ = '?'; + stats.flag_str.push_back('?'); } - if (stats.isEncrypted) + if (stats.is_encrypted) { - *pch++ = 'E'; + stats.flag_str.push_back('E'); } if (stats.from == TR_PEER_FROM_DHT) { - *pch++ = 'H'; + stats.flag_str.push_back('H'); } else if (stats.from == TR_PEER_FROM_PEX) { - *pch++ = 'X'; + stats.flag_str.push_back('X'); } - if (stats.isIncoming) + if (stats.is_incoming) { - *pch++ = 'I'; + stats.flag_str.push_back('I'); } - *pch = '\0'; - return stats; } } // namespace peer_stat_helpers } // namespace -tr_peer_stat* tr_peerMgrPeerStats(tr_torrent const* tor, size_t* setme_count) +std::vector tr_peerMgrPeerStats(tr_torrent const* tor) { TR_ASSERT(tr_isTorrent(tor)); TR_ASSERT(tor->swarm->manager != nullptr); auto const peers = tor->swarm->peers; - auto const n = std::size(peers); - auto* const ret = new tr_peer_stat[n]; + auto ret = std::vector(std::size(peers)); auto const lock = tor->unique_lock(); auto const now = tr_time(); auto const now_msec = tr_time_msec(); std::ranges::transform( peers, - ret, + std::data(ret), [&now, &now_msec](auto const& peer) { return peer_stat_helpers::get_peer_stats(peer.get(), now, now_msec); }); - *setme_count = n; return ret; } diff --git a/libtransmission/peer-mgr.h b/libtransmission/peer-mgr.h index 9bf19f5b0..7803b46d7 100644 --- a/libtransmission/peer-mgr.h +++ b/libtransmission/peer-mgr.h @@ -716,7 +716,7 @@ void tr_peerMgrTorrentAvailability(tr_torrent const* tor, int8_t* tab, unsigned [[nodiscard]] uint64_t tr_peerMgrGetDesiredAvailable(tr_torrent const* tor); -[[nodiscard]] struct tr_peer_stat* tr_peerMgrPeerStats(tr_torrent const* tor, size_t* setme_count); +[[nodiscard]] std::vector tr_peerMgrPeerStats(tr_torrent const* tor); [[nodiscard]] tr_webseed_view tr_peerMgrWebseed(tr_torrent const* tor, size_t i); diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index 2b852ad9f..83e2e9d08 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -613,36 +613,33 @@ namespace make_torrent_field_helpers [[nodiscard]] auto make_peer_vec(tr_torrent const& tor) { - auto n_peers = size_t{}; - auto* const peers = tr_torrentPeers(&tor, &n_peers); + auto const peers = tr_torrentPeers(&tor); auto peers_vec = tr_variant::Vector{}; - peers_vec.reserve(n_peers); - for (size_t idx = 0U; idx != n_peers; ++idx) + peers_vec.reserve(std::size(peers)); + for (auto const& peer : peers) { - auto const& peer = peers[idx]; auto peer_map = tr_variant::Map{ 19U }; peer_map.try_emplace(TR_KEY_address, peer.addr); - peer_map.try_emplace(TR_KEY_client_is_choked, peer.clientIsChoked); - peer_map.try_emplace(TR_KEY_client_is_interested, peer.clientIsInterested); - peer_map.try_emplace(TR_KEY_client_name, peer.client); + peer_map.try_emplace(TR_KEY_client_is_choked, peer.client_is_choked); + peer_map.try_emplace(TR_KEY_client_is_interested, peer.client_is_interested); + peer_map.try_emplace(TR_KEY_client_name, peer.user_agent); peer_map.try_emplace(TR_KEY_peer_id, tr_base64_encode(std::string_view{ peer.peer_id.data(), peer.peer_id.size() })); - peer_map.try_emplace(TR_KEY_flag_str, peer.flagStr); - peer_map.try_emplace(TR_KEY_is_downloading_from, peer.isDownloadingFrom); - peer_map.try_emplace(TR_KEY_is_encrypted, peer.isEncrypted); - peer_map.try_emplace(TR_KEY_is_incoming, peer.isIncoming); - peer_map.try_emplace(TR_KEY_is_utp, peer.isUTP); - peer_map.try_emplace(TR_KEY_is_uploading_to, peer.isUploadingTo); - peer_map.try_emplace(TR_KEY_peer_is_choked, peer.peerIsChoked); - peer_map.try_emplace(TR_KEY_peer_is_interested, peer.peerIsInterested); + peer_map.try_emplace(TR_KEY_flag_str, peer.flag_str); + peer_map.try_emplace(TR_KEY_is_downloading_from, peer.is_downloading_from); + peer_map.try_emplace(TR_KEY_is_encrypted, peer.is_encrypted); + peer_map.try_emplace(TR_KEY_is_incoming, peer.is_incoming); + peer_map.try_emplace(TR_KEY_is_utp, peer.is_utp); + peer_map.try_emplace(TR_KEY_is_uploading_to, peer.is_uploading_to); + peer_map.try_emplace(TR_KEY_peer_is_choked, peer.peer_is_choked); + peer_map.try_emplace(TR_KEY_peer_is_interested, peer.peer_is_interested); peer_map.try_emplace(TR_KEY_port, peer.port); peer_map.try_emplace(TR_KEY_progress, peer.progress); - peer_map.try_emplace(TR_KEY_rate_to_client, Speed{ peer.rateToClient_KBps, Speed::Units::KByps }.base_quantity()); - peer_map.try_emplace(TR_KEY_rate_to_peer, Speed{ peer.rateToPeer_KBps, Speed::Units::KByps }.base_quantity()); + peer_map.try_emplace(TR_KEY_rate_to_client, peer.rate_to_client.base_quantity()); + peer_map.try_emplace(TR_KEY_rate_to_peer, peer.rate_to_peer.base_quantity()); peer_map.try_emplace(TR_KEY_bytes_to_peer, peer.bytes_to_peer); peer_map.try_emplace(TR_KEY_bytes_to_client, peer.bytes_to_client); peers_vec.emplace_back(std::move(peer_map)); } - tr_torrentPeersFree(peers, n_peers); return tr_variant{ std::move(peers_vec) }; } diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index aff89f46e..ef337df23 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -1491,16 +1491,11 @@ std::string tr_torrentFilename(tr_torrent const* tor) // --- -tr_peer_stat* tr_torrentPeers(tr_torrent const* tor, size_t* peer_count) +std::vector tr_torrentPeers(tr_torrent const* tor) { TR_ASSERT(tr_isTorrent(tor)); - return tr_peerMgrPeerStats(tor, peer_count); -} - -void tr_torrentPeersFree(tr_peer_stat* peer_stats, size_t /*peer_count*/) -{ - delete[] peer_stats; + return tr_peerMgrPeerStats(tor); } void tr_torrentAvailability(tr_torrent const* tor, int8_t* tab, int size) diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 5400b9641..f045dc4b6 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -20,6 +20,7 @@ #include #include "libtransmission/tr-macros.h" +#include "libtransmission/values.h" using tr_file_index_t = size_t; using tr_piece_index_t = uint32_t; @@ -1139,60 +1140,58 @@ bool tr_torrentCanManualUpdate(tr_torrent const* torrent); // --- tr_peer_stat -// NOLINTBEGIN(modernize-avoid-c-arrays) struct tr_peer_stat { - bool isUTP; + std::string addr; + std::string flag_str; - bool isEncrypted; - bool isDownloadingFrom; - bool isUploadingTo; - bool isSeed; + // The user agent, e.g. `BitTorrent 7.9.1`. + // Will be an empty string if the agent cannot be determined. + std::string user_agent; - bool peerIsChoked; - bool peerIsInterested; - bool clientIsChoked; - bool clientIsInterested; - bool isIncoming; + libtransmission::Values::Speed rate_to_peer; + libtransmission::Values::Speed rate_to_client; - uint8_t from; - uint16_t port; + // how many requests the peer has made that we haven't responded to yet + size_t active_reqs_to_client = {}; - char addr[TrInet6AddrStrlen]; - char flagStr[32]; - char const* client; + // how many requests we've made and are currently awaiting a response for + size_t active_reqs_to_peer = {}; - tr_peer_id_t peer_id; + size_t bytes_to_peer = {}; + size_t bytes_to_client = {}; - float progress; - double rateToPeer_KBps; - double rateToClient_KBps; + tr_peer_id_t peer_id = {}; + + float progress = {}; // THESE NEXT FOUR FIELDS ARE EXPERIMENTAL. // Don't rely on them; they'll probably go away - /* how many blocks we've sent to this peer in the last 120 seconds */ - uint32_t blocksToPeer; - /* how many blocks this client's sent to us in the last 120 seconds */ - uint32_t blocksToClient; - /* how many requests to this peer that we've cancelled in the last 120 seconds */ - uint32_t cancelsToPeer; - /* how many requests this peer made of us, then cancelled, in the last 120 seconds */ - uint32_t cancelsToClient; + // how many blocks we've sent to this peer in the last 120 seconds + uint32_t blocks_to_peer = {}; + // how many blocks this client's sent to us in the last 120 seconds + uint32_t blocks_to_client = {}; + // how many requests to this peer that we've cancelled in the last 120 seconds + uint32_t cancels_to_peer = {}; + // how many requests this peer made of us, then cancelled, in the last 120 seconds + uint32_t cancels_to_client = {}; - /* how many requests the peer has made that we haven't responded to yet */ - size_t activeReqsToClient; + uint16_t port = {}; + uint8_t from = {}; - /* how many requests we've made and are currently awaiting a response for */ - size_t activeReqsToPeer; - - size_t bytes_to_peer; - size_t bytes_to_client; + bool client_is_choked = {}; + bool client_is_interested = {}; + bool is_downloading_from = {}; + bool is_encrypted = {}; + bool is_incoming = {}; + bool is_seed = {}; + bool is_uploading_to = {}; + bool is_utp = {}; + bool peer_is_choked = {}; + bool peer_is_interested = {}; }; -// NOLINTEND(modernize-avoid-c-arrays) -tr_peer_stat* tr_torrentPeers(tr_torrent const* torrent, size_t* peer_count); - -void tr_torrentPeersFree(tr_peer_stat* peer_stats, size_t peer_count); +std::vector tr_torrentPeers(tr_torrent const* torrent); // --- tr_tracker_stat diff --git a/macosx/Torrent.mm b/macosx/Torrent.mm index 9f2948cca..9ef9873bb 100644 --- a/macosx/Torrent.mm +++ b/macosx/Torrent.mm @@ -1006,41 +1006,38 @@ bool trashDataFile(std::string_view const filename, tr_error* error) - (NSArray*)peers { - size_t totalPeers; - tr_peer_stat* peers = tr_torrentPeers(self.fHandle, &totalPeers); + auto const peers = tr_torrentPeers(self.fHandle); + size_t const totalPeers = peers.size(); NSMutableArray* peerDicts = [NSMutableArray arrayWithCapacity:totalPeers]; - for (size_t i = 0; i < totalPeers; i++) + for (auto const& peer : peers) { - tr_peer_stat* peer = &peers[i]; NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:12]; dict[@"Name"] = self.name; - dict[@"From"] = @(peer->from); - dict[@"IP"] = @(peer->addr); - dict[@"Port"] = @(peer->port); - dict[@"Progress"] = @(peer->progress); - dict[@"Seed"] = @(peer->isSeed); - dict[@"Encryption"] = @(peer->isEncrypted); - dict[@"uTP"] = @(peer->isUTP); - dict[@"Client"] = @(peer->client); - dict[@"Flags"] = @(peer->flagStr); + dict[@"From"] = @(peer.from); + dict[@"IP"] = tr_strv_to_utf8_nsstring(peer.addr); + dict[@"Port"] = @(peer.port); + dict[@"Progress"] = @(peer.progress); + dict[@"Seed"] = @(peer.is_seed); + dict[@"Encryption"] = @(peer.is_encrypted); + dict[@"uTP"] = @(peer.is_utp); + dict[@"Client"] = tr_strv_to_utf8_nsstring(peer.user_agent); + dict[@"Flags"] = tr_strv_to_utf8_nsstring(peer.flag_str); - if (peer->isUploadingTo) + if (peer.is_uploading_to) { - dict[@"UL To Rate"] = @(peer->rateToPeer_KBps); + dict[@"UL To Rate"] = @(peer.rate_to_peer.count(libtransmission::Values::Speed::Units::KByps)); } - if (peer->isDownloadingFrom) + if (peer.is_downloading_from) { - dict[@"DL From Rate"] = @(peer->rateToClient_KBps); + dict[@"DL From Rate"] = @(peer.rate_to_client.count(libtransmission::Values::Speed::Units::KByps)); } [peerDicts addObject:dict]; } - tr_torrentPeersFree(peers, totalPeers); - return peerDicts; }