diff --git a/libtransmission/announcer-common.h b/libtransmission/announcer-common.h index 43f0c5bab..5b7ac32a9 100644 --- a/libtransmission/announcer-common.h +++ b/libtransmission/announcer-common.h @@ -12,6 +12,7 @@ #include #include // size_t #include +#include #include "transmission.h" @@ -45,7 +46,7 @@ struct tr_scrape_request std::array info_hash; /* how many hashes to use in the info_hash field */ - int info_hash_count; + int info_hash_count = 0; }; struct tr_scrape_response_row @@ -54,33 +55,33 @@ struct tr_scrape_response_row tr_sha1_digest_t info_hash; /* how many peers are seeding this torrent */ - int seeders; + int seeders = 0; /* how many peers are downloading this torrent */ - int leechers; + int leechers = 0; /* how many times this torrent has been downloaded */ - int downloads; + int downloads = 0; /* the number of active downloaders in the swarm. * this is a BEP 21 extension that some trackers won't support. * http://www.bittorrent.org/beps/bep_0021.html#tracker-scrapes */ - int downloaders; + int downloaders = 0; }; struct tr_scrape_response { /* whether or not we managed to connect to the tracker */ - bool did_connect; + bool did_connect = false; /* whether or not the scrape timed out */ - bool did_timeout; + bool did_timeout = false; /* how many info hashes are in the 'rows' field */ int row_count; /* the individual torrents' scrape results */ - struct tr_scrape_response_row rows[TR_MULTISCRAPE_MAX]; + std::array rows; /* the raw scrape url */ tr_interned_string scrape_url; @@ -126,36 +127,36 @@ char const* tr_announce_event_get_string(tr_announce_event); struct tr_announce_request { - tr_announce_event event; - bool partial_seed; + tr_announce_event event = {}; + bool partial_seed = false; /* the port we listen for incoming peers on */ - int port; + int port = 0; /* per-session key */ - int key; + int key = 0; /* the number of peers we'd like to get back in the response */ - int numwant; + int numwant = 0; /* the number of bytes we uploaded since the last 'started' event */ - uint64_t up; + uint64_t up = 0; /* the number of good bytes we downloaded since the last 'started' event */ - uint64_t down; + uint64_t down = 0; /* the number of bad bytes we downloaded since the last 'started' event */ - uint64_t corrupt; + uint64_t corrupt = 0; /* the total size of the torrent minus the number of bytes completed */ - uint64_t leftUntilComplete; + uint64_t leftUntilComplete = 0; /* the tracker's announce URL */ tr_interned_string announce_url; /* key generated by and returned from an http tracker. * see tr_announce_response.tracker_id_str */ - char* tracker_id_str; + std::string tracker_id; /* the torrent's peer id. * this changes when a torrent is stopped -> restarted. */ @@ -173,42 +174,36 @@ struct tr_pex; struct tr_announce_response { /* the torrent's info hash */ - tr_sha1_digest_t info_hash; + tr_sha1_digest_t info_hash = {}; /* whether or not we managed to connect to the tracker */ - bool did_connect; + bool did_connect = false; /* whether or not the scrape timed out */ - bool did_timeout; + bool did_timeout = false; /* preferred interval between announces. * transmission treats this as the interval for periodic announces */ - int interval; + int interval = 0; /* minimum interval between announces. (optional) * transmission treats this as the min interval for manual announces */ - int min_interval; + int min_interval = 0; /* how many peers are seeding this torrent */ - int seeders; + int seeders = -1; /* how many peers are downloading this torrent */ - int leechers; + int leechers = -1; /* how many times this torrent has been downloaded */ - int downloads; - - /* number of items in the 'pex' field */ - size_t pex_count; + int downloads = -1; /* IPv4 peers that we acquired from the tracker */ - struct tr_pex* pex; - - /* number of items in the 'pex6' field */ - size_t pex6_count; + std::vector pex; /* IPv6 peers that we acquired from the tracker */ - struct tr_pex* pex6; + std::vector pex6; /* human-readable error string on failure, or nullptr */ std::string errmsg; @@ -218,7 +213,7 @@ struct tr_announce_response /* key generated by and returned from an http tracker. * if this is provided, subsequent http announces must include this. */ - char* tracker_id_str; + std::string tracker_id; }; using tr_announce_response_func = void (*)(tr_announce_response const* response, void* userdata); diff --git a/libtransmission/announcer-http.cc b/libtransmission/announcer-http.cc index 47a08eeef..66186d66b 100644 --- a/libtransmission/announcer-http.cc +++ b/libtransmission/announcer-http.cc @@ -46,8 +46,8 @@ static std::string announce_url_new(tr_session const* session, tr_announce_reque { auto const announce_sv = req->announce_url.sv(); - char escaped_info_hash[SHA_DIGEST_LENGTH * 3 + 1]; - tr_http_escape_sha1(escaped_info_hash, req->info_hash); + auto escaped_info_hash = std::array{}; + tr_http_escape_sha1(std::data(escaped_info_hash), req->info_hash); auto* const buf = evbuffer_new(); evbuffer_expand(buf, 1024); @@ -67,7 +67,7 @@ static std::string announce_url_new(tr_session const* session, tr_announce_reque "&supportcrypto=1", TR_PRIsv_ARG(announce_sv), announce_sv.find('?') == announce_sv.npos ? '?' : '&', - escaped_info_hash, + std::data(escaped_info_hash), TR_PRIsv_ARG(req->peer_id), req->port, req->up, @@ -92,10 +92,9 @@ static std::string announce_url_new(tr_session const* session, tr_announce_reque evbuffer_add_printf(buf, "&event=%s", str); } - str = req->tracker_id_str; - if (!tr_str_is_empty(str)) + if (!std::empty(req->tracker_id)) { - evbuffer_add_printf(buf, "&trackerid=%s", str); + evbuffer_add_printf(buf, "&trackerid=%" TR_PRIsv, TR_PRIsv_ARG(req->tracker_id)); } /* There are two incompatible techniques for announcing an IPv6 address. @@ -119,11 +118,11 @@ static std::string announce_url_new(tr_session const* session, tr_announce_reque return evbuffer_free_to_str(buf); } -static tr_pex* listToPex(tr_variant* peerList, size_t* setme_len) +static auto listToPex(tr_variant* peerList) { size_t n = 0; size_t const len = tr_variantListSize(peerList); - auto* const pex = tr_new0(tr_pex, len); + auto pex = std::vector(len); for (size_t i = 0; i < len; ++i) { @@ -167,7 +166,7 @@ static tr_pex* listToPex(tr_variant* peerList, size_t* setme_len) ++n; } - *setme_len = n; + pex.resize(n); return pex; } @@ -188,10 +187,7 @@ static void on_announce_done_eventthread(void* vdata) data->response_func(&data->response, data->response_func_user_data); } - tr_free(data->response.pex6); - tr_free(data->response.pex); - tr_free(data->response.tracker_id_str); - tr_free(data); + delete data; } static void on_announce_done( @@ -264,7 +260,7 @@ static void on_announce_done( if (tr_variantDictFindStrView(&benc, TR_KEY_tracker_id, &sv)) { - response->tracker_id_str = tr_strvDup(sv); + response->tracker_id = sv; } if (tr_variantDictFindInt(&benc, TR_KEY_complete, &i)) @@ -285,18 +281,18 @@ static void on_announce_done( if (tr_variantDictFindStrView(&benc, TR_KEY_peers6, &sv)) { dbgmsg(data->log_name, "got a peers6 length of %zu", std::size(sv)); - response->pex6 = tr_peerMgrCompact6ToPex(std::data(sv), std::size(sv), nullptr, 0, &response->pex6_count); + response->pex6 = tr_peerMgrCompact6ToPex(std::data(sv), std::size(sv), nullptr, 0); } if (tr_variantDictFindStrView(&benc, TR_KEY_peers, &sv)) { dbgmsg(data->log_name, "got a compact peers length of %zu", std::size(sv)); - response->pex = tr_peerMgrCompactToPex(std::data(sv), std::size(sv), nullptr, 0, &response->pex_count); + response->pex = tr_peerMgrCompactToPex(std::data(sv), std::size(sv), nullptr, 0); } else if (tr_variantDictFindList(&benc, TR_KEY_peers, &tmp)) { - response->pex = listToPex(tmp, &response->pex_count); - dbgmsg(data->log_name, "got a peers list with %zu entries", response->pex_count); + response->pex = listToPex(tmp); + dbgmsg(data->log_name, "got a peers list with %zu entries", std::size(response->pex)); } } @@ -315,7 +311,7 @@ void tr_tracker_http_announce( tr_announce_response_func response_func, void* response_func_user_data) { - auto* const d = tr_new0(announce_data, 1); + auto* const d = new announce_data{}; d->response.seeders = -1; d->response.leechers = -1; d->response.downloads = -1; diff --git a/libtransmission/announcer-udp.cc b/libtransmission/announcer-udp.cc index e5a5fd419..b8e847ba7 100644 --- a/libtransmission/announcer-udp.cc +++ b/libtransmission/announcer-udp.cc @@ -6,6 +6,8 @@ #include /* errno, EAFNOSUPPORT */ #include /* memset() */ #include +#include +#include #include #include @@ -22,7 +24,6 @@ #include "log.h" #include "peer-io.h" #include "peer-mgr.h" /* tr_peerMgrCompactToPex() */ -#include "ptrarray.h" #include "session.h" #include "tr-assert.h" #include "tr-udp.h" @@ -154,6 +155,54 @@ static auto constexpr TauRequestTtl = int{ 60 }; struct tau_scrape_request { + void requestFinished() + { + if (callback != nullptr) + { + callback(&response, user_data); + } + } + + void fail(bool did_connect, bool did_timeout, std::string_view errmsg) + { + response.did_connect = did_connect; + response.did_timeout = did_timeout; + response.errmsg = errmsg; + requestFinished(); + } + + void onResponse(tau_action_t action, evbuffer* buf) + { + response.did_connect = true; + response.did_timeout = false; + + if (action == TAU_ACTION_SCRAPE) + { + for (int i = 0; i < response.row_count; ++i) + { + if (evbuffer_get_length(buf) < sizeof(uint32_t) * 3) + { + break; + } + + auto& row = response.rows[i]; + row.seeders = evbuffer_read_ntoh_32(buf); + row.downloads = evbuffer_read_ntoh_32(buf); + row.leechers = evbuffer_read_ntoh_32(buf); + } + + requestFinished(); + } + else + { + size_t const buflen = evbuffer_get_length(buf); + auto const errmsg = action == TAU_ACTION_ERROR && buflen > 0 ? + std::string_view{ reinterpret_cast(evbuffer_pullup(buf, -1)), buflen } : + _("Unknown error"); + fail(true, false, errmsg); + } + } + std::vector payload; time_t sent_at; @@ -165,7 +214,7 @@ struct tau_scrape_request void* user_data; }; -static struct tau_scrape_request* tau_scrape_request_new( +static tau_scrape_request make_tau_scrape_request( tr_scrape_request const* in, tr_scrape_response_func callback, void* user_data) @@ -185,22 +234,22 @@ static struct tau_scrape_request* tau_scrape_request_new( /* build the tau_scrape_request */ - auto* req = new tau_scrape_request{}; - req->callback = callback; - req->created_at = tr_time(); - req->transaction_id = transaction_id; - req->callback = callback; - req->user_data = user_data; - req->response.scrape_url = in->scrape_url; - req->response.row_count = in->info_hash_count; - req->payload.assign(payload_begin, payload_end); + auto req = tau_scrape_request{}; + req.callback = callback; + req.created_at = tr_time(); + req.transaction_id = transaction_id; + req.callback = callback; + req.user_data = user_data; + req.response.scrape_url = in->scrape_url; + req.response.row_count = in->info_hash_count; + req.payload.assign(payload_begin, payload_end); - for (int i = 0; i < req->response.row_count; ++i) + for (int i = 0; i < req.response.row_count; ++i) { - req->response.rows[i].seeders = -1; - req->response.rows[i].leechers = -1; - req->response.rows[i].downloads = -1; - req->response.rows[i].info_hash = in->info_hash[i]; + req.response.rows[i].seeders = -1; + req.response.rows[i].leechers = -1; + req.response.rows[i].downloads = -1; + req.response.rows[i].info_hash = in->info_hash[i]; } /* cleanup */ @@ -208,63 +257,6 @@ static struct tau_scrape_request* tau_scrape_request_new( return req; } -static void tau_scrape_request_free(struct tau_scrape_request* req) -{ - delete req; -} - -static void tau_scrape_request_finished(struct tau_scrape_request const* request) -{ - if (request->callback != nullptr) - { - request->callback(&request->response, request->user_data); - } -} - -static void tau_scrape_request_fail( - struct tau_scrape_request* request, - bool did_connect, - bool did_timeout, - std::string_view errmsg) -{ - request->response.did_connect = did_connect; - request->response.did_timeout = did_timeout; - request->response.errmsg = errmsg; - tau_scrape_request_finished(request); -} - -static void on_scrape_response(struct tau_scrape_request* request, tau_action_t action, struct evbuffer* buf) -{ - request->response.did_connect = true; - request->response.did_timeout = false; - - if (action == TAU_ACTION_SCRAPE) - { - for (int i = 0; i < request->response.row_count; ++i) - { - if (evbuffer_get_length(buf) < sizeof(uint32_t) * 3) - { - break; - } - - struct tr_scrape_response_row& row = request->response.rows[i]; - row.seeders = evbuffer_read_ntoh_32(buf); - row.downloads = evbuffer_read_ntoh_32(buf); - row.leechers = evbuffer_read_ntoh_32(buf); - } - - tau_scrape_request_finished(request); - } - else - { - size_t const buflen = evbuffer_get_length(buf); - auto const errmsg = action == TAU_ACTION_ERROR && buflen > 0 ? - std::string_view{ reinterpret_cast(evbuffer_pullup(buf, -1)), buflen } : - _("Unknown error"); - tau_scrape_request_fail(request, true, false, errmsg); - } -} - /**** ***** ***** ANNOUNCE @@ -273,15 +265,56 @@ static void on_scrape_response(struct tau_scrape_request* request, tau_action_t struct tau_announce_request { + void requestFinished() + { + if (this->callback != nullptr) + { + this->callback(&this->response, this->user_data); + } + } + + void fail(bool did_connect, bool did_timeout, std::string_view errmsg) + { + this->response.did_connect = did_connect; + this->response.did_timeout = did_timeout; + this->response.errmsg = errmsg; + this->requestFinished(); + } + + void onResponse(tau_action_t action, struct evbuffer* buf) + { + size_t const buflen = evbuffer_get_length(buf); + + this->response.did_connect = true; + this->response.did_timeout = false; + + if (action == TAU_ACTION_ANNOUNCE && buflen >= 3 * sizeof(uint32_t)) + { + response.interval = evbuffer_read_ntoh_32(buf); + response.leechers = evbuffer_read_ntoh_32(buf); + response.seeders = evbuffer_read_ntoh_32(buf); + response.pex = tr_peerMgrCompactToPex(evbuffer_pullup(buf, -1), evbuffer_get_length(buf), nullptr, 0); + requestFinished(); + } + else + { + auto const errmsg = action == TAU_ACTION_ERROR && buflen > 0 ? + std::string_view{ reinterpret_cast(evbuffer_pullup(buf, -1)), buflen } : + _("Unknown error"); + fail(true, false, errmsg); + } + } + std::vector payload; - time_t created_at; - time_t sent_at; - tau_transaction_t transaction_id; + time_t created_at = 0; + time_t sent_at = 0; + tau_transaction_t transaction_id = 0; - tr_announce_response response; - tr_announce_response_func callback; - void* user_data; + tr_announce_response response = {}; + + tr_announce_response_func callback = nullptr; + void* user_data = nullptr; }; enum tau_announce_event @@ -311,7 +344,7 @@ static tau_announce_event get_tau_announce_event(tr_announce_event e) } } -static struct tau_announce_request* tau_announce_request_new( +static tau_announce_request make_tau_announce_request( tr_announce_request const* in, tr_announce_response_func callback, void* user_data) @@ -336,79 +369,21 @@ static struct tau_announce_request* tau_announce_request_new( auto const* const payload_end = payload_begin + evbuffer_get_length(buf); /* build the tau_announce_request */ - auto* req = new tau_announce_request{}; - req->created_at = tr_time(); - req->transaction_id = transaction_id; - req->callback = callback; - req->user_data = user_data; - req->payload.assign(payload_begin, payload_end); - req->response.seeders = -1; - req->response.leechers = -1; - req->response.downloads = -1; - req->response.info_hash = in->info_hash; + auto req = tau_announce_request(); + req.created_at = tr_time(); + req.transaction_id = transaction_id; + req.callback = callback; + req.user_data = user_data; + req.payload.assign(payload_begin, payload_end); + req.response.seeders = -1; + req.response.leechers = -1; + req.response.downloads = -1; + req.response.info_hash = in->info_hash; evbuffer_free(buf); return req; } -static void tau_announce_request_free(struct tau_announce_request* req) -{ - tr_free(req->response.tracker_id_str); - tr_free(req->response.pex6); - tr_free(req->response.pex); - delete req; -} - -static void tau_announce_request_finished(struct tau_announce_request const* request) -{ - if (request->callback != nullptr) - { - request->callback(&request->response, request->user_data); - } -} - -static void tau_announce_request_fail( - struct tau_announce_request* request, - bool did_connect, - bool did_timeout, - std::string_view errmsg) -{ - request->response.did_connect = did_connect; - request->response.did_timeout = did_timeout; - request->response.errmsg = errmsg; - tau_announce_request_finished(request); -} - -static void on_announce_response(struct tau_announce_request* request, tau_action_t action, struct evbuffer* buf) -{ - size_t const buflen = evbuffer_get_length(buf); - - request->response.did_connect = true; - request->response.did_timeout = false; - - if (action == TAU_ACTION_ANNOUNCE && buflen >= 3 * sizeof(uint32_t)) - { - tr_announce_response* resp = &request->response; - resp->interval = evbuffer_read_ntoh_32(buf); - resp->leechers = evbuffer_read_ntoh_32(buf); - resp->seeders = evbuffer_read_ntoh_32(buf); - resp->pex = tr_peerMgrCompactToPex( - evbuffer_pullup(buf, -1), - evbuffer_get_length(buf), - nullptr, - 0, - &request->response.pex_count); - tau_announce_request_finished(request); - } - else - { - auto const errmsg = action == TAU_ACTION_ERROR && buflen > 0 ? - std::string_view{ reinterpret_cast(evbuffer_pullup(buf, -1)), buflen } : - _("Unknown error"); - tau_announce_request_fail(request, true, false, errmsg); - } -} - /**** ***** ***** TRACKERS @@ -417,14 +392,43 @@ static void on_announce_response(struct tau_announce_request* request, tau_actio struct tau_tracker { + [[nodiscard]] auto isIdle() const + { + return std::empty(announces) && std::empty(scrapes) && dns_request == nullptr; + } + + ~tau_tracker() + { + if (this->addr != nullptr) + { + evutil_freeaddrinfo(this->addr); + } + } + + void failAll(bool did_connect, bool did_timeout, std::string_view errmsg) + { + for (auto& req : this->scrapes) + { + req.fail(did_connect, did_timeout, errmsg); + } + + for (auto& req : this->announces) + { + req.fail(did_connect, did_timeout, errmsg); + } + + this->scrapes.clear(); + this->announces.clear(); + } + tr_session* const session; tr_interned_string const key; tr_interned_string const host; int const port; - struct evdns_getaddrinfo_request* dns_request = nullptr; - struct evutil_addrinfo* addr = nullptr; + evdns_getaddrinfo_request* dns_request = nullptr; + evutil_addrinfo* addr = nullptr; time_t addr_expiration_time = 0; time_t connecting_at = 0; @@ -434,8 +438,8 @@ struct tau_tracker time_t close_at = 0; - tr_ptrArray announces = {}; - tr_ptrArray scrapes = {}; + std::list announces; + std::list scrapes; tau_tracker(tr_session* session_in, tr_interned_string key_in, tr_interned_string host_in, int port_in) : session{ session_in } @@ -448,47 +452,6 @@ struct tau_tracker static void tau_tracker_upkeep(struct tau_tracker*); -static void tau_tracker_free(struct tau_tracker* t) -{ - TR_ASSERT(t->dns_request == nullptr); - - if (t->addr != nullptr) - { - evutil_freeaddrinfo(t->addr); - } - - tr_ptrArrayDestruct(&t->announces, (PtrArrayForeachFunc)tau_announce_request_free); - tr_ptrArrayDestruct(&t->scrapes, (PtrArrayForeachFunc)tau_scrape_request_free); - delete t; -} - -static void tau_tracker_fail_all(struct tau_tracker* tracker, bool did_connect, bool did_timeout, std::string_view errmsg) -{ - /* fail all the scrapes */ - tr_ptrArray* reqs = &tracker->scrapes; - - for (int i = 0, n = tr_ptrArraySize(reqs); i < n; ++i) - { - auto* req = static_cast(tr_ptrArrayNth(reqs, i)); - tau_scrape_request_fail(req, did_connect, did_timeout, errmsg); - } - - tr_ptrArrayDestruct(reqs, (PtrArrayForeachFunc)tau_scrape_request_free); - *reqs = {}; - - /* fail all the announces */ - reqs = &tracker->announces; - - for (int i = 0, n = tr_ptrArraySize(reqs); i < n; ++i) - { - auto* req = static_cast(tr_ptrArrayNth(reqs, i)); - tau_announce_request_fail(req, did_connect, did_timeout, errmsg); - } - - tr_ptrArrayDestruct(reqs, (PtrArrayForeachFunc)tau_announce_request_free); - *reqs = {}; -} - static void tau_tracker_on_dns(int errcode, struct evutil_addrinfo* addr, void* vtracker) { auto* tracker = static_cast(vtracker); @@ -499,7 +462,7 @@ static void tau_tracker_on_dns(int errcode, struct evutil_addrinfo* addr, void* { auto const errmsg = tr_strvJoin("DNS Lookup failed: "sv, evutil_gai_strerror(errcode)); dbgmsg(tracker->key, "%s", errmsg.c_str()); - tau_tracker_fail_all(tracker, false, false, errmsg.c_str()); + tracker->failAll(false, false, errmsg.c_str()); } else { @@ -520,59 +483,45 @@ static void tau_tracker_send_request(struct tau_tracker* tracker, void const* pa evbuffer_free(buf); } -static void tau_tracker_send_reqs(struct tau_tracker* tracker) +template +static void tau_tracker_send_requests(tau_tracker* tracker, std::list& reqs) +{ + auto const now = tr_time(); + + for (auto it = std::begin(reqs); it != std::end(reqs);) + { + auto& req = *it; + + if (req.sent_at != 0) // it's already been sent; we're awaiting a response + { + ++it; + continue; + } + + dbgmsg(tracker->key, "sending req %p", (void*)&req); + req.sent_at = now; + tau_tracker_send_request(tracker, std::data(req.payload), std::size(req.payload)); + + if (req.callback != nullptr) + { + ++it; + continue; + } + + // no response needed, so we can remove it now + it = reqs.erase(it); + } +} + +static void tau_tracker_send_reqs(tau_tracker* tracker) { TR_ASSERT(tracker->dns_request == nullptr); TR_ASSERT(tracker->connecting_at == 0); TR_ASSERT(tracker->addr != nullptr); + TR_ASSERT(tracker->connection_expiration_time > tr_time()); - time_t const now = tr_time(); - - TR_ASSERT(tracker->connection_expiration_time > now); - - tr_ptrArray* reqs = &tracker->announces; - - for (int i = 0, n = tr_ptrArraySize(reqs); i < n; ++i) - { - auto* req = static_cast(tr_ptrArrayNth(reqs, i)); - - if (req->sent_at == 0) - { - dbgmsg(tracker->key, "sending announce req %p", (void*)req); - req->sent_at = now; - tau_tracker_send_request(tracker, std::data(req->payload), std::size(req->payload)); - - if (req->callback == nullptr) - { - tau_announce_request_free(req); - tr_ptrArrayRemove(reqs, i); - --i; - --n; - } - } - } - - reqs = &tracker->scrapes; - - for (int i = 0, n = tr_ptrArraySize(reqs); i < n; ++i) - { - auto* req = static_cast(tr_ptrArrayNth(reqs, i)); - - if (req->sent_at == 0) - { - dbgmsg(tracker->key, "sending scrape req %p", (void*)req); - req->sent_at = now; - tau_tracker_send_request(tracker, std::data(req->payload), std::size(req->payload)); - - if (req->callback == nullptr) - { - tau_scrape_request_free(req); - tr_ptrArrayRemove(reqs, i); - --i; - --n; - } - } - } + tau_tracker_send_requests(tracker, tracker->announces); + tau_tracker_send_requests(tracker, tracker->scrapes); } static void on_tracker_connection_response(struct tau_tracker* tracker, tau_action_t action, struct evbuffer* buf) @@ -597,7 +546,7 @@ static void on_tracker_connection_response(struct tau_tracker* tracker, tau_acti std::string_view{ _("Connection failed") }; dbgmsg(tracker->key, "%" TR_PRIsv, TR_PRIsv_ARG(errmsg)); - tau_tracker_fail_all(tracker, true, false, errmsg); + tracker->failAll(true, false, errmsg); } tau_tracker_upkeep(tracker); @@ -613,46 +562,43 @@ static void tau_tracker_timeout_reqs(struct tau_tracker* tracker) on_tracker_connection_response(tracker, TAU_ACTION_ERROR, nullptr); } - tr_ptrArray* reqs = &tracker->announces; - - for (int i = 0, n = tr_ptrArraySize(reqs); i < n; ++i) + if (auto& reqs = tracker->announces; !std::empty(reqs)) { - auto* req = static_cast(tr_ptrArrayNth(reqs, i)); - - if (cancel_all || req->created_at + TauRequestTtl < now) + for (auto it = std::begin(reqs); it != std::end(reqs);) { - dbgmsg(tracker->key, "timeout announce req %p", (void*)req); - tau_announce_request_fail(req, false, true, ""); - tau_announce_request_free(req); - tr_ptrArrayRemove(reqs, i); - --i; - --n; + auto& req = *it; + if (cancel_all || req.created_at + TauRequestTtl < now) + { + dbgmsg(tracker->key, "timeout announce req %p", (void*)&req); + req.fail(false, true, ""); + it = reqs.erase(it); + } + else + { + ++it; + } } } - reqs = &tracker->scrapes; - - for (int i = 0, n = tr_ptrArraySize(reqs); i < n; ++i) + if (auto& reqs = tracker->scrapes; !std::empty(reqs)) { - auto* const req = static_cast(tr_ptrArrayNth(reqs, i)); - - if (cancel_all || req->created_at + TauRequestTtl < now) + for (auto it = std::begin(reqs); it != std::end(reqs);) { - dbgmsg(tracker->key, "timeout scrape req %p", (void*)req); - tau_scrape_request_fail(req, false, true, ""); - tau_scrape_request_free(req); - tr_ptrArrayRemove(reqs, i); - --i; - --n; + auto& req = *it; + if (cancel_all || req.created_at + TauRequestTtl < now) + { + dbgmsg(tracker->key, "timeout scrape req %p", &req); + req.fail(false, true, ""); + it = reqs.erase(it); + } + else + { + ++it; + } } } } -static bool tau_tracker_is_idle(struct tau_tracker const* tracker) -{ - return tr_ptrArrayEmpty(&tracker->announces) && tr_ptrArrayEmpty(&tracker->scrapes) && tracker->dns_request == nullptr; -} - static void tau_tracker_upkeep_ex(struct tau_tracker* tracker, bool timeout_reqs) { time_t const now = tr_time(); @@ -667,7 +613,7 @@ static void tau_tracker_upkeep_ex(struct tau_tracker* tracker, bool timeout_reqs } /* are there any requests pending? */ - if (tau_tracker_is_idle(tracker)) + if (tracker->isIdle()) { return; } @@ -739,10 +685,14 @@ static void tau_tracker_upkeep(struct tau_tracker* tracker) struct tr_announcer_udp { - /* tau_tracker */ - tr_ptrArray trackers; + explicit tr_announcer_udp(tr_session* session_in) + : session{ session_in } + { + } - tr_session* session; + std::list trackers; + + tr_session* const session; }; static struct tr_announcer_udp* announcer_udp_get(tr_session* session) @@ -752,9 +702,7 @@ static struct tr_announcer_udp* announcer_udp_get(tr_session* session) return session->announcer_udp; } - auto* const tau = tr_new0(tr_announcer_udp, 1); - tau->trackers = {}; - tau->session = session; + auto* const tau = new tr_announcer_udp(session); session->announcer_udp = tau; return tau; } @@ -773,20 +721,18 @@ static tau_tracker* tau_session_get_tracker(tr_announcer_udp* tau, tr_interned_s } // see if we already have it - // TODO: replace tr_ptrArray auto const key = tr_announcerGetKey(*parsed); - for (int i = 0, n = tr_ptrArraySize(&tau->trackers); i < n; ++i) + for (auto& tracker : tau->trackers) { - auto* tmp = static_cast(tr_ptrArrayNth(&tau->trackers, i)); - if (tmp->key == key) + if (tracker.key == key) { - return tmp; + return &tracker; } } // we don't have it -- build a new one - auto* const tracker = new tau_tracker{ tau->session, key, tr_interned_string(parsed->host), parsed->port }; - tr_ptrArrayAppend(&tau->trackers, tracker); + tau->trackers.emplace_back(tau->session, key, tr_interned_string(parsed->host), parsed->port); + auto* const tracker = &tau->trackers.back(); dbgmsg(tracker->key, "New tau_tracker created"); return tracker; } @@ -799,43 +745,30 @@ static tau_tracker* tau_session_get_tracker(tr_announcer_udp* tau, tr_interned_s void tr_tracker_udp_upkeep(tr_session* session) { - struct tr_announcer_udp* tau = session->announcer_udp; - - if (tau != nullptr) + if (auto* const tau = session->announcer_udp; tau != nullptr) { - tr_ptrArrayForeach(&tau->trackers, (PtrArrayForeachFunc)tau_tracker_upkeep); + for (auto& tracker : tau->trackers) + { + tau_tracker_upkeep(&tracker); + } } } bool tr_tracker_udp_is_idle(tr_session const* session) { - struct tr_announcer_udp* tau = session->announcer_udp; + auto const* tau = session->announcer_udp; - if (tau != nullptr) - { - for (int i = 0, n = tr_ptrArraySize(&tau->trackers); i < n; ++i) - { - auto const* tracker = static_cast(tr_ptrArrayNth(&tau->trackers, i)); - if (!tau_tracker_is_idle(tracker)) - { - return false; - } - } - } - - return true; + return tau == nullptr || + std::all_of(std::begin(tau->trackers), std::end(tau->trackers), [](auto const& tracker) { return tracker.isIdle(); }); } /* drop dead now. */ void tr_tracker_udp_close(tr_session* session) { - struct tr_announcer_udp* tau = session->announcer_udp; - - if (tau != nullptr) + if (auto* const tau = session->announcer_udp; tau != nullptr) { session->announcer_udp = nullptr; - tr_ptrArrayDestruct(&tau->trackers, (PtrArrayForeachFunc)tau_tracker_free); - tr_free(tau); + delete tau; } } @@ -845,21 +778,18 @@ void tr_tracker_udp_close(tr_session* session) void tr_tracker_udp_start_shutdown(tr_session* session) { time_t const now = time(nullptr); - struct tr_announcer_udp* tau = session->announcer_udp; - if (tau != nullptr) + if (auto* const tau = session->announcer_udp; tau != nullptr) { - for (int i = 0, n = tr_ptrArraySize(&tau->trackers); i < n; ++i) + for (auto& tracker : tau->trackers) { - auto* tracker = static_cast(tr_ptrArrayNth(&tau->trackers, i)); - - if (tracker->dns_request != nullptr) + if (tracker.dns_request != nullptr) { - evdns_getaddrinfo_cancel(tracker->dns_request); + evdns_getaddrinfo_cancel(tracker.dns_request); } - tracker->close_at = now + 3; - tau_tracker_upkeep(tracker); + tracker.close_at = now + 3; + tau_tracker_upkeep(&tracker); } } } @@ -879,7 +809,7 @@ bool tau_handle_message(tr_session* session, uint8_t const* msg, size_t msglen) } /* extract the action_id and see if it makes sense */ - struct evbuffer* const buf = evbuffer_new(); + auto* const buf = evbuffer_new(); evbuffer_add_reference(buf, msg, msglen, nullptr, nullptr); auto const action_id = tau_action_t(evbuffer_read_ntoh_32(buf)); @@ -893,50 +823,48 @@ bool tau_handle_message(tr_session* session, uint8_t const* msg, size_t msglen) struct tr_announcer_udp* const tau = session->announcer_udp; tau_transaction_t const transaction_id = evbuffer_read_ntoh_32(buf); - for (int i = 0, n = tr_ptrArraySize(&tau->trackers); i < n; ++i) + for (auto& tracker : tau->trackers) { - auto* tracker = static_cast(tr_ptrArrayNth(&tau->trackers, i)); - - /* is it a connection response? */ - if (tracker->connecting_at != 0 && transaction_id == tracker->connection_transaction_id) + // is it a connection response? + if (tracker.connecting_at != 0 && transaction_id == tracker.connection_transaction_id) { - dbgmsg(tracker->key, "%" PRIu32 " is my connection request!", transaction_id); - on_tracker_connection_response(tracker, action_id, buf); + dbgmsg(tracker.key, "%" PRIu32 " is my connection request!", transaction_id); + on_tracker_connection_response(&tracker, action_id, buf); evbuffer_free(buf); return true; } - /* is it a response to one of this tracker's announces? */ - tr_ptrArray* reqs = &tracker->announces; - - for (int j = 0, jn = tr_ptrArraySize(reqs); j < jn; ++j) + // is it a response to one of this tracker's announces? + if (auto& reqs = tracker.announces; !std::empty(reqs)) { - auto* req = static_cast(tr_ptrArrayNth(reqs, j)); - - if (req->sent_at != 0 && transaction_id == req->transaction_id) + auto it = std::find_if( + std::begin(reqs), + std::end(reqs), + [&transaction_id](auto const& req) { return req.transaction_id == transaction_id; }); + if (it != std::end(reqs)) { - dbgmsg(tracker->key, "%" PRIu32 " is an announce request!", transaction_id); - tr_ptrArrayRemove(reqs, j); - on_announce_response(req, action_id, buf); - tau_announce_request_free(req); + dbgmsg(tracker.key, "%" PRIu32 " is an announce request!", transaction_id); + auto req = *it; + it = reqs.erase(it); + req.onResponse(action_id, buf); evbuffer_free(buf); return true; } } - /* is it a response to one of this tracker's scrapes? */ - reqs = &tracker->scrapes; - - for (int j = 0, jn = tr_ptrArraySize(reqs); j < jn; ++j) + // is it a response to one of this tracker's scrapes? + if (auto& reqs = tracker.scrapes; !std::empty(reqs)) { - auto* const req = static_cast(tr_ptrArrayNth(reqs, j)); - - if (req->sent_at != 0 && transaction_id == req->transaction_id) + auto it = std::find_if( + std::begin(reqs), + std::end(reqs), + [&transaction_id](auto const& req) { return req.transaction_id == transaction_id; }); + if (it != std::end(reqs)) { - dbgmsg(tracker->key, "%" PRIu32 " is a scrape request!", transaction_id); - tr_ptrArrayRemove(reqs, j); - on_scrape_response(req, action_id, buf); - tau_scrape_request_free(req); + dbgmsg(tracker.key, "%" PRIu32 " is a scrape request!", transaction_id); + auto req = *it; + it = reqs.erase(it); + req.onResponse(action_id, buf); evbuffer_free(buf); return true; } @@ -961,8 +889,7 @@ void tr_tracker_udp_announce( return; } - tau_announce_request* r = tau_announce_request_new(request, response_func, user_data); - tr_ptrArrayAppend(&tracker->announces, r); + tracker->announces.push_back(make_tau_announce_request(request, response_func, user_data)); tau_tracker_upkeep_ex(tracker, false); } @@ -979,7 +906,6 @@ void tr_tracker_udp_scrape( return; } - tau_scrape_request* r = tau_scrape_request_new(request, response_func, user_data); - tr_ptrArrayAppend(&tracker->scrapes, r); + tracker->scrapes.push_back(make_tau_scrape_request(request, response_func, user_data)); tau_tracker_upkeep_ex(tracker, false); } diff --git a/libtransmission/announcer.cc b/libtransmission/announcer.cc index 7504857cf..a121c814b 100644 --- a/libtransmission/announcer.cc +++ b/libtransmission/announcer.cc @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,18 +38,14 @@ using namespace std::literals; -struct tr_tier; - -static void tier_build_log_name(struct tr_tier const* tier, char* buf, size_t buflen); - #define dbgmsg(tier, ...) \ do \ { \ if (tr_logGetDeepEnabled()) \ { \ - char name[128]; \ - tier_build_log_name(tier, name, TR_N_ELEMENTS(name)); \ - tr_logAddDeep(__FILE__, __LINE__, name, __VA_ARGS__); \ + auto name = std::array{}; \ + tier->buildLogName(std::data(name), std::size(name)); \ + tr_logAddDeep(__FILE__, __LINE__, std::data(name), __VA_ARGS__); \ } \ } while (0) @@ -160,18 +158,38 @@ struct tr_scrape_info } }; +static void onUpkeepTimer(evutil_socket_t fd, short what, void* vannouncer); + /** * "global" (per-tr_session) fields */ struct tr_announcer { + explicit tr_announcer(tr_session* session_in) + : session{ session_in } + , upkeep_timer{ evtimer_new(session_in->event_base, onUpkeepTimer, this) } + , key{ tr_rand_int(INT_MAX) } + { + scheduleNextUpdate(); + } + + ~tr_announcer() + { + event_free(upkeep_timer); + } + + void scheduleNextUpdate() const + { + tr_timerAddMsec(this->upkeep_timer, UpkeepIntervalMsec); + } + std::set stops; std::map scrape_info; - tr_session* session; - struct event* upkeepTimer; - int key; - time_t tauUpkeepAt; + tr_session* const session; + event* const upkeep_timer; + int const key; + time_t tau_upkeep_at = 0; }; static tr_scrape_info* tr_announcerGetScrapeInfo(tr_announcer* announcer, tr_interned_string url) @@ -186,17 +204,11 @@ static tr_scrape_info* tr_announcerGetScrapeInfo(tr_announcer* announcer, tr_int return &it.first->second; } -static void onUpkeepTimer(evutil_socket_t fd, short what, void* vannouncer); - void tr_announcerInit(tr_session* session) { TR_ASSERT(tr_isSession(session)); - auto* a = new tr_announcer{}; - a->key = tr_rand_int(INT_MAX); - a->session = session; - a->upkeepTimer = evtimer_new(session->event_base, onUpkeepTimer, a); - tr_timerAddMsec(a->upkeepTimer, UpkeepIntervalMsec); + auto* a = new tr_announcer{ session }; session->announcer = a; } @@ -211,9 +223,6 @@ void tr_announcerClose(tr_session* session) tr_tracker_udp_start_shutdown(session); - event_free(announcer->upkeepTimer); - announcer->upkeepTimer = nullptr; - session->announcer = nullptr; delete announcer; } @@ -225,20 +234,55 @@ void tr_announcerClose(tr_session* session) /* a row in tr_tier's list of trackers */ struct tr_tracker { - tr_interned_string key; - tr_interned_string announce_url; - struct tr_scrape_info* scrape_info; + explicit tr_tracker(tr_announcer* announcer, tr_announce_list::tracker_info const& info) + : host{ info.host } + , announce_url{ info.announce_str } + , scrape_info{ std::empty(info.scrape_str) ? nullptr : tr_announcerGetScrapeInfo(announcer, info.scrape_str) } + , id{ info.id } + { + } - char* tracker_id_str; + int getRetryInterval() const + { + switch (consecutive_failures) + { + case 0: + return 0; - int seederCount; - int leecherCount; - int downloadCount; - int downloaderCount; + case 1: + return 20; - int consecutiveFailures; + case 2: + return tr_rand_int_weak(60) + 60 * 5; - uint32_t id; + case 3: + return tr_rand_int_weak(60) + 60 * 15; + + case 4: + return tr_rand_int_weak(60) + 60 * 30; + + case 5: + return tr_rand_int_weak(60) + 60 * 60; + + default: + return tr_rand_int_weak(60) + 60 * 120; + } + } + + tr_interned_string const host; + tr_interned_string const announce_url; + tr_scrape_info* const scrape_info; + + std::string tracker_id; + + int seeder_count = -1; + int leecher_count = -1; + int download_count = -1; + int downloader_count = -1; + + int consecutive_failures = 0; + + tr_tracker_id_t const id; }; // format: `${host}:${port}` @@ -249,79 +293,166 @@ tr_interned_string tr_announcerGetKey(tr_url_parsed_t const& parsed) return tr_interned_string{ buf }; } -static void trackerConstruct(tr_announcer* announcer, tr_tracker* tracker, tr_announce_list::tracker_info const& info) -{ - memset(tracker, 0, sizeof(tr_tracker)); - tracker->key = info.host; - tracker->announce_url = info.announce_str; - tracker->scrape_info = std::empty(info.scrape_str) ? nullptr : tr_announcerGetScrapeInfo(announcer, info.scrape_str); - tracker->id = info.id; - tracker->seederCount = -1; - tracker->leecherCount = -1; - tracker->downloadCount = -1; -} - -static void trackerDestruct(tr_tracker* tracker) -{ - tr_free(tracker->tracker_id_str); -} - /*** **** ***/ -struct tr_announcer_tiers; - /** @brief A group of trackers in a single tier, as per the multitracker spec */ struct tr_tier { + tr_tier(tr_announcer* announcer, tr_torrent* tor_in, std::vector const& infos) + : tor{ tor_in } + , id{ next_key++ } + { + trackers.reserve(std::size(infos)); + for (auto const* info : infos) + { + trackers.emplace_back(announcer, *info); + } + useNextTracker(); + } + + [[nodiscard]] tr_tracker* currentTracker() + { + if (!current_tracker_index_) + { + return nullptr; + } + + TR_ASSERT(*current_tracker_index_ < std::size(trackers)); + return &trackers[*current_tracker_index_]; + } + + [[nodiscard]] tr_tracker const* currentTracker() const + { + if (!current_tracker_index_) + { + return nullptr; + } + + TR_ASSERT(*current_tracker_index_ < std::size(trackers)); + return &trackers[*current_tracker_index_]; + } + + [[nodiscard]] bool needsToAnnounce(time_t now) const + { + return !isAnnouncing && !isScraping && announceAt != 0 && announceAt <= now && !std::empty(announce_events); + } + + [[nodiscard]] bool needsToScrape(time_t now) const + { + auto const* const tracker = currentTracker(); + + return !isScraping && scrapeAt != 0 && scrapeAt <= now && tracker != nullptr && tracker->scrape_info != nullptr; + } + + [[nodiscard]] auto countDownloaders() const + { + auto const* const tracker = currentTracker(); + + return tracker == nullptr ? 0 : tracker->downloader_count + tracker->leecher_count; + } + + tr_tracker* useNextTracker() + { + // move our index to the next tracker in the tier + if (std::empty(trackers)) + { + current_tracker_index_ = std::nullopt; + } + else if (!current_tracker_index_) + { + current_tracker_index_ = 0; + } + else + { + current_tracker_index_ = (*current_tracker_index_ + 1) % std::size(trackers); + } + + // reset some of the tier's fields + scrapeIntervalSec = DefaultScrapeIntervalSec; + announceIntervalSec = DefaultAnnounceIntervalSec; + announceMinIntervalSec = DefaultAnnounceMinIntervalSec; + isAnnouncing = false; + isScraping = false; + lastAnnounceStartTime = 0; + lastScrapeStartTime = 0; + + return currentTracker(); + } + + [[nodiscard]] std::optional indexOf(tr_interned_string const& announce_url) const + { + for (size_t i = 0, n = std::size(trackers); i < n; ++i) + { + if (announce_url == trackers[i].announce_url) + { + return i; + } + } + + return std::nullopt; + } + + void buildLogName(char* buf, size_t buflen) const + { + auto const* const torrent_name = tr_torrentName(tor); + auto const* const current_tracker = currentTracker(); + auto const host_sv = current_tracker == nullptr ? "?"sv : current_tracker->host.sv(); + tr_snprintf(buf, buflen, "[%s---%" TR_PRIsv "]", torrent_name, TR_PRIsv_ARG(host_sv)); + } + + [[nodiscard]] bool canManualAnnounce() const + { + return this->manualAnnounceAllowedAt <= tr_time(); + } + + tr_torrent* const tor; + /* number of up/down/corrupt bytes since the last time we sent an * "event=stopped" message that was acknowledged by the tracker */ - uint64_t byteCounts[3]; + std::array byteCounts = {}; - tr_tracker* trackers; - int tracker_count; - tr_tracker* currentTracker; - int currentTrackerIndex; + std::vector trackers; + std::optional current_tracker_index_; - tr_torrent* tor; + time_t scrapeAt = 0; + time_t lastScrapeStartTime = 0; + time_t lastScrapeTime = 0; + bool lastScrapeSucceeded = false; + bool lastScrapeTimedOut = false; - time_t scrapeAt; - time_t lastScrapeStartTime; - time_t lastScrapeTime; - bool lastScrapeSucceeded; - bool lastScrapeTimedOut; + time_t announceAt = 0; + time_t manualAnnounceAllowedAt = 0; + time_t lastAnnounceStartTime = 0; + time_t lastAnnounceTime = 0; + bool lastAnnounceSucceeded = false; + bool lastAnnounceTimedOut = false; - time_t announceAt; - time_t manualAnnounceAllowedAt; - time_t lastAnnounceStartTime; - time_t lastAnnounceTime; - bool lastAnnounceSucceeded; - bool lastAnnounceTimedOut; + std::deque announce_events; + int announce_event_priority = 0; - tr_announce_event* announce_events; - int announce_event_priority; - int announce_event_count; - int announce_event_alloc; + int const id; - /* unique lookup key */ - int key; + int scrapeIntervalSec = DefaultScrapeIntervalSec; + int announceIntervalSec = DefaultAnnounceIntervalSec; + int announceMinIntervalSec = DefaultAnnounceMinIntervalSec; - int scrapeIntervalSec; - int announceIntervalSec; - int announceMinIntervalSec; + int lastAnnouncePeerCount = 0; - int lastAnnouncePeerCount; + bool isRunning = false; + bool isAnnouncing = false; + bool isScraping = false; - bool isRunning; - bool isAnnouncing; - bool isScraping; - bool wasCopied; + std::string last_announce_str; + std::string last_scrape_str; - char lastAnnounceStr[128]; - char lastScrapeStr[128]; +private: + static int next_key; }; +int tr_tier::next_key = 0; + static time_t get_next_scrape_time(tr_session const* session, tr_tier const* tier, int interval) { /* Maybe don't scrape paused torrents */ @@ -343,50 +474,6 @@ static time_t get_next_scrape_time(tr_session const* session, tr_tier const* tie return ret; } -static void tierConstruct(tr_tier* tier, tr_torrent* tor) -{ - static int nextKey = 1; - - memset(tier, 0, sizeof(tr_tier)); - - tier->key = nextKey++; - tier->currentTrackerIndex = -1; - tier->scrapeIntervalSec = DefaultScrapeIntervalSec; - tier->announceIntervalSec = DefaultAnnounceIntervalSec; - tier->announceMinIntervalSec = DefaultAnnounceMinIntervalSec; - tier->scrapeAt = get_next_scrape_time(tor->session, tier, 0); - tier->tor = tor; -} - -static void tierDestruct(tr_tier* tier) -{ - tr_free(tier->announce_events); -} - -static void tier_build_log_name(tr_tier const* tier, char* buf, size_t buflen) -{ - auto const* const name = tier != nullptr && tier->tor != nullptr ? tr_torrentName(tier->tor) : "?"; - auto const key_sv = tier != nullptr && tier->currentTracker != nullptr ? tier->currentTracker->key.sv() : "?"sv; - tr_snprintf(buf, buflen, "[%s---%" TR_PRIsv "]", name, TR_PRIsv_ARG(key_sv)); -} - -static void tierIncrementTracker(tr_tier* tier) -{ - /* move our index to the next tracker in the tier */ - int const i = tier->currentTracker == nullptr ? 0 : (tier->currentTrackerIndex + 1) % tier->tracker_count; - tier->currentTrackerIndex = i; - tier->currentTracker = &tier->trackers[i]; - - /* reset some of the tier's fields */ - tier->scrapeIntervalSec = DefaultScrapeIntervalSec; - tier->announceIntervalSec = DefaultAnnounceIntervalSec; - tier->announceMinIntervalSec = DefaultAnnounceMinIntervalSec; - tier->isAnnouncing = false; - tier->isScraping = false; - tier->lastAnnounceStartTime = 0; - tier->lastScrapeStartTime = 0; -} - /*** **** ***/ @@ -396,69 +483,95 @@ static void tierIncrementTracker(tr_tier* tier) * * this opaque data structure can be found in tr_torrent.tiers */ -struct tr_announcer_tiers +struct tr_torrent_announcer { - tr_tier* tiers; - int tier_count; - - tr_tracker* trackers; - int tracker_count; - - tr_tracker_callback callback; - void* callbackData; -}; - -static tr_announcer_tiers* tiersNew(void) -{ - return tr_new0(tr_announcer_tiers, 1); -} - -static void tiersDestruct(tr_announcer_tiers* tt) -{ - for (int i = 0; i < tt->tracker_count; ++i) + tr_torrent_announcer(tr_announcer* announcer, tr_torrent* tor) { - trackerDestruct(&tt->trackers[i]); - } - - tr_free(tt->trackers); - - for (int i = 0; i < tt->tier_count; ++i) - { - tierDestruct(&tt->tiers[i]); - } - - tr_free(tt->tiers); -} - -static void tiersFree(tr_announcer_tiers* tt) -{ - tiersDestruct(tt); - tr_free(tt); -} - -static tr_tier* getTier(tr_announcer* announcer, tr_sha1_digest_t const& info_hash, int tierId) -{ - tr_tier* tier = nullptr; - - if (announcer != nullptr) - { - tr_torrent* const tor = announcer->session->getTorrent(info_hash); - - if (tor != nullptr && tor->announcer_tiers != nullptr) + // build the trackers + auto tier_to_infos = std::map>{}; + auto const& announce_list = tor->announceList(); + for (auto const& info : announce_list) { - tr_announcer_tiers* tt = tor->announcer_tiers; + tier_to_infos[info.tier].emplace_back(&info); + } - for (int i = 0; tier == nullptr && i < tt->tier_count; ++i) - { - if (tt->tiers[i].key == tierId) - { - tier = &tt->tiers[i]; - } - } + for (auto const& tt : tier_to_infos) + { + tiers.emplace_back(announcer, tor, tt.second); } } - return tier; + tr_tier* getTier(int tier_id) + { + for (auto& tier : tiers) + { + if (tier.id == tier_id) + { + return &tier; + } + } + + return nullptr; + } + + tr_tier* getTierFromScrape(tr_interned_string const& scrape_url) + { + for (auto& tier : tiers) + { + auto const* const tracker = tier.currentTracker(); + + if (tracker != nullptr && tracker->scrape_info != nullptr && tracker->scrape_info->scrape_url == scrape_url) + { + return &tier; + } + } + + return nullptr; + } + + bool canManualAnnounce() const + { + return std::any_of(std::begin(tiers), std::end(tiers), [](auto const& tier) { return tier.canManualAnnounce(); }); + } + + bool findTracker(tr_interned_string const& announce_url, tr_tier const** setme_tier, tr_tracker const** setme_tracker) const + { + for (auto const& tier : tiers) + { + for (auto const& tracker : tier.trackers) + { + if (tracker.announce_url == announce_url) + { + *setme_tier = &tier; + *setme_tracker = &tracker; + return true; + } + } + } + + return false; + } + + std::vector tiers; + + tr_tracker_callback callback = nullptr; + void* callback_data = nullptr; +}; + +static tr_tier* getTier(tr_announcer* announcer, tr_sha1_digest_t const& info_hash, int tier_id) +{ + if (announcer == nullptr) + { + return nullptr; + } + + auto* const tor = announcer->session->getTorrent(info_hash); + if (tor == nullptr || tor->torrent_announcer == nullptr) + { + return nullptr; + } + + return tor->torrent_announcer->getTier(tier_id); } /*** @@ -467,20 +580,21 @@ static tr_tier* getTier(tr_announcer* announcer, tr_sha1_digest_t const& info_ha static void publishMessage(tr_tier* tier, std::string_view msg, TrackerEventType type) { - if (tier != nullptr && tier->tor != nullptr && tier->tor->announcer_tiers != nullptr && - tier->tor->announcer_tiers->callback != nullptr) + if (tier != nullptr && tier->tor != nullptr && tier->tor->torrent_announcer != nullptr && + tier->tor->torrent_announcer->callback != nullptr) { - tr_announcer_tiers* tiers = tier->tor->announcer_tiers; + auto* const ta = tier->tor->torrent_announcer; auto event = tr_tracker_event{}; event.messageType = type; event.text = msg; - if (tier->currentTracker != nullptr) + auto* const current_tracker = tier->currentTracker(); + if (current_tracker != nullptr) { - event.announce_url = tier->currentTracker->announce_url; + event.announce_url = current_tracker->announce_url; } - (*tiers->callback)(tier->tor, &event, tiers->callbackData); + (*ta->callback)(tier->tor, &event, ta->callback_data); } } @@ -501,7 +615,7 @@ static void publishError(tr_tier* tier, std::string_view msg) static void publishPeerCounts(tr_tier* tier, int seeders, int leechers) { - if (tier->tor->announcer_tiers->callback != nullptr) + if (tier->tor->torrent_announcer->callback != nullptr) { auto e = tr_tracker_event{}; e.messageType = TR_TRACKER_COUNTS; @@ -509,23 +623,27 @@ static void publishPeerCounts(tr_tier* tier, int seeders, int leechers) e.leechers = leechers; dbgmsg(tier, "peer counts: %d seeders, %d leechers.", seeders, leechers); - (*tier->tor->announcer_tiers->callback)(tier->tor, &e, nullptr); + (*tier->tor->torrent_announcer->callback)(tier->tor, &e, nullptr); } } -static void publishPeersPex(tr_tier* tier, int seeders, int leechers, tr_pex const* pex, int n) +static void publishPeersPex(tr_tier* tier, int seeders, int leechers, std::vector const& pex) { - if (tier->tor->announcer_tiers->callback != nullptr) + if (tier->tor->torrent_announcer->callback != nullptr) { auto e = tr_tracker_event{}; e.messageType = TR_TRACKER_PEERS; e.seeders = seeders; e.leechers = leechers; e.pex = pex; - e.pexCount = n; - dbgmsg(tier, "tracker knows of %d seeders and %d leechers and gave a list of %d peers.", seeders, leechers, n); + dbgmsg( + tier, + "tracker knows of %d seeders and %d leechers and gave a list of %zu peers.", + seeders, + leechers, + std::size(pex)); - (*tier->tor->announcer_tiers->callback)(tier->tor, &e, nullptr); + (*tier->tor->torrent_announcer->callback)(tier->tor, &e, nullptr); } } @@ -533,98 +651,37 @@ static void publishPeersPex(tr_tier* tier, int seeders, int leechers, tr_pex con **** ***/ -static void addTorrentToTier(tr_announcer_tiers* tt, tr_torrent* tor) -{ - auto const n = tor->trackerCount(); - auto const tiers = tor->tiers(); - - // build the tracker and tier arrays - tt->trackers = tr_new0(tr_tracker, n); - tt->tracker_count = n; - tt->tiers = tr_new0(tr_tier, std::size(tiers)); - - auto prev_tier = std::optional{}; - tr_tier* tier = nullptr; - for (size_t i = 0; i < n; ++i) - { - auto const info = tor->tracker(i); - - trackerConstruct(tor->session->announcer, &tt->trackers[i], info); - - if (!prev_tier || *prev_tier != info.tier) - { - tier = &tt->tiers[tt->tier_count++]; - tierConstruct(tier, tor); - tier->trackers = &tt->trackers[i]; - tier->tracker_count = 1; - tierIncrementTracker(tier); - - prev_tier = info.tier; - } - else - { - ++tier->tracker_count; - } - } -} - -tr_announcer_tiers* tr_announcerAddTorrent(tr_torrent* tor, tr_tracker_callback callback, void* callbackData) +tr_torrent_announcer* tr_announcerAddTorrent(tr_torrent* tor, tr_tracker_callback callback, void* callback_data) { TR_ASSERT(tr_isTorrent(tor)); - tr_announcer_tiers* tiers = tiersNew(); - tiers->callback = callback; - tiers->callbackData = callbackData; - - addTorrentToTier(tiers, tor); - - return tiers; + auto* ta = new tr_torrent_announcer(tor->session->announcer, tor); + ta->callback = callback; + ta->callback_data = callback_data; + return ta; } /*** **** ***/ -static bool tierCanManualAnnounce(tr_tier const* tier) -{ - return tier->manualAnnounceAllowedAt <= tr_time(); -} - bool tr_announcerCanManualAnnounce(tr_torrent const* tor) { TR_ASSERT(tr_isTorrent(tor)); - TR_ASSERT(tor->announcer_tiers != nullptr); + TR_ASSERT(tor->torrent_announcer != nullptr); - struct tr_announcer_tiers const* tt = nullptr; - - if (tor->isRunning) - { - tt = tor->announcer_tiers; - } - - /* return true if any tier can manual announce */ - for (int i = 0; tt != nullptr && i < tt->tier_count; ++i) - { - if (tierCanManualAnnounce(&tt->tiers[i])) - { - return true; - } - } - - return false; + return tor->isRunning && tor->torrent_announcer->canManualAnnounce(); } time_t tr_announcerNextManualAnnounce(tr_torrent const* tor) { time_t ret = ~(time_t)0; - struct tr_announcer_tiers const* tt = tor->announcer_tiers; - /* find the earliest manual announce time from all peers */ - for (int i = 0; tt != nullptr && i < tt->tier_count; ++i) + for (auto const& tier : tor->torrent_announcer->tiers) { - if (tt->tiers[i].isRunning) + if (tier.isRunning) { - ret = std::min(ret, tt->tiers[i].manualAnnounceAllowedAt); + ret = std::min(ret, tier.manualAnnounceAllowedAt); } } @@ -635,20 +692,19 @@ static void dbgmsg_tier_announce_queue(tr_tier const* tier) { if (tr_logGetDeepEnabled()) { - char name[128]; - struct evbuffer* buf = evbuffer_new(); + auto name = std::array{}; + tier->buildLogName(std::data(name), std::size(name)); - tier_build_log_name(tier, name, sizeof(name)); - - for (int i = 0; i < tier->announce_event_count; ++i) + auto* const buf = evbuffer_new(); + for (size_t i = 0, n = std::size(tier->announce_events); i < n; ++i) { tr_announce_event const e = tier->announce_events[i]; char const* str = tr_announce_event_get_string(e); - evbuffer_add_printf(buf, "[%d:%s]", i, str); + evbuffer_add_printf(buf, "[%zu:%s]", i, str); } auto const message = evbuffer_free_to_str(buf); - tr_logAddDeep(__FILE__, __LINE__, name, "announce queue is %" TR_PRIsv, TR_PRIsv_ARG(message)); + tr_logAddDeep(__FILE__, __LINE__, std::data(name), "announce queue is %" TR_PRIsv, TR_PRIsv_ARG(message)); } } @@ -657,9 +713,9 @@ static void tier_update_announce_priority(tr_tier* tier) { int priority = -1; - for (int i = 0; i < tier->announce_event_count; ++i) + for (auto const& event : tier->announce_events) { - priority = std::max(priority, int{ tier->announce_events[i] }); + priority = std::max(priority, int{ event }); } tier->announce_event_priority = priority; @@ -667,9 +723,9 @@ static void tier_update_announce_priority(tr_tier* tier) static void tier_announce_remove_trailing(tr_tier* tier, tr_announce_event e) { - while (tier->announce_event_count > 0 && tier->announce_events[tier->announce_event_count - 1] == e) + while (!std::empty(tier->announce_events) && tier->announce_events.back() == e) { - --tier->announce_event_count; + tier->announce_events.resize(std::size(tier->announce_events) - 1); } tier_update_announce_priority(tier); @@ -682,26 +738,18 @@ static void tier_announce_event_push(tr_tier* tier, tr_announce_event e, time_t dbgmsg_tier_announce_queue(tier); dbgmsg(tier, "queued \"%s\"", tr_announce_event_get_string(e)); - if (tier->announce_event_count > 0) + auto& events = tier->announce_events; + if (!std::empty(events)) { /* special case #1: if we're adding a "stopped" event, * dump everything leading up to it except "completed" */ if (e == TR_ANNOUNCE_EVENT_STOPPED) { - bool has_completed = false; - tr_announce_event const c = TR_ANNOUNCE_EVENT_COMPLETED; - - for (int i = 0; !has_completed && i < tier->announce_event_count; ++i) - { - has_completed = c == tier->announce_events[i]; - } - - tier->announce_event_count = 0; - + bool has_completed = std::count(std::begin(events), std::end(events), TR_ANNOUNCE_EVENT_COMPLETED); + events.clear(); if (has_completed) { - tier->announce_events[tier->announce_event_count++] = c; - tier_update_announce_priority(tier); + events.push_back(TR_ANNOUNCE_EVENT_COMPLETED); } } @@ -712,41 +760,29 @@ static void tier_announce_event_push(tr_tier* tier, tr_announce_event e, time_t tier_announce_remove_trailing(tier, e); } - /* make room in the array for another event */ - if (tier->announce_event_alloc <= tier->announce_event_count) - { - tier->announce_event_alloc += 4; - tier->announce_events = tr_renew(tr_announce_event, tier->announce_events, tier->announce_event_alloc); - } - /* add it */ + events.push_back(e); tier->announceAt = announceAt; - tier->announce_events[tier->announce_event_count++] = e; tier_update_announce_priority(tier); dbgmsg_tier_announce_queue(tier); dbgmsg(tier, "announcing in %d seconds", (int)difftime(announceAt, tr_time())); } -static tr_announce_event tier_announce_event_pull(tr_tier* tier) +static auto tier_announce_event_pull(tr_tier* tier) { - tr_announce_event const e = tier->announce_events[0]; - - tr_removeElementFromArray(tier->announce_events, 0, sizeof(tr_announce_event), tier->announce_event_count); - --tier->announce_event_count; + auto const e = tier->announce_events.front(); + tier->announce_events.pop_front(); tier_update_announce_priority(tier); - return e; } static void torrentAddAnnounce(tr_torrent* tor, tr_announce_event e, time_t announceAt) { - struct tr_announcer_tiers* tt = tor->announcer_tiers; - - /* walk through each tier and tell them to announce */ - for (int i = 0; i < tt->tier_count; ++i) + // tell each tier to announce + for (auto& tier : tor->torrent_announcer->tiers) { - tier_announce_event_push(&tt->tiers[i], e, announceAt); + tier_announce_event_push(&tier, e, announceAt); } } @@ -784,11 +820,9 @@ void tr_announcerAddBytes(tr_torrent* tor, int type, uint32_t byteCount) TR_ASSERT(tr_isTorrent(tor)); TR_ASSERT(type == TR_ANN_UP || type == TR_ANN_DOWN || type == TR_ANN_CORRUPT); - struct tr_announcer_tiers* tt = tor->announcer_tiers; - - for (int i = 0; i < tt->tier_count; ++i) + for (auto& tier : tor->torrent_announcer->tiers) { - tt->tiers[i].byteCounts[type] += byteCount; + tier.byteCounts[type] += byteCount; } } @@ -802,10 +836,10 @@ static tr_announce_request* announce_request_new( tr_tier const* tier, tr_announce_event event) { - auto* const req = tr_new0(tr_announce_request, 1); + auto* const req = new tr_announce_request(); req->port = tr_sessionGetPublicPeerPort(announcer->session); - req->announce_url = tier->currentTracker->announce_url; - req->tracker_id_str = tr_strdup(tier->currentTracker->tracker_id_str); + req->announce_url = tier->currentTracker()->announce_url; + req->tracker_id = tier->currentTracker()->tracker_id; req->info_hash = tor->infoHash(); req->peer_id = tr_torrentGetPeerId(tor); req->up = tier->byteCounts[TR_ANN_UP]; @@ -816,108 +850,80 @@ static tr_announce_request* announce_request_new( req->numwant = event == TR_ANNOUNCE_EVENT_STOPPED ? 0 : Numwant; req->key = announcer->key; req->partial_seed = tor->isPartialSeed(); - tier_build_log_name(tier, req->log_name, sizeof(req->log_name)); + tier->buildLogName(req->log_name, sizeof(req->log_name)); return req; } -static void announce_request_free(tr_announce_request* req); - void tr_announcerRemoveTorrent(tr_announcer* announcer, tr_torrent* tor) { - struct tr_announcer_tiers const* tt = tor->announcer_tiers; - - if (tt != nullptr) + auto* const ta = tor->torrent_announcer; + if (ta == nullptr) { - for (int i = 0; i < tt->tier_count; ++i) + return; + } + + for (auto& tier : ta->tiers) + { + if (tier.isRunning) { - tr_tier const* tier = &tt->tiers[i]; + auto const e = TR_ANNOUNCE_EVENT_STOPPED; + auto* req = announce_request_new(announcer, tor, &tier, e); - if (tier->isRunning) + if (announcer->stops.count(req)) { - tr_announce_event const e = TR_ANNOUNCE_EVENT_STOPPED; - tr_announce_request* req = announce_request_new(announcer, tor, tier, e); - - if (announcer->stops.count(req)) - { - announce_request_free(req); - } - else - { - announcer->stops.insert(req); - } + delete req; + } + else + { + announcer->stops.insert(req); } } - - tiersFree(tor->announcer_tiers); - tor->announcer_tiers = nullptr; } -} -static int getRetryInterval(tr_tracker const* t) -{ - switch (t->consecutiveFailures) - { - case 0: - return 0; - - case 1: - return 20; - - case 2: - return tr_rand_int_weak(60) + 60 * 5; - - case 3: - return tr_rand_int_weak(60) + 60 * 15; - - case 4: - return tr_rand_int_weak(60) + 60 * 30; - - case 5: - return tr_rand_int_weak(60) + 60 * 60; - - default: - return tr_rand_int_weak(60) + 60 * 120; - } + tor->torrent_announcer = nullptr; + delete ta; } struct announce_data { - int tierId; - time_t timeSent; - tr_announce_event event; - tr_session* session; + int const tier_id; + time_t const time_sent; + tr_announce_event event = {}; + tr_session* session = nullptr; /** If the request succeeds, the value for tier's "isRunning" flag */ - bool isRunningOnSuccess; + bool is_running_on_success = false; }; static void on_announce_error(tr_tier* tier, char const* err, tr_announce_event e) { /* increment the error count */ - if (tier->currentTracker != nullptr) + auto* current_tracker = tier->currentTracker(); + if (current_tracker != nullptr) { - ++tier->currentTracker->consecutiveFailures; + ++current_tracker->consecutive_failures; } /* set the error message */ - tr_strlcpy(tier->lastAnnounceStr, err, sizeof(tier->lastAnnounceStr)); + tier->last_announce_str = err; /* switch to the next tracker */ - tierIncrementTracker(tier); + current_tracker = tier->useNextTracker(); /* schedule a reannounce */ - int const interval = getRetryInterval(tier->currentTracker); - auto const* const key_cstr = tier->currentTracker->key.c_str(); - dbgmsg(tier, "Tracker '%s' announce error: %s (Retrying in %d seconds)", key_cstr, err, interval); - tr_logAddTorInfo(tier->tor, "Tracker '%s' announce error: %s (Retrying in %d seconds)", key_cstr, err, interval); + int const interval = current_tracker->getRetryInterval(); + auto const* const host_cstr = current_tracker->host.c_str(); + dbgmsg(tier, "Tracker '%s' announce error: %s (Retrying in %d seconds)", host_cstr, err, interval); + tr_logAddTorInfo(tier->tor, "Tracker '%s' announce error: %s (Retrying in %d seconds)", host_cstr, err, interval); tier_announce_event_push(tier, e, tr_time() + interval); } static void on_announce_done(tr_announce_response const* response, void* vdata) { - auto* data = static_cast(vdata); + auto* const data = static_cast(vdata); + tr_announcer* announcer = data->session->announcer; - tr_tier* tier = getTier(announcer, response->info_hash, data->tierId); + tr_tier* tier = getTier(announcer, response->info_hash, data->tier_id); time_t const now = tr_time(); tr_announce_event const event = data->event; @@ -945,9 +951,9 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) response->downloads, response->interval, response->min_interval, - response->tracker_id_str != nullptr ? response->tracker_id_str : "none", - response->pex_count, - response->pex6_count, + (!std::empty(response->tracker_id) ? response->tracker_id.c_str() : "none"), + std::size(response->pex), + std::size(response->pex6), (!std::empty(response->errmsg) ? response->errmsg.c_str() : "none"), (!std::empty(response->warning) ? response->warning.c_str() : "none")); @@ -987,45 +993,44 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) publishErrorClear(tier); - tr_tracker* const tracker = tier->currentTracker; + tr_tracker* const tracker = tier->currentTracker(); if (tracker != nullptr) { - tracker->consecutiveFailures = 0; + tracker->consecutive_failures = 0; if (response->seeders >= 0) { - tracker->seederCount = seeders = response->seeders; + tracker->seeder_count = seeders = response->seeders; ++scrape_fields; } if (response->leechers >= 0) { - tracker->leecherCount = leechers = response->leechers; + tracker->leecher_count = leechers = response->leechers; ++scrape_fields; } if (response->downloads >= 0) { - tracker->downloadCount = response->downloads; + tracker->download_count = response->downloads; ++scrape_fields; } - if (response->tracker_id_str != nullptr) + if (!std::empty(response->tracker_id)) { - tr_free(tracker->tracker_id_str); - tracker->tracker_id_str = tr_strdup(response->tracker_id_str); + tracker->tracker_id = response->tracker_id; } } if (auto const& warning = response->warning; !std::empty(warning)) { - tr_strlcpy(tier->lastAnnounceStr, warning.c_str(), sizeof(tier->lastAnnounceStr)); + tier->last_announce_str = warning; dbgmsg(tier, "tracker gave \"%s\"", warning.c_str()); publishWarning(tier, warning); } else { - tr_strlcpy(tier->lastAnnounceStr, _("Success"), sizeof(tier->lastAnnounceStr)); + tier->last_announce_str = _("Success"); } if (response->min_interval != 0) @@ -1038,19 +1043,19 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) tier->announceIntervalSec = response->interval; } - if (response->pex_count > 0) + if (!std::empty(response->pex)) { - publishPeersPex(tier, seeders, leechers, response->pex, response->pex_count); + publishPeersPex(tier, seeders, leechers, response->pex); } - if (response->pex6_count > 0) + if (!std::empty(response->pex6)) { - publishPeersPex(tier, seeders, leechers, response->pex6, response->pex6_count); + publishPeersPex(tier, seeders, leechers, response->pex6); } publishPeerCounts(tier, seeders, leechers); - tier->isRunning = data->isRunningOnSuccess; + tier->isRunning = data->is_running_on_success; /* if the tracker included scrape fields in its announce response, then a separate scrape isn't needed */ @@ -1071,7 +1076,7 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) } tier->lastAnnounceSucceeded = true; - tier->lastAnnouncePeerCount = response->pex_count + response->pex6_count; + tier->lastAnnouncePeerCount = std::size(response->pex) + std::size(response->pex6); if (isStopped) { @@ -1083,7 +1088,7 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) tier->byteCounts[TR_ANN_CORRUPT] = 0; } - if (!isStopped && tier->announce_event_count == 0) + if (!isStopped && std::empty(tier->announce_events)) { /* the queue is empty, so enqueue a perodic update */ int const i = tier->announceIntervalSec; @@ -1093,20 +1098,14 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) } } - tr_free(data); -} - -static void announce_request_free(tr_announce_request* req) -{ - tr_free(req->tracker_id_str); - tr_free(req); + delete data; } static void announce_request_delegate( tr_announcer* announcer, tr_announce_request* request, tr_announce_response_func callback, - void* callback_data) + announce_data* callback_data) { tr_session* session = announcer->session; @@ -1132,15 +1131,16 @@ static void announce_request_delegate( else { tr_logAddError("Unsupported url: %" TR_PRIsv, TR_PRIsv_ARG(announce_sv)); + delete callback_data; } - announce_request_free(request); + delete request; } static void tierAnnounce(tr_announcer* announcer, tr_tier* tier) { TR_ASSERT(!tier->isAnnouncing); - TR_ASSERT(tier->announce_event_count > 0); + TR_ASSERT(!std::empty(tier->announce_events)); time_t const now = tr_time(); @@ -1148,12 +1148,7 @@ static void tierAnnounce(tr_announcer* announcer, tr_tier* tier) tr_announce_event announce_event = tier_announce_event_pull(tier); tr_announce_request* req = announce_request_new(announcer, tor, tier, announce_event); - auto* const data = tr_new0(struct announce_data, 1); - data->session = announcer->session; - data->tierId = tier->key; - data->isRunningOnSuccess = tor->isRunning; - data->timeSent = now; - data->event = announce_event; + auto* const data = new announce_data{ tier->id, now, announce_event, announcer->session, tor->isRunning }; tier->isAnnouncing = true; tier->lastAnnounceStartTime = now; @@ -1167,7 +1162,7 @@ static void tierAnnounce(tr_announcer* announcer, tr_tier* tier) **** ***/ -static constexpr bool multiscrape_too_big(std::string_view errmsg) +static bool multiscrape_too_big(std::string_view errmsg) { /* Found a tracker that returns some bespoke string for this case? Add your patch here and open a PR */ @@ -1177,57 +1172,36 @@ static constexpr bool multiscrape_too_big(std::string_view errmsg) "Request-URI Too Long", }; - for (auto const& tle : TooLongErrors) - { - if (tr_strvContains(errmsg, tle)) - { - return true; - } - } - - return false; + return std::any_of( + std::begin(TooLongErrors), + std::end(TooLongErrors), + [&errmsg](auto const& substr) { return tr_strvContains(errmsg, substr); }); } static void on_scrape_error(tr_session const* session, tr_tier* tier, char const* errmsg) { - /* increment the error count */ - if (tier->currentTracker != nullptr) + // increment the error count + auto* current_tracker = tier->currentTracker(); + if (current_tracker != nullptr) { - ++tier->currentTracker->consecutiveFailures; + ++current_tracker->consecutive_failures; } - /* set the error message */ - tr_strlcpy(tier->lastScrapeStr, errmsg, sizeof(tier->lastScrapeStr)); + // set the error message + tier->last_scrape_str = errmsg != nullptr ? errmsg : ""; - /* switch to the next tracker */ - tierIncrementTracker(tier); + // switch to the next tracker + current_tracker = tier->useNextTracker(); - /* schedule a rescrape */ - int const interval = getRetryInterval(tier->currentTracker); - auto const* const key_cstr = tier->currentTracker->key.c_str(); - dbgmsg(tier, "Tracker '%s' scrape error: %s (Retrying in %zu seconds)", key_cstr, errmsg, (size_t)interval); - tr_logAddTorInfo(tier->tor, "Tracker '%s' error: %s (Retrying in %zu seconds)", key_cstr, errmsg, (size_t)interval); + // schedule a rescrape + auto const interval = current_tracker->getRetryInterval(); + auto const* const host_cstr = current_tracker->host.c_str(); + dbgmsg(tier, "Tracker '%s' scrape error: %s (Retrying in %zu seconds)", host_cstr, errmsg, (size_t)interval); + tr_logAddTorInfo(tier->tor, "Tracker '%s' error: %s (Retrying in %zu seconds)", host_cstr, errmsg, (size_t)interval); tier->lastScrapeSucceeded = false; tier->scrapeAt = get_next_scrape_time(session, tier, interval); } -static tr_tier* find_tier(tr_torrent* tor, tr_interned_string scrape_url) -{ - struct tr_announcer_tiers* tt = tor->announcer_tiers; - - for (int i = 0; tt != nullptr && i < tt->tier_count; ++i) - { - tr_tracker const* const tracker = tt->tiers[i].currentTracker; - - if (tracker != nullptr && tracker->scrape_info != nullptr && tracker->scrape_info->scrape_url == scrape_url) - { - return &tt->tiers[i]; - } - } - - return nullptr; -} - static void checkMultiscrapeMax(tr_announcer* announcer, tr_scrape_response const* response) { if (!multiscrape_too_big(response->errmsg)) @@ -1236,7 +1210,7 @@ static void checkMultiscrapeMax(tr_announcer* announcer, tr_scrape_response cons } auto const& url = response->scrape_url; - struct tr_scrape_info* const scrape_info = tr_announcerGetScrapeInfo(announcer, url); + auto* const scrape_info = tr_announcerGetScrapeInfo(announcer, url); if (scrape_info == nullptr) { return; @@ -1266,95 +1240,97 @@ static void checkMultiscrapeMax(tr_announcer* announcer, tr_scrape_response cons static void on_scrape_done(tr_scrape_response const* response, void* vsession) { - time_t const now = tr_time(); - auto* session = static_cast(vsession); - tr_announcer* announcer = session->announcer; + auto const now = tr_time(); + auto* const session = static_cast(vsession); + auto* const announcer = session->announcer; for (int i = 0; i < response->row_count; ++i) { - struct tr_scrape_response_row const* row = &response->rows[i]; - tr_torrent* tor = session->getTorrent(row->info_hash); + auto const& row = response->rows[i]; + auto* const tor = session->getTorrent(row.info_hash); if (tor != nullptr) { - tr_tier* tier = find_tier(tor, response->scrape_url); + auto* tier = tor->torrent_announcer->getTierFromScrape(response->scrape_url); - if (tier != nullptr) + if (tier == nullptr) { - auto const scrape_url_sv = response->scrape_url.sv(); + continue; + } - dbgmsg( - tier, - "scraped url:%" TR_PRIsv - " -- " - "did_connect:%d " - "did_timeout:%d " - "seeders:%d " - "leechers:%d " - "downloads:%d " - "downloaders:%d " - "min_request_interval:%d " - "err:%s ", - TR_PRIsv_ARG(scrape_url_sv), - (int)response->did_connect, - (int)response->did_timeout, - row->seeders, - row->leechers, - row->downloads, - row->downloaders, - response->min_request_interval, - std::empty(response->errmsg) ? "none" : response->errmsg.c_str()); + auto const scrape_url_sv = response->scrape_url.sv(); - tier->isScraping = false; - tier->lastScrapeTime = now; - tier->lastScrapeSucceeded = false; - tier->lastScrapeTimedOut = response->did_timeout; + dbgmsg( + tier, + "scraped url:%" TR_PRIsv + " -- " + "did_connect:%d " + "did_timeout:%d " + "seeders:%d " + "leechers:%d " + "downloads:%d " + "downloaders:%d " + "min_request_interval:%d " + "err:%s ", + TR_PRIsv_ARG(scrape_url_sv), + (int)response->did_connect, + (int)response->did_timeout, + row.seeders, + row.leechers, + row.downloads, + row.downloaders, + response->min_request_interval, + std::empty(response->errmsg) ? "none" : response->errmsg.c_str()); - if (!response->did_connect) - { - on_scrape_error(session, tier, _("Could not connect to tracker")); - } - else if (response->did_timeout) - { - on_scrape_error(session, tier, _("Tracker did not respond")); - } - else if (!std::empty(response->errmsg)) - { - on_scrape_error(session, tier, response->errmsg.c_str()); - } - else - { - tier->lastScrapeSucceeded = true; - tier->scrapeIntervalSec = std::max(int{ DefaultScrapeIntervalSec }, response->min_request_interval); - tier->scrapeAt = get_next_scrape_time(session, tier, tier->scrapeIntervalSec); - tr_logAddTorDbg(tier->tor, "Scrape successful. Rescraping in %d seconds.", tier->scrapeIntervalSec); + tier->isScraping = false; + tier->lastScrapeTime = now; + tier->lastScrapeSucceeded = false; + tier->lastScrapeTimedOut = response->did_timeout; - tr_tracker* const tracker = tier->currentTracker; - if (tracker != nullptr) + if (!response->did_connect) + { + on_scrape_error(session, tier, _("Could not connect to tracker")); + } + else if (response->did_timeout) + { + on_scrape_error(session, tier, _("Tracker did not respond")); + } + else if (!std::empty(response->errmsg)) + { + on_scrape_error(session, tier, response->errmsg.c_str()); + } + else + { + tier->lastScrapeSucceeded = true; + tier->scrapeIntervalSec = std::max(int{ DefaultScrapeIntervalSec }, response->min_request_interval); + tier->scrapeAt = get_next_scrape_time(session, tier, tier->scrapeIntervalSec); + tr_logAddTorDbg(tier->tor, "Scrape successful. Rescraping in %d seconds.", tier->scrapeIntervalSec); + + tr_tracker* const tracker = tier->currentTracker(); + if (tracker != nullptr) + { + if (row.seeders >= 0) { - if (row->seeders >= 0) - { - tracker->seederCount = row->seeders; - } - - if (row->leechers >= 0) - { - tracker->leecherCount = row->leechers; - } - - if (row->downloads >= 0) - { - tracker->downloadCount = row->downloads; - } - - tracker->downloaderCount = row->downloaders; - tracker->consecutiveFailures = 0; + tracker->seeder_count = row.seeders; } - if (row->seeders >= 0 && row->leechers >= 0 && row->downloads >= 0) + if (row.leechers >= 0) { - publishPeerCounts(tier, row->seeders, row->leechers); + tracker->leecher_count = row.leechers; } + + if (row.downloads >= 0) + { + tracker->download_count = row.downloads; + } + + tracker->downloader_count = row.downloaders; + tracker->consecutive_failures = 0; + } + + if (row.seeders >= 0 && row.leechers >= 0 && row.downloads >= 0) + { + publishPeerCounts(tier, row.seeders, row.leechers); } } } @@ -1389,14 +1365,14 @@ static void scrape_request_delegate( static void multiscrape(tr_announcer* announcer, std::vector const& tiers) { - size_t request_count = 0; - time_t const now = tr_time(); - tr_scrape_request requests[MaxScrapesPerUpkeep] = {}; + auto const now = tr_time(); + auto requests = std::array{}; + auto request_count = size_t{}; - /* batch as many info_hashes into a request as we can */ + // batch as many info_hashes into a request as we can for (auto* tier : tiers) { - struct tr_scrape_info* const scrape_info = tier->currentTracker->scrape_info; + auto* const scrape_info = tier->currentTracker()->scrape_info; bool found = false; TR_ASSERT(scrape_info != nullptr); @@ -1404,7 +1380,7 @@ static void multiscrape(tr_announcer* announcer, std::vector const& ti /* if there's a request with this scrape URL and a free slot, use it */ for (size_t j = 0; !found && j < request_count; ++j) { - tr_scrape_request* req = &requests[j]; + auto* const req = &requests[j]; if (req->info_hash_count >= scrape_info->multiscrape_max) { @@ -1426,9 +1402,9 @@ static void multiscrape(tr_announcer* announcer, std::vector const& ti /* otherwise, if there's room for another request, build a new one */ if (!found && request_count < MaxScrapesPerUpkeep) { - tr_scrape_request* req = &requests[request_count++]; + auto* const req = &requests[request_count++]; req->scrape_url = scrape_info->scrape_url; - tier_build_log_name(tier, req->log_name, sizeof(req->log_name)); + tier->buildLogName(req->log_name, sizeof(req->log_name)); req->info_hash[req->info_hash_count] = tier->tor->infoHash(); ++req->info_hash_count; @@ -1454,25 +1430,6 @@ static void flushCloseMessages(tr_announcer* announcer) stops.clear(); } -static constexpr bool tierNeedsToAnnounce(tr_tier const* tier, time_t const now) -{ - return !tier->isAnnouncing && !tier->isScraping && tier->announceAt != 0 && tier->announceAt <= now && - tier->announce_event_count > 0; -} - -static constexpr bool tierNeedsToScrape(tr_tier const* tier, time_t const now) -{ - return !tier->isScraping && tier->scrapeAt != 0 && tier->scrapeAt <= now && tier->currentTracker != nullptr && - tier->currentTracker->scrape_info != nullptr; -} - -static constexpr int countDownloaders(tr_tier const* tier) -{ - tr_tracker const* const tracker = tier->currentTracker; - - return tracker == nullptr ? 0 : tracker->downloaderCount + tracker->leecherCount; -} - static int compareAnnounceTiers(tr_tier const* a, tr_tier const* b) { /* prefer higher-priority events */ @@ -1482,7 +1439,7 @@ static int compareAnnounceTiers(tr_tier const* a, tr_tier const* b) } /* prefer swarms where we might upload */ - if (auto const leechers_a = countDownloaders(a), leechers_b = countDownloaders(b); leechers_a != leechers_b) + if (auto const leechers_a = a->countDownloaders(), leechers_b = b->countDownloaders(); leechers_a != leechers_b) { return leechers_a > leechers_b ? -1 : 1; } @@ -1521,20 +1478,16 @@ static void scrapeAndAnnounceMore(tr_announcer* announcer) auto scrape_me = std::vector{}; for (auto* tor : announcer->session->torrents) { - struct tr_announcer_tiers* tt = tor->announcer_tiers; - - for (int i = 0; tt != nullptr && i < tt->tier_count; ++i) + for (auto& tier : tor->torrent_announcer->tiers) { - tr_tier* tier = &tt->tiers[i]; - - if (tierNeedsToAnnounce(tier, now)) + if (tier.needsToAnnounce(now)) { - announce_me.push_back(tier); + announce_me.push_back(&tier); } - if (tierNeedsToScrape(tier, now)) + if (tier.needsToScrape(now)) { - scrape_me.push_back(tier); + scrape_me.push_back(&tier); } } } @@ -1583,14 +1536,14 @@ static void onUpkeepTimer(evutil_socket_t /*fd*/, short /*what*/, void* vannounc } /* TAU upkeep */ - if (announcer->tauUpkeepAt <= now) + if (announcer->tau_upkeep_at <= now) { - announcer->tauUpkeepAt = now + TauUpkeepIntervalSecs; + announcer->tau_upkeep_at = now + TauUpkeepIntervalSecs; tr_tracker_udp_upkeep(session); } - /* set up the next timer */ - tr_timerAddMsec(announcer->upkeepTimer, UpkeepIntervalMsec); + // set up the next timer + announcer->scheduleNextUpdate(); } /*** @@ -1602,17 +1555,17 @@ static tr_tracker_view trackerView(tr_torrent const& tor, int tier_index, tr_tie auto const now = tr_time(); auto view = tr_tracker_view{}; - view.host = tracker.key.c_str(); + view.host = tracker.host.c_str(); view.announce = tracker.announce_url.c_str(); view.scrape = tracker.scrape_info == nullptr ? "" : tracker.scrape_info->scrape_url.c_str(); view.id = tracker.id; view.tier = tier_index; - view.isBackup = &tracker != tier.currentTracker; + view.isBackup = &tracker != tier.currentTracker(); view.lastScrapeStartTime = tier.lastScrapeStartTime; - view.seederCount = tracker.seederCount; - view.leecherCount = tracker.leecherCount; - view.downloadCount = tracker.downloadCount; + view.seederCount = tracker.seeder_count; + view.leecherCount = tracker.leecher_count; + view.downloadCount = tracker.download_count; if (view.isBackup) { @@ -1629,7 +1582,7 @@ static tr_tracker_view trackerView(tr_torrent const& tor, int tier_index, tr_tie view.lastScrapeTime = tier.lastScrapeTime; view.lastScrapeSucceeded = tier.lastScrapeSucceeded; view.lastScrapeTimedOut = tier.lastScrapeTimedOut; - tr_strlcpy(view.lastScrapeResult, tier.lastScrapeStr, sizeof(view.lastScrapeResult)); + tr_strlcpy(view.lastScrapeResult, tier.last_scrape_str.c_str(), sizeof(view.lastScrapeResult)); } if (tier.isScraping) @@ -1659,7 +1612,7 @@ static tr_tracker_view trackerView(tr_torrent const& tor, int tier_index, tr_tie view.lastAnnounceSucceeded = tier.lastAnnounceSucceeded; view.lastAnnounceTimedOut = tier.lastAnnounceTimedOut; view.lastAnnouncePeerCount = tier.lastAnnouncePeerCount; - tr_strlcpy(view.lastAnnounceResult, tier.lastAnnounceStr, sizeof(view.lastAnnounceResult)); + tr_strlcpy(view.lastAnnounceResult, tier.last_announce_str.c_str(), sizeof(view.lastAnnounceResult)); } if (tier.isAnnouncing) @@ -1682,42 +1635,42 @@ static tr_tracker_view trackerView(tr_torrent const& tor, int tier_index, tr_tie } TR_ASSERT(0 <= view.tier); - TR_ASSERT(view.tier < tor.announcer_tiers->tier_count); return view; } size_t tr_announcerTrackerCount(tr_torrent const* tor) { TR_ASSERT(tr_isTorrent(tor)); - TR_ASSERT(tor->announcer_tiers != nullptr); + TR_ASSERT(tor->torrent_announcer != nullptr); - return tor->announcer_tiers->tracker_count; + auto const& tiers = tor->torrent_announcer->tiers; + return std::accumulate( + std::begin(tiers), + std::end(tiers), + size_t{}, + [](size_t acc, auto const& cur) { return acc + std::size(cur.trackers); }); } tr_tracker_view tr_announcerTracker(tr_torrent const* tor, size_t nth) { TR_ASSERT(tr_isTorrent(tor)); - TR_ASSERT(tor->announcer_tiers != nullptr); + TR_ASSERT(tor->torrent_announcer != nullptr); - // find the nth tracker - struct tr_announcer_tiers const* const tt = tor->announcer_tiers; - if (nth >= size_t(tt->tracker_count)) + auto i = size_t{ 0 }; + for (auto const& tier : tor->torrent_announcer->tiers) { - return {}; - } - auto const& tracker = tt->trackers[nth]; - for (int i = 0; i < tt->tier_count; ++i) - { - tr_tier const& tier = tt->tiers[i]; - - for (int j = 0; j < tier.tracker_count; ++j) + for (auto const& tracker : tier.trackers) { - if (&tier.trackers[j] == &tracker) + if (i == nth) { return trackerView(*tor, i, tier, tracker); } + + ++i; } } + + TR_ASSERT(false); return {}; } @@ -1725,91 +1678,54 @@ tr_tracker_view tr_announcerTracker(tr_torrent const* tor, size_t nth) **** ***/ -static void copy_tier_attributes_impl(struct tr_tier* tgt, int trackerIndex, tr_tier const* src) -{ - /* sanity clause */ - TR_ASSERT(trackerIndex < tgt->tracker_count); - TR_ASSERT(tgt->trackers[trackerIndex].announce_url == src->currentTracker->announce_url); - - tr_tier const keep = *tgt; - - /* bitwise copy will handle most of tr_tier's fields... */ - *tgt = *src; - - /* ...fix the fields that can't be cleanly bitwise-copied */ - tgt->wasCopied = true; - tgt->trackers = keep.trackers; - tgt->tracker_count = keep.tracker_count; - tgt->announce_events = static_cast( - tr_memdup(src->announce_events, sizeof(tr_announce_event) * src->announce_event_count)); - tgt->announce_event_priority = src->announce_event_priority; - tgt->announce_event_count = src->announce_event_count; - tgt->announce_event_alloc = src->announce_event_count; - tgt->currentTrackerIndex = trackerIndex; - tgt->currentTracker = &tgt->trackers[trackerIndex]; - tgt->currentTracker->seederCount = src->currentTracker->seederCount; - tgt->currentTracker->leecherCount = src->currentTracker->leecherCount; - tgt->currentTracker->downloadCount = src->currentTracker->downloadCount; - tgt->currentTracker->downloaderCount = src->currentTracker->downloaderCount; -} - -static void copy_tier_attributes(struct tr_announcer_tiers* tt, tr_tier const* src) -{ - bool found = false; - - /* find a tier (if any) which has a match for src->currentTracker */ - for (int i = 0; !found && i < tt->tier_count; ++i) - { - for (int j = 0; !found && j < tt->tiers[i].tracker_count; ++j) - { - if (src->currentTracker->announce_url == tt->tiers[i].trackers[j].announce_url) - { - found = true; - copy_tier_attributes_impl(&tt->tiers[i], j, src); - } - } - } -} - +// called after the torrent's announceList was rebuilt -- +// so announcer needs to update the tr_tier / tr_trackers to match void tr_announcerResetTorrent(tr_announcer* /*announcer*/, tr_torrent* tor) { - TR_ASSERT(tor->announcer_tiers != nullptr); + // make a new tr_announcer_tier + auto* const older = tor->torrent_announcer; + tor->torrent_announcer = new tr_torrent_announcer(tor->session->announcer, tor); + auto* const newer = tor->torrent_announcer; - time_t const now = tr_time(); - - tr_announcer_tiers* tt = tor->announcer_tiers; - tr_announcer_tiers old = *tt; - - /* remove the old tiers / trackers */ - tt->tiers = nullptr; - tt->trackers = nullptr; - tt->tier_count = 0; - tt->tracker_count = 0; - - /* create the new tiers / trackers */ - addTorrentToTier(tt, tor); - - /* copy the old tiers' states into their replacements */ - for (int i = 0; i < old.tier_count; ++i) + // copy the tracker counts into the new replacementa + if (older != nullptr) { - if (old.tiers[i].currentTracker != nullptr) + for (auto& new_tier : newer->tiers) { - copy_tier_attributes(tt, &old.tiers[i]); - } - } - - /* kickstart any tiers that didn't get started */ - if (tor->isRunning) - { - for (int i = 0; i < tt->tier_count; ++i) - { - if (!tt->tiers[i].wasCopied) + for (auto& new_tracker : new_tier.trackers) { - tier_announce_event_push(&tt->tiers[i], TR_ANNOUNCE_EVENT_STARTED, now); + tr_tier const* old_tier = nullptr; + tr_tracker const* old_tracker = nullptr; + if (older->findTracker(new_tracker.announce_url, &old_tier, &old_tracker)) + { + new_tracker.seeder_count = old_tracker->seeder_count; + new_tracker.leecher_count = old_tracker->leecher_count; + new_tracker.download_count = old_tracker->download_count; + new_tracker.downloader_count = old_tracker->downloader_count; + + new_tier.announce_events = old_tier->announce_events; + new_tier.announce_event_priority = old_tier->announce_event_priority; + + auto const* const old_current = old_tier->currentTracker(); + new_tier.current_tracker_index_ = old_current == nullptr ? std::nullopt : + new_tier.indexOf(old_current->announce_url); + } } } } - /* cleanup */ - tiersDestruct(&old); + // kickstart any tiers that didn't get started + if (tor->isRunning) + { + auto const now = tr_time(); + for (auto& tier : newer->tiers) + { + if (!tier.current_tracker_index_) + { + tier_announce_event_push(&tier, TR_ANNOUNCE_EVENT_STARTED, now); + } + } + } + + delete older; } diff --git a/libtransmission/announcer.h b/libtransmission/announcer.h index 774ad484a..7ab41f462 100644 --- a/libtransmission/announcer.h +++ b/libtransmission/announcer.h @@ -12,13 +12,14 @@ #include // size_t #include #include +#include #include "transmission.h" #include "interned-string.h" struct tr_announcer; -struct tr_announcer_tiers; +struct tr_torrent_announcer; /** * *** Tracker Publish / Subscribe @@ -46,8 +47,7 @@ struct tr_tracker_event tr_interned_string announce_url; /* for TR_TRACKER_PEERS */ - struct tr_pex const* pex; - size_t pexCount; + std::vector pex; /* for TR_TRACKER_PEERS and TR_TRACKER_COUNTS */ int leechers; @@ -68,7 +68,7 @@ void tr_announcerClose(tr_session*); *** For torrent customers **/ -struct tr_announcer_tiers* tr_announcerAddTorrent(tr_torrent* torrent, tr_tracker_callback cb, void* cbdata); +struct tr_torrent_announcer* tr_announcerAddTorrent(tr_torrent* torrent, tr_tracker_callback cb, void* cbdata); void tr_announcerResetTorrent(struct tr_announcer*, tr_torrent*); diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index 90f02ffdb..cd162f922 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -1201,6 +1201,27 @@ tr_pex* tr_peerMgrCompactToPex( return pex; } +std::vector tr_peerMgrCompactToPex(void const* compact, size_t compactLen, uint8_t const* added_f, size_t added_f_len) +{ + size_t n = compactLen / 6; + auto const* walk = static_cast(compact); + auto pex = std::vector(n); + + for (size_t i = 0; i < n; ++i) + { + pex[i].addr.type = TR_AF_INET; + walk = std::copy_n(walk, 4, reinterpret_cast(&pex[i].addr.addr)); + walk = std::copy_n(walk, 2, reinterpret_cast(&pex[i].port)); + + if (added_f != nullptr && n == added_f_len) + { + pex[i].flags = added_f[i]; + } + } + + return pex; +} + tr_pex* tr_peerMgrCompact6ToPex( void const* compact, size_t compactLen, @@ -1230,6 +1251,27 @@ tr_pex* tr_peerMgrCompact6ToPex( return pex; } +std::vector tr_peerMgrCompact6ToPex(void const* compact, size_t compactLen, uint8_t const* added_f, size_t added_f_len) +{ + size_t n = compactLen / 18; + auto const* walk = static_cast(compact); + auto pex = std::vector(n); + + for (size_t i = 0; i < n; ++i) + { + pex[i].addr.type = TR_AF_INET6; + walk = std::copy_n(walk, 16, reinterpret_cast(&pex[i].addr.addr.addr6.s6_addr)); + walk = std::copy_n(walk, 2, reinterpret_cast(&pex[i].port)); + + if (added_f != nullptr && n == added_f_len) + { + pex[i].flags = added_f[i]; + } + } + + return pex; +} + /** *** **/ diff --git a/libtransmission/peer-mgr.h b/libtransmission/peer-mgr.h index 4e990e188..5947a2d3a 100644 --- a/libtransmission/peer-mgr.h +++ b/libtransmission/peer-mgr.h @@ -101,6 +101,10 @@ tr_pex* tr_peerMgrCompact6ToPex( size_t added_f_len, size_t* pexCount); +std::vector tr_peerMgrCompactToPex(void const* compact, size_t compactLen, uint8_t const* added_f, size_t added_f_len); + +std::vector tr_peerMgrCompact6ToPex(void const* compact, size_t compactLen, uint8_t const* added_f, size_t added_f_len); + size_t tr_peerMgrAddPex(tr_torrent* tor, uint8_t from, tr_pex const* pex, size_t n_pex); void tr_peerMgrSetSwarmIsAllSeeds(tr_torrent* tor); diff --git a/libtransmission/port-forwarding.cc b/libtransmission/port-forwarding.cc index 89f7b5e1e..dd42b3386 100644 --- a/libtransmission/port-forwarding.cc +++ b/libtransmission/port-forwarding.cc @@ -68,7 +68,6 @@ static char const* getNatStateStr(int state) static void natPulse(tr_shared* s, bool do_check) { - tr_port received_private_port; tr_port const private_peer_port = s->session->private_peer_port; bool const is_enabled = s->isEnabled && !s->isShuttingDown; @@ -85,6 +84,7 @@ static void natPulse(tr_shared* s, bool do_check) auto const old_status = tr_sharedTraversalStatus(s); auto public_peer_port = tr_port{}; + auto received_private_port = tr_port{}; s->natpmpStatus = tr_natpmpPulse(s->natpmp, private_peer_port, is_enabled, &public_peer_port, &received_private_port); if (s->natpmpStatus == TR_PORT_MAPPED) diff --git a/libtransmission/session.h b/libtransmission/session.h index 3e412dbee..ab9320cd5 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -103,12 +103,12 @@ struct tr_turtle_info struct tr_session { public: - auto unique_lock() const + [[nodiscard]] auto unique_lock() const { return std::unique_lock(session_mutex_); } - bool isClosing() const + [[nodiscard]] bool isClosing() const { return is_closing_; } diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index b52d7b92a..0f161d3bb 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -508,8 +508,8 @@ static void onTrackerResponse(tr_torrent* tor, tr_tracker_event const* event, vo switch (event->messageType) { case TR_TRACKER_PEERS: - tr_logAddTorDbg(tor, "Got %zu peers from tracker", event->pexCount); - tr_peerMgrAddPex(tor, TR_PEER_FROM_TRACKER, event->pex, event->pexCount); + tr_logAddTorDbg(tor, "Got %zu peers from tracker", size_t(std::size(event->pex))); + tr_peerMgrAddPex(tor, TR_PEER_FROM_TRACKER, std::data(event->pex), std::size(event->pex)); break; case TR_TRACKER_COUNTS: @@ -733,7 +733,7 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) tr_error_clear(&error); } - tor->announcer_tiers = tr_announcerAddTorrent(tor, onTrackerResponse, nullptr); + tor->torrent_announcer = tr_announcerAddTorrent(tor, onTrackerResponse, nullptr); if (is_new_torrent) { diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index d5c11222d..2f9e6dc74 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -37,7 +37,7 @@ struct tr_magnet_info; struct tr_metainfo_parsed; struct tr_session; struct tr_torrent; -struct tr_announcer_tiers; +struct tr_torrent_announcer; /** *** Package-visible ctor API @@ -131,7 +131,7 @@ public: void setMetainfo(tr_torrent_metainfo const& tm); - auto unique_lock() const + [[nodiscard]] auto unique_lock() const { return session->unique_lock(); } @@ -140,7 +140,7 @@ public: void setSpeedLimitBps(tr_direction, unsigned int Bps); - unsigned int speedLimitBps(tr_direction) const; + [[nodiscard]] unsigned int speedLimitBps(tr_direction) const; /// BLOCK INFO @@ -582,7 +582,7 @@ public: tr_session* session = nullptr; - tr_announcer_tiers* announcer_tiers = nullptr; + tr_torrent_announcer* torrent_announcer = nullptr; // Changed to non-owning pointer temporarily till tr_torrent becomes C++-constructible and destructible // TODO: change tr_bandwidth* to owning pointer to the bandwidth, or remove * and own the value