refactor: use C++ objects in announcer (#2474)

This commit is contained in:
Charles Kerr 2022-01-22 23:41:01 -06:00 committed by GitHub
parent e0c3a7f3e6
commit b45c831bcb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 969 additions and 1090 deletions

View File

@ -12,6 +12,7 @@
#include <array>
#include <cstddef> // size_t
#include <string>
#include <vector>
#include "transmission.h"
@ -45,7 +46,7 @@ struct tr_scrape_request
std::array<tr_sha1_digest_t, TR_MULTISCRAPE_MAX> 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<tr_scrape_response_row, TR_MULTISCRAPE_MAX> 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<tr_pex> pex;
/* IPv6 peers that we acquired from the tracker */
struct tr_pex* pex6;
std::vector<tr_pex> 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);

View File

@ -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<char, SHA_DIGEST_LENGTH * 3 + 1>{};
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<tr_pex>(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;

View File

@ -6,6 +6,8 @@
#include <cerrno> /* errno, EAFNOSUPPORT */
#include <cstring> /* memset() */
#include <ctime>
#include <list>
#include <set>
#include <string_view>
#include <vector>
@ -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<char const*>(evbuffer_pullup(buf, -1)), buflen } :
_("Unknown error");
fail(true, false, errmsg);
}
}
std::vector<uint8_t> 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<char const*>(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<char const*>(evbuffer_pullup(buf, -1)), buflen } :
_("Unknown error");
fail(true, false, errmsg);
}
}
std::vector<uint8_t> 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<char const*>(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<tau_announce_request> announces;
std::list<tau_scrape_request> 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<struct tau_scrape_request*>(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<struct tau_announce_request*>(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<struct tau_tracker*>(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<typename T>
static void tau_tracker_send_requests(tau_tracker* tracker, std::list<T>& 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<struct tau_announce_request*>(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<struct tau_scrape_request*>(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<struct tau_announce_request*>(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<struct tau_scrape_request*>(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<tau_tracker> 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<struct tau_tracker*>(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<struct tau_tracker const*>(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<struct tau_tracker*>(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<struct tau_tracker*>(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<struct tau_announce_request*>(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<struct tau_scrape_request*>(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);
}

File diff suppressed because it is too large Load Diff

View File

@ -12,13 +12,14 @@
#include <cstddef> // size_t
#include <ctime>
#include <string_view>
#include <vector>
#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<tr_pex> 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*);

View File

@ -1201,6 +1201,27 @@ tr_pex* tr_peerMgrCompactToPex(
return pex;
}
std::vector<tr_pex> 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<std::byte const*>(compact);
auto pex = std::vector<tr_pex>(n);
for (size_t i = 0; i < n; ++i)
{
pex[i].addr.type = TR_AF_INET;
walk = std::copy_n(walk, 4, reinterpret_cast<std::byte*>(&pex[i].addr.addr));
walk = std::copy_n(walk, 2, reinterpret_cast<std::byte*>(&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_pex> 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<std::byte const*>(compact);
auto pex = std::vector<tr_pex>(n);
for (size_t i = 0; i < n; ++i)
{
pex[i].addr.type = TR_AF_INET6;
walk = std::copy_n(walk, 16, reinterpret_cast<std::byte*>(&pex[i].addr.addr.addr6.s6_addr));
walk = std::copy_n(walk, 2, reinterpret_cast<std::byte*>(&pex[i].port));
if (added_f != nullptr && n == added_f_len)
{
pex[i].flags = added_f[i];
}
}
return pex;
}
/**
***
**/

View File

@ -101,6 +101,10 @@ tr_pex* tr_peerMgrCompact6ToPex(
size_t added_f_len,
size_t* pexCount);
std::vector<tr_pex> tr_peerMgrCompactToPex(void const* compact, size_t compactLen, uint8_t const* added_f, size_t added_f_len);
std::vector<tr_pex> 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);

View File

@ -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)

View File

@ -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_;
}

View File

@ -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)
{

View File

@ -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