refactor: misc-use-anonymous-namespace pt. 4 (#4550)

This commit is contained in:
Charles Kerr 2023-01-07 12:58:16 -06:00 committed by GitHub
parent 9678b26984
commit cb10255ef1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1495 additions and 1455 deletions

View File

@ -41,16 +41,9 @@
using namespace std::literals;
/****
***** ANNOUNCE
****/
[[nodiscard]] static constexpr std::string_view get_event_string(tr_announce_request const& req)
namespace
{
return req.partial_seed && (req.event != TR_ANNOUNCE_EVENT_STOPPED) ? "paused"sv : tr_announce_event_get_string(req.event);
}
static void verboseLog(std::string_view description, tr_direction direction, std::string_view message)
void verboseLog(std::string_view description, tr_direction direction, std::string_view message)
{
auto& out = std::cerr;
static bool const verbose = tr_env_key_exists("TR_CURL_VERBOSE");
@ -76,7 +69,270 @@ static void verboseLog(std::string_view description, tr_direction direction, std
out << std::endl << "[b64]"sv << direction_sv << tr_base64_encode(message) << std::endl;
}
static auto constexpr MaxBencDepth = 8;
auto constexpr MaxBencDepth = 8;
} // namespace
/****
***** ANNOUNCE
****/
namespace
{
namespace announce_helpers
{
[[nodiscard]] constexpr std::string_view get_event_string(tr_announce_request const& req)
{
return req.partial_seed && (req.event != TR_ANNOUNCE_EVENT_STOPPED) ? "paused"sv : tr_announce_event_get_string(req.event);
}
struct http_announce_data
{
http_announce_data(tr_sha1_digest_t info_hash_in, tr_announce_response_func on_response_in, std::string_view log_name_in)
: info_hash{ info_hash_in }
, on_response{ std::move(on_response_in) }
, log_name{ log_name_in }
{
}
tr_sha1_digest_t info_hash = {};
std::optional<tr_announce_response> previous_response;
tr_announce_response_func on_response;
bool http_success = false;
uint8_t requests_sent_count = {};
uint8_t requests_answered_count = {};
std::string log_name;
};
bool handleAnnounceResponse(tr_web::FetchResponse const& web_response, tr_announce_response* const response)
{
auto const& [status, body, did_connect, did_timeout, vdata] = web_response;
auto const& log_name = static_cast<http_announce_data const*>(vdata)->log_name;
response->did_connect = did_connect;
response->did_timeout = did_timeout;
tr_logAddTrace("Got announce response", log_name);
if (status != HTTP_OK)
{
auto const* const response_str = tr_webGetResponseStr(status);
response->errmsg = fmt::format(FMT_STRING("Tracker HTTP response {:d} ({:s}"), status, response_str);
return false;
}
tr_announcerParseHttpAnnounceResponse(*response, body, log_name);
if (!std::empty(response->pex6))
{
tr_logAddTrace(fmt::format("got a peers6 length of {}", std::size(response->pex6)), log_name);
}
if (!std::empty(response->pex))
{
tr_logAddTrace(fmt::format("got a peers length of {}", std::size(response->pex)), log_name);
}
return true;
}
void onAnnounceDone(tr_web::FetchResponse const& web_response)
{
auto const& [status, body, did_connect, did_timeout, vdata] = web_response;
auto* data = static_cast<struct http_announce_data*>(vdata);
++data->requests_answered_count;
// If another request already succeeded (or we don't have a registered callback),
// skip processing this response:
if (!data->http_success && data->on_response)
{
tr_announce_response response;
response.info_hash = data->info_hash;
data->http_success = handleAnnounceResponse(web_response, &response);
if (data->http_success)
{
data->on_response(response);
}
else if (data->requests_answered_count == data->requests_sent_count)
{
auto const* response_used = &response;
// All requests have been answered, but none were successful.
// Choose the one that went further to report.
if (data->previous_response && !response.did_connect && !response.did_timeout)
{
response_used = &*data->previous_response;
}
data->on_response(*response_used);
}
else
{
// There is still one request pending that might succeed, so store
// the response for later. There is only room for 1 previous response,
// because there can be at most 2 requests.
TR_ASSERT(!data->previous_response);
data->previous_response = std::move(response);
}
}
else
{
tr_logAddTrace("Ignoring redundant announce response", data->log_name);
}
// Free data if no more responses are expected:
if (data->requests_answered_count == data->requests_sent_count)
{
delete data;
}
}
void announce_url_new(tr_urlbuf& url, tr_session const* session, tr_announce_request const& req)
{
url.clear();
auto out = std::back_inserter(url);
auto escaped_info_hash = tr_urlbuf{};
tr_urlPercentEncode(std::back_inserter(escaped_info_hash), req.info_hash);
fmt::format_to(
out,
"{url}"
"{sep}info_hash={info_hash}"
"&peer_id={peer_id}"
"&port={port}"
"&uploaded={uploaded}"
"&downloaded={downloaded}"
"&left={left}"
"&numwant={numwant}"
"&key={key}"
"&compact=1"
"&supportcrypto=1",
fmt::arg("url", req.announce_url),
fmt::arg("sep", tr_strvContains(req.announce_url.sv(), '?') ? '&' : '?'),
fmt::arg("info_hash", std::data(escaped_info_hash)),
fmt::arg("peer_id", std::string_view{ std::data(req.peer_id), std::size(req.peer_id) }),
fmt::arg("port", req.port.host()),
fmt::arg("uploaded", req.up),
fmt::arg("downloaded", req.down),
fmt::arg("left", req.leftUntilComplete),
fmt::arg("numwant", req.numwant),
fmt::arg("key", req.key));
if (session->encryptionMode() == TR_ENCRYPTION_REQUIRED)
{
fmt::format_to(out, "&requirecrypto=1");
}
if (req.corrupt != 0)
{
fmt::format_to(out, "&corrupt={}", req.corrupt);
}
if (auto const str = get_event_string(req); !std::empty(str))
{
fmt::format_to(out, "&event={}", str);
}
if (!std::empty(req.tracker_id))
{
fmt::format_to(out, "&trackerid={}", req.tracker_id);
}
}
[[nodiscard]] std::string format_ip_arg(std::string_view ip)
{
return fmt::format("&ip={:s}", ip);
}
} // namespace announce_helpers
} // namespace
void tr_tracker_http_announce(
tr_session const* session,
tr_announce_request const& request,
tr_announce_response_func on_response)
{
using namespace announce_helpers;
auto* const d = new http_announce_data{ request.info_hash, std::move(on_response), request.log_name };
/* There are two alternative techniques for announcing both IPv4 and
IPv6 addresses. Previous version of BEP-7 suggests adding "ipv4="
and "ipv6=" parameters to the announce URL, while OpenTracker and
newer version of BEP-7 requires that peers announce once per each
public address they want to use.
We should ensure that we send the announce both via IPv6 and IPv4,
and to be safe we also add the "ipv6=" and "ipv4=" parameters, if
we already have them. Our global IPv6 address is computed for the
LTEP handshake, so this comes for free. Our public IPv4 address
may have been returned from a previous announce and stored in the
session.
*/
auto url = tr_urlbuf{};
announce_url_new(url, session, request);
auto options = tr_web::FetchOptions{ url.sv(), onAnnounceDone, d };
options.timeout_secs = TR_ANNOUNCE_TIMEOUT_SEC;
options.sndbuf = 4096;
options.rcvbuf = 4096;
auto do_make_request = [&](std::string_view const& protocol_name, tr_web::FetchOptions&& opt)
{
tr_logAddTrace(fmt::format("Sending {} announce to libcurl: '{}'", protocol_name, opt.url), request.log_name);
session->fetch(std::move(opt));
};
auto const [ipv6, ipv6_is_any] = session->publicAddress(TR_AF_INET6);
/*
* Before Curl 7.77.0, if we explicitly choose the IP version we want
* to use, it is still possible that the wrong one is used. The workaround
* is expensive (disabling DNS cache), so instead we have to make do with
* a request that we don't know if will go through IPv6 or IPv4.
*/
static bool const use_curl_workaround = curl_version_info(CURLVERSION_NOW)->version_num < CURL_VERSION_BITS(7, 77, 0);
if (use_curl_workaround)
{
if (session->useAnnounceIP())
{
options.url += format_ip_arg(session->announceIP());
}
d->requests_sent_count = 1;
do_make_request(""sv, std::move(options));
}
else
{
if (session->useAnnounceIP() || ipv6_is_any)
{
if (session->useAnnounceIP())
{
options.url += format_ip_arg(session->announceIP());
}
d->requests_sent_count = 1;
do_make_request(""sv, std::move(options));
}
else
{
d->requests_sent_count = 2;
// First try to send the announce via IPv4:
auto ipv4_options = options;
ipv4_options.ip_proto = tr_web::FetchOptions::IPProtocol::V4;
do_make_request("IPv4"sv, std::move(ipv4_options));
// Then try to send via IPv6:
options.ip_proto = tr_web::FetchOptions::IPProtocol::V6;
do_make_request("IPv6"sv, std::move(options));
}
}
}
void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std::string_view benc, std::string_view log_name)
{
@ -216,263 +472,113 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std::
}
}
struct http_announce_data
// ---
namespace
{
http_announce_data(tr_sha1_digest_t info_hash_in, tr_announce_response_func on_response_in, std::string_view log_name_in)
: info_hash{ info_hash_in }
, on_response{ std::move(on_response_in) }
, log_name{ log_name_in }
namespace scrape_helpers
{
class scrape_data
{
public:
scrape_data(tr_scrape_response_func response_func, std::string_view log_name)
: response_func_{ std::move(response_func) }
, log_name_{ log_name }
{
}
tr_sha1_digest_t info_hash = {};
std::optional<tr_announce_response> previous_response;
[[nodiscard]] constexpr auto& response() noexcept
{
return response_;
}
tr_announce_response_func on_response;
bool http_success = false;
[[nodiscard]] constexpr auto const& log_name() const noexcept
{
return log_name_;
}
uint8_t requests_sent_count = {};
uint8_t requests_answered_count = {};
void invoke_callback() const
{
if (response_func_)
{
response_func_(response_);
}
}
std::string log_name;
private:
tr_scrape_response response_ = {};
tr_scrape_response_func response_func_ = {};
std::string log_name_;
};
static bool handleAnnounceResponse(tr_web::FetchResponse const& web_response, tr_announce_response* const response)
void onScrapeDone(tr_web::FetchResponse const& web_response)
{
auto const& [status, body, did_connect, did_timeout, vdata] = web_response;
auto const& log_name = static_cast<http_announce_data const*>(vdata)->log_name;
auto* const data = static_cast<scrape_data*>(vdata);
response->did_connect = did_connect;
response->did_timeout = did_timeout;
tr_logAddTrace("Got announce response", log_name);
auto& response = data->response();
response.did_connect = did_connect;
response.did_timeout = did_timeout;
auto const scrape_url_sv = response.scrape_url.sv();
tr_logAddTrace(fmt::format("Got scrape response for '{}'", scrape_url_sv), data->log_name());
if (status != HTTP_OK)
{
auto const* const response_str = tr_webGetResponseStr(status);
response->errmsg = fmt::format(FMT_STRING("Tracker HTTP response {:d} ({:s}"), status, response_str);
return false;
response.errmsg = fmt::format(FMT_STRING("Tracker HTTP response {:d} ({:s})"), status, response_str);
}
tr_announcerParseHttpAnnounceResponse(*response, body, log_name);
if (!std::empty(response->pex6))
else if (!std::empty(body))
{
tr_logAddTrace(fmt::format("got a peers6 length of {}", std::size(response->pex6)), log_name);
tr_announcerParseHttpScrapeResponse(response, body, data->log_name());
}
if (!std::empty(response->pex))
{
tr_logAddTrace(fmt::format("got a peers length of {}", std::size(response->pex)), log_name);
}
return true;
data->invoke_callback();
delete data;
}
static void onAnnounceDone(tr_web::FetchResponse const& web_response)
void scrape_url_new(tr_pathbuf& scrape_url, tr_scrape_request const& req)
{
auto const& [status, body, did_connect, did_timeout, vdata] = web_response;
auto* data = static_cast<struct http_announce_data*>(vdata);
scrape_url = req.scrape_url.sv();
char delimiter = tr_strvContains(scrape_url, '?') ? '&' : '?';
++data->requests_answered_count;
// If another request already succeeded (or we don't have a registered callback),
// skip processing this response:
if (!data->http_success && data->on_response)
for (int i = 0; i < req.info_hash_count; ++i)
{
tr_announce_response response;
response.info_hash = data->info_hash;
data->http_success = handleAnnounceResponse(web_response, &response);
if (data->http_success)
{
data->on_response(response);
}
else if (data->requests_answered_count == data->requests_sent_count)
{
auto const* response_used = &response;
// All requests have been answered, but none were successful.
// Choose the one that went further to report.
if (data->previous_response && !response.did_connect && !response.did_timeout)
{
response_used = &*data->previous_response;
}
data->on_response(*response_used);
}
else
{
// There is still one request pending that might succeed, so store
// the response for later. There is only room for 1 previous response,
// because there can be at most 2 requests.
TR_ASSERT(!data->previous_response);
data->previous_response = std::move(response);
}
}
else
{
tr_logAddTrace("Ignoring redundant announce response", data->log_name);
}
// Free data if no more responses are expected:
if (data->requests_answered_count == data->requests_sent_count)
{
delete data;
scrape_url.append(delimiter, "info_hash=");
tr_urlPercentEncode(std::back_inserter(scrape_url), req.info_hash[i]);
delimiter = '&';
}
}
} // namespace scrape_helpers
} // namespace
namespace tr_tracker_announce_helpers
void tr_tracker_http_scrape(tr_session const* session, tr_scrape_request const& request, tr_scrape_response_func on_response)
{
using namespace scrape_helpers;
void announce_url_new(tr_urlbuf& url, tr_session const* session, tr_announce_request const& req)
{
url.clear();
auto out = std::back_inserter(url);
auto* d = new scrape_data{ std::move(on_response), request.log_name };
auto escaped_info_hash = tr_urlbuf{};
tr_urlPercentEncode(std::back_inserter(escaped_info_hash), req.info_hash);
fmt::format_to(
out,
"{url}"
"{sep}info_hash={info_hash}"
"&peer_id={peer_id}"
"&port={port}"
"&uploaded={uploaded}"
"&downloaded={downloaded}"
"&left={left}"
"&numwant={numwant}"
"&key={key}"
"&compact=1"
"&supportcrypto=1",
fmt::arg("url", req.announce_url),
fmt::arg("sep", tr_strvContains(req.announce_url.sv(), '?') ? '&' : '?'),
fmt::arg("info_hash", std::data(escaped_info_hash)),
fmt::arg("peer_id", std::string_view{ std::data(req.peer_id), std::size(req.peer_id) }),
fmt::arg("port", req.port.host()),
fmt::arg("uploaded", req.up),
fmt::arg("downloaded", req.down),
fmt::arg("left", req.leftUntilComplete),
fmt::arg("numwant", req.numwant),
fmt::arg("key", req.key));
if (session->encryptionMode() == TR_ENCRYPTION_REQUIRED)
auto& response = d->response();
response.scrape_url = request.scrape_url;
response.row_count = request.info_hash_count;
for (int i = 0; i < response.row_count; ++i)
{
fmt::format_to(out, "&requirecrypto=1");
response.rows[i].info_hash = request.info_hash[i];
response.rows[i].seeders = -1;
response.rows[i].leechers = -1;
response.rows[i].downloads = -1;
}
if (req.corrupt != 0)
{
fmt::format_to(out, "&corrupt={}", req.corrupt);
}
if (auto const str = get_event_string(req); !std::empty(str))
{
fmt::format_to(out, "&event={}", str);
}
if (!std::empty(req.tracker_id))
{
fmt::format_to(out, "&trackerid={}", req.tracker_id);
}
}
[[nodiscard]] std::string format_ip_arg(std::string_view ip)
{
return fmt::format("&ip={:s}", ip);
}
} // namespace tr_tracker_announce_helpers
void tr_tracker_http_announce(
tr_session const* session,
tr_announce_request const& request,
tr_announce_response_func on_response)
{
using namespace tr_tracker_announce_helpers;
auto* const d = new http_announce_data{ request.info_hash, std::move(on_response), request.log_name };
/* There are two alternative techniques for announcing both IPv4 and
IPv6 addresses. Previous version of BEP-7 suggests adding "ipv4="
and "ipv6=" parameters to the announce URL, while OpenTracker and
newer version of BEP-7 requires that peers announce once per each
public address they want to use.
We should ensure that we send the announce both via IPv6 and IPv4,
and to be safe we also add the "ipv6=" and "ipv4=" parameters, if
we already have them. Our global IPv6 address is computed for the
LTEP handshake, so this comes for free. Our public IPv4 address
may have been returned from a previous announce and stored in the
session.
*/
auto url = tr_urlbuf{};
announce_url_new(url, session, request);
auto options = tr_web::FetchOptions{ url.sv(), onAnnounceDone, d };
options.timeout_secs = TR_ANNOUNCE_TIMEOUT_SEC;
auto scrape_url = tr_pathbuf{};
scrape_url_new(scrape_url, request);
tr_logAddTrace(fmt::format("Sending scrape to libcurl: '{}'", scrape_url), request.log_name);
auto options = tr_web::FetchOptions{ scrape_url, onScrapeDone, d };
options.timeout_secs = TR_SCRAPE_TIMEOUT_SEC;
options.sndbuf = 4096;
options.rcvbuf = 4096;
auto do_make_request = [&](std::string_view const& protocol_name, tr_web::FetchOptions&& opt)
{
tr_logAddTrace(fmt::format("Sending {} announce to libcurl: '{}'", protocol_name, opt.url), request.log_name);
session->fetch(std::move(opt));
};
auto const [ipv6, ipv6_is_any] = session->publicAddress(TR_AF_INET6);
/*
* Before Curl 7.77.0, if we explicitly choose the IP version we want
* to use, it is still possible that the wrong one is used. The workaround
* is expensive (disabling DNS cache), so instead we have to make do with
* a request that we don't know if will go through IPv6 or IPv4.
*/
static bool const use_curl_workaround = curl_version_info(CURLVERSION_NOW)->version_num < CURL_VERSION_BITS(7, 77, 0);
if (use_curl_workaround)
{
if (session->useAnnounceIP())
{
options.url += format_ip_arg(session->announceIP());
}
d->requests_sent_count = 1;
do_make_request(""sv, std::move(options));
}
else
{
if (session->useAnnounceIP() || ipv6_is_any)
{
if (session->useAnnounceIP())
{
options.url += format_ip_arg(session->announceIP());
}
d->requests_sent_count = 1;
do_make_request(""sv, std::move(options));
}
else
{
d->requests_sent_count = 2;
// First try to send the announce via IPv4:
auto ipv4_options = options;
ipv4_options.ip_proto = tr_web::FetchOptions::IPProtocol::V4;
do_make_request("IPv4"sv, std::move(ipv4_options));
// Then try to send via IPv6:
options.ip_proto = tr_web::FetchOptions::IPProtocol::V6;
do_make_request("IPv6"sv, std::move(options));
}
}
session->fetch(std::move(options));
}
/****
*****
***** SCRAPE
*****
****/
void tr_announcerParseHttpScrapeResponse(tr_scrape_response& response, std::string_view benc, std::string_view log_name)
{
verboseLog("Scrape response:", TR_DOWN, benc);
@ -576,100 +682,3 @@ void tr_announcerParseHttpScrapeResponse(tr_scrape_response& response, std::stri
tr_error_clear(&error);
}
}
class scrape_data
{
public:
scrape_data(tr_scrape_response_func response_func, std::string_view log_name)
: response_func_{ std::move(response_func) }
, log_name_{ log_name }
{
}
[[nodiscard]] constexpr auto& response() noexcept
{
return response_;
}
[[nodiscard]] constexpr auto const& log_name() const noexcept
{
return log_name_;
}
void invoke_callback() const
{
if (response_func_)
{
response_func_(response_);
}
}
private:
tr_scrape_response response_ = {};
tr_scrape_response_func response_func_ = {};
std::string log_name_;
};
static void onScrapeDone(tr_web::FetchResponse const& web_response)
{
auto const& [status, body, did_connect, did_timeout, vdata] = web_response;
auto* const data = static_cast<scrape_data*>(vdata);
auto& response = data->response();
response.did_connect = did_connect;
response.did_timeout = did_timeout;
auto const scrape_url_sv = response.scrape_url.sv();
tr_logAddTrace(fmt::format("Got scrape response for '{}'", scrape_url_sv), data->log_name());
if (status != HTTP_OK)
{
auto const* const response_str = tr_webGetResponseStr(status);
response.errmsg = fmt::format(FMT_STRING("Tracker HTTP response {:d} ({:s})"), status, response_str);
}
else if (!std::empty(body))
{
tr_announcerParseHttpScrapeResponse(response, body, data->log_name());
}
data->invoke_callback();
delete data;
}
static void scrape_url_new(tr_pathbuf& scrape_url, tr_scrape_request const& req)
{
scrape_url = req.scrape_url.sv();
char delimiter = tr_strvContains(scrape_url, '?') ? '&' : '?';
for (int i = 0; i < req.info_hash_count; ++i)
{
scrape_url.append(delimiter, "info_hash=");
tr_urlPercentEncode(std::back_inserter(scrape_url), req.info_hash[i]);
delimiter = '&';
}
}
void tr_tracker_http_scrape(tr_session const* session, tr_scrape_request const& request, tr_scrape_response_func on_response)
{
auto* d = new scrape_data{ std::move(on_response), request.log_name };
auto& response = d->response();
response.scrape_url = request.scrape_url;
response.row_count = request.info_hash_count;
for (int i = 0; i < response.row_count; ++i)
{
response.rows[i].info_hash = request.info_hash[i];
response.rows[i].seeders = -1;
response.rows[i].leechers = -1;
response.rows[i].downloads = -1;
}
auto scrape_url = tr_pathbuf{};
scrape_url_new(scrape_url, request);
tr_logAddTrace(fmt::format("Sending scrape to libcurl: '{}'", scrape_url), request.log_name);
auto options = tr_web::FetchOptions{ scrape_url, onScrapeDone, d };
options.timeout_secs = TR_SCRAPE_TIMEOUT_SEC;
options.sndbuf = 4096;
options.rcvbuf = 4096;
session->fetch(std::move(options));
}

View File

@ -43,23 +43,20 @@ using namespace std::literals;
#define tr_logAddDebugTier(tier, msg) tr_logAddDebug(msg, (tier)->buildLogName())
#define tr_logAddTraceTier(tier, msg) tr_logAddTrace(msg, (tier)->buildLogName())
/* unless the tracker says otherwise, rescrape this frequently */
static auto constexpr DefaultScrapeIntervalSec = int{ 60 * 30 };
/* the value of the 'numwant' argument passed in tracker requests. */
static auto constexpr Numwant = int{ 80 };
/* how often to announce & scrape */
static auto constexpr MaxAnnouncesPerUpkeep = int{ 20 };
static auto constexpr MaxScrapesPerUpkeep = int{ 20 };
/* how many infohashes to remove when we get a scrape-too-long error */
static auto constexpr TrMultiscrapeStep = int{ 5 };
// ---
namespace
{
/* unless the tracker says otherwise, rescrape this frequently */
auto constexpr DefaultScrapeIntervalSec = int{ 60 * 30 };
/* the value of the 'numwant' argument passed in tracker requests. */
auto constexpr Numwant = int{ 80 };
/* how often to announce & scrape */
auto constexpr MaxAnnouncesPerUpkeep = int{ 20 };
auto constexpr MaxScrapesPerUpkeep = int{ 20 };
/* how many infohashes to remove when we get a scrape-too-long error */
auto constexpr TrMultiscrapeStep = int{ 5 };
struct StopsCompare
{
@ -643,22 +640,6 @@ private:
}
};
static tr_tier* getTier(tr_announcer_impl* announcer, tr_sha1_digest_t const& info_hash, int tier_id)
{
if (announcer == nullptr)
{
return nullptr;
}
auto* const tor = announcer->session->torrents().get(info_hash);
if (tor == nullptr || tor->torrent_announcer == nullptr)
{
return nullptr;
}
return tor->torrent_announcer->getTier(tier_id);
}
// --- PUBLISH
namespace
@ -773,7 +754,11 @@ time_t tr_announcerNextManualAnnounce(tr_torrent const* tor)
return ret;
}
static void tr_logAddTrace_tier_announce_queue(tr_tier const* tier)
namespace
{
namespace announce_helpers
{
void tr_logAddTrace_tier_announce_queue(tr_tier const* tier)
{
if (!tr_logLevelIsActive(TR_LOG_TRACE) || std::empty(tier->announce_events))
{
@ -792,7 +777,7 @@ static void tr_logAddTrace_tier_announce_queue(tr_tier const* tier)
}
// higher priorities go to the front of the announce queue
static void tier_update_announce_priority(tr_tier* tier)
void tier_update_announce_priority(tr_tier* tier)
{
int priority = -1;
@ -804,7 +789,7 @@ static void tier_update_announce_priority(tr_tier* tier)
tier->announce_event_priority = priority;
}
static void tier_announce_remove_trailing(tr_tier* tier, tr_announce_event e)
void tier_announce_remove_trailing(tr_tier* tier, tr_announce_event e)
{
while (!std::empty(tier->announce_events) && tier->announce_events.back() == e)
{
@ -814,7 +799,7 @@ static void tier_announce_remove_trailing(tr_tier* tier, tr_announce_event e)
tier_update_announce_priority(tier);
}
static void tier_announce_event_push(tr_tier* tier, tr_announce_event e, time_t announce_at)
void tier_announce_event_push(tr_tier* tier, tr_announce_event e, time_t announce_at)
{
TR_ASSERT(tier != nullptr);
@ -852,7 +837,7 @@ static void tier_announce_event_push(tr_tier* tier, tr_announce_event e, time_t
tr_logAddTraceTier(tier, fmt::format("announcing in {} seconds", difftime(announce_at, tr_time())));
}
static auto tier_announce_event_pull(tr_tier* tier)
auto tier_announce_event_pull(tr_tier* tier)
{
auto const e = tier->announce_events.front();
tier->announce_events.pop_front();
@ -860,104 +845,7 @@ static auto tier_announce_event_pull(tr_tier* tier)
return e;
}
static void torrentAddAnnounce(tr_torrent* tor, tr_announce_event e, time_t announce_at)
{
// tell each tier to announce
for (auto& tier : tor->torrent_announcer->tiers)
{
tier_announce_event_push(&tier, e, announce_at);
}
}
void tr_announcer_impl::startTorrent(tr_torrent* tor)
{
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_STARTED, tr_time());
}
void tr_announcerManualAnnounce(tr_torrent* tor)
{
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_NONE, tr_time());
}
void tr_announcer_impl::stopTorrent(tr_torrent* tor)
{
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_STOPPED, tr_time());
}
void tr_announcerTorrentCompleted(tr_torrent* tor)
{
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_COMPLETED, tr_time());
}
void tr_announcerChangeMyPort(tr_torrent* tor)
{
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_STARTED, tr_time());
}
// ---
void tr_announcerAddBytes(tr_torrent* tor, int type, uint32_t n_bytes)
{
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(type == TR_ANN_UP || type == TR_ANN_DOWN || type == TR_ANN_CORRUPT);
for (auto& tier : tor->torrent_announcer->tiers)
{
tier.byteCounts[type] += n_bytes;
}
}
// ---
[[nodiscard]] static tr_announce_request create_announce_request(
tr_announcer_impl const* const announcer,
tr_torrent* const tor,
tr_tier const* const tier,
tr_announce_event const event)
{
auto const* const current_tracker = tier->currentTracker();
TR_ASSERT(current_tracker != nullptr);
auto req = tr_announce_request{};
req.port = announcer->session->advertisedPeerPort();
req.announce_url = current_tracker->announce_url;
req.tracker_id = current_tracker->tracker_id;
req.info_hash = tor->infoHash();
req.peer_id = tr_torrentGetPeerId(tor);
req.up = tier->byteCounts[TR_ANN_UP];
req.down = tier->byteCounts[TR_ANN_DOWN];
req.corrupt = tier->byteCounts[TR_ANN_CORRUPT];
req.leftUntilComplete = tor->hasMetainfo() ? tor->totalSize() - tor->hasTotal() : INT64_MAX;
req.event = event;
req.numwant = event == TR_ANNOUNCE_EVENT_STOPPED ? 0 : Numwant;
req.key = tor->announce_key();
req.partial_seed = tor->isPartialSeed();
tier->buildLogName(req.log_name, sizeof(req.log_name));
return req;
}
void tr_announcer_impl::removeTorrent(tr_torrent* tor)
{
// FIXME(ckerr)
auto* const ta = tor->torrent_announcer;
if (ta == nullptr)
{
return;
}
for (auto const& tier : ta->tiers)
{
if (tier.isRunning && tier.lastAnnounceSucceeded)
{
stops_.emplace(create_announce_request(this, tor, &tier, TR_ANNOUNCE_EVENT_STOPPED));
}
}
tor->torrent_announcer = nullptr;
delete ta;
}
static bool isUnregistered(char const* errmsg)
bool isUnregistered(char const* errmsg)
{
auto const lower = tr_strlower(errmsg != nullptr ? errmsg : "");
@ -966,8 +854,10 @@ static bool isUnregistered(char const* errmsg)
return std::any_of(std::begin(Keys), std::end(Keys), [&lower](auto const& key) { return tr_strvContains(lower, key); });
}
static void on_announce_error(tr_tier* tier, char const* err, tr_announce_event e)
void on_announce_error(tr_tier* tier, char const* err, tr_announce_event e)
{
using namespace announce_helpers;
/* increment the error count */
auto* current_tracker = tier->currentTracker();
if (current_tracker != nullptr)
@ -1002,12 +892,69 @@ static void on_announce_error(tr_tier* tier, char const* err, tr_announce_event
}
}
[[nodiscard]] tr_announce_request create_announce_request(
tr_announcer_impl const* const announcer,
tr_torrent* const tor,
tr_tier const* const tier,
tr_announce_event const event)
{
auto const* const current_tracker = tier->currentTracker();
TR_ASSERT(current_tracker != nullptr);
auto req = tr_announce_request{};
req.port = announcer->session->advertisedPeerPort();
req.announce_url = current_tracker->announce_url;
req.tracker_id = current_tracker->tracker_id;
req.info_hash = tor->infoHash();
req.peer_id = tr_torrentGetPeerId(tor);
req.up = tier->byteCounts[TR_ANN_UP];
req.down = tier->byteCounts[TR_ANN_DOWN];
req.corrupt = tier->byteCounts[TR_ANN_CORRUPT];
req.leftUntilComplete = tor->hasMetainfo() ? tor->totalSize() - tor->hasTotal() : INT64_MAX;
req.event = event;
req.numwant = event == TR_ANNOUNCE_EVENT_STOPPED ? 0 : Numwant;
req.key = tor->announce_key();
req.partial_seed = tor->isPartialSeed();
tier->buildLogName(req.log_name, sizeof(req.log_name));
return req;
}
[[nodiscard]] tr_tier* getTier(tr_announcer_impl* announcer, tr_sha1_digest_t const& info_hash, int tier_id)
{
if (announcer == nullptr)
{
return nullptr;
}
auto* const tor = announcer->session->torrents().get(info_hash);
if (tor == nullptr || tor->torrent_announcer == nullptr)
{
return nullptr;
}
return tor->torrent_announcer->getTier(tier_id);
}
} // namespace announce_helpers
void torrentAddAnnounce(tr_torrent* tor, tr_announce_event e, time_t announce_at)
{
using namespace announce_helpers;
// tell each tier to announce
for (auto& tier : tor->torrent_announcer->tiers)
{
tier_announce_event_push(&tier, e, announce_at);
}
}
} // namespace
void tr_announcer_impl::onAnnounceDone(
int tier_id,
tr_announce_event event,
bool is_running_on_success,
tr_announce_response const& response)
{
using namespace announce_helpers;
using namespace publish_helpers;
auto* const tier = getTier(this, response.info_hash, tier_id);
@ -1193,54 +1140,92 @@ void tr_announcer_impl::onAnnounceDone(
}
}
static void tierAnnounce(tr_announcer_impl* announcer, tr_tier* tier)
void tr_announcer_impl::startTorrent(tr_torrent* tor)
{
TR_ASSERT(!tier->isAnnouncing);
TR_ASSERT(!std::empty(tier->announce_events));
TR_ASSERT(tier->currentTracker() != nullptr);
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_STARTED, tr_time());
}
auto const now = tr_time();
void tr_announcerManualAnnounce(tr_torrent* tor)
{
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_NONE, tr_time());
}
tr_torrent* tor = tier->tor;
auto const event = tier_announce_event_pull(tier);
auto const req = create_announce_request(announcer, tor, tier, event);
void tr_announcer_impl::stopTorrent(tr_torrent* tor)
{
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_STOPPED, tr_time());
}
tier->isAnnouncing = true;
tier->lastAnnounceStartTime = now;
void tr_announcerTorrentCompleted(tr_torrent* tor)
{
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_COMPLETED, tr_time());
}
auto tier_id = tier->id;
auto is_running_on_success = tor->isRunning;
void tr_announcerChangeMyPort(tr_torrent* tor)
{
torrentAddAnnounce(tor, TR_ANNOUNCE_EVENT_STARTED, tr_time());
}
announcer->announce(
req,
[session = announcer->session, announcer, tier_id, event, is_running_on_success](tr_announce_response const& response)
// ---
void tr_announcerAddBytes(tr_torrent* tor, int type, uint32_t n_bytes)
{
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(type == TR_ANN_UP || type == TR_ANN_DOWN || type == TR_ANN_CORRUPT);
for (auto& tier : tor->torrent_announcer->tiers)
{
tier.byteCounts[type] += n_bytes;
}
}
// ---
void tr_announcer_impl::removeTorrent(tr_torrent* tor)
{
using namespace announce_helpers;
// FIXME(ckerr)
auto* const ta = tor->torrent_announcer;
if (ta == nullptr)
{
return;
}
for (auto const& tier : ta->tiers)
{
if (tier.isRunning && tier.lastAnnounceSucceeded)
{
if (session->announcer_)
{
announcer->onAnnounceDone(tier_id, event, is_running_on_success, response);
}
});
stops_.emplace(create_announce_request(this, tor, &tier, TR_ANNOUNCE_EVENT_STOPPED));
}
}
tor->torrent_announcer = nullptr;
delete ta;
}
// --- SCRAPE
static bool multiscrape_too_big(std::string_view errmsg)
namespace
{
namespace on_scrape_done_helpers
{
[[nodiscard]] TR_CONSTEXPR20 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 */
auto constexpr TooLongErrors = std::array<std::string_view, 3>{
auto too_long_errors = std::array<std::string_view, 3>{
"Bad Request",
"GET string too long",
"Request-URI Too Long",
};
return std::any_of(
std::begin(TooLongErrors),
std::end(TooLongErrors),
std::begin(too_long_errors),
std::end(too_long_errors),
[&errmsg](auto const& substr) { return tr_strvContains(errmsg, substr); });
}
static void on_scrape_error(tr_session const* /*session*/, tr_tier* tier, char const* errmsg)
void on_scrape_error(tr_session const* /*session*/, tr_tier* tier, char const* errmsg)
{
// increment the error count
auto* current_tracker = tier->currentTracker();
@ -1265,7 +1250,7 @@ static void on_scrape_error(tr_session const* /*session*/, tr_tier* tier, char c
tier->scheduleNextScrape(interval);
}
static void checkMultiscrapeMax(tr_announcer_impl* announcer, tr_scrape_response const& response)
void checkMultiscrapeMax(tr_announcer_impl* announcer, tr_scrape_response const& response)
{
if (!multiscrape_too_big(response.errmsg))
{
@ -1303,9 +1288,12 @@ static void checkMultiscrapeMax(tr_announcer_impl* announcer, tr_scrape_response
multiscrape_max = n;
}
}
} // namespace on_scrape_done_helpers
} // namespace
void tr_announcer_impl::onScrapeDone(tr_scrape_response const& response)
{
using namespace on_scrape_done_helpers;
using namespace publish_helpers;
auto const now = tr_time();
@ -1404,7 +1392,9 @@ void tr_announcer_impl::onScrapeDone(tr_scrape_response const& response)
checkMultiscrapeMax(this, response);
}
static void multiscrape(tr_announcer_impl* announcer, std::vector<tr_tier*> const& tiers)
namespace
{
void multiscrape(tr_announcer_impl* announcer, std::vector<tr_tier*> const& tiers)
{
auto const now = tr_time();
auto requests = std::array<tr_scrape_request, MaxScrapesPerUpkeep>{};
@ -1471,7 +1461,9 @@ static void multiscrape(tr_announcer_impl* announcer, std::vector<tr_tier*> cons
}
}
static int compareAnnounceTiers(tr_tier const* a, tr_tier const* b)
namespace upkeep_helpers
{
int compareAnnounceTiers(tr_tier const* a, tr_tier const* b)
{
/* prefer higher-priority events */
if (auto const priority_a = a->announce_event_priority, priority_b = b->announce_event_priority; priority_a != priority_b)
@ -1510,9 +1502,40 @@ static int compareAnnounceTiers(tr_tier const* a, tr_tier const* b)
return a < b ? -1 : 1;
}
static void scrapeAndAnnounceMore(tr_announcer_impl* announcer)
void tierAnnounce(tr_announcer_impl* announcer, tr_tier* tier)
{
time_t const now = tr_time();
using namespace announce_helpers;
TR_ASSERT(!tier->isAnnouncing);
TR_ASSERT(!std::empty(tier->announce_events));
TR_ASSERT(tier->currentTracker() != nullptr);
auto const now = tr_time();
tr_torrent* tor = tier->tor;
auto const event = tier_announce_event_pull(tier);
auto const req = create_announce_request(announcer, tor, tier, event);
tier->isAnnouncing = true;
tier->lastAnnounceStartTime = now;
auto tier_id = tier->id;
auto is_running_on_success = tor->isRunning;
announcer->announce(
req,
[session = announcer->session, announcer, tier_id, event, is_running_on_success](tr_announce_response const& response)
{
if (session->announcer_)
{
announcer->onAnnounceDone(tier_id, event, is_running_on_success, response);
}
});
}
void scrapeAndAnnounceMore(tr_announcer_impl* announcer)
{
auto const now = tr_time();
/* build a list of tiers that need to be announced */
auto announce_me = std::vector<tr_tier*>{};
@ -1557,9 +1580,13 @@ static void scrapeAndAnnounceMore(tr_announcer_impl* announcer)
tierAnnounce(announcer, tier);
}
}
} // namespace upkeep_helpers
} // namespace
void tr_announcer_impl::upkeep()
{
using namespace upkeep_helpers;
auto const lock = session->unique_lock();
// maybe send out some "stopped" messages for closed torrents
@ -1576,7 +1603,11 @@ void tr_announcer_impl::upkeep()
// ---
static tr_tracker_view trackerView(tr_torrent const& tor, size_t tier_index, tr_tier const& tier, tr_tracker const& tracker)
namespace
{
namespace tracker_view_helpers
{
[[nodiscard]] auto trackerView(tr_torrent const& tor, size_t tier_index, tr_tier const& tier, tr_tracker const& tracker)
{
auto const now = tr_time();
auto view = tr_tracker_view{};
@ -1666,6 +1697,8 @@ static tr_tracker_view trackerView(tr_torrent const& tor, size_t tier_index, tr_
return view;
}
} // namespace tracker_view_helpers
} // namespace
size_t tr_announcerTrackerCount(tr_torrent const* tor)
{
@ -1682,6 +1715,8 @@ size_t tr_announcerTrackerCount(tr_torrent const* tor)
tr_tracker_view tr_announcerTracker(tr_torrent const* tor, size_t nth)
{
using namespace tracker_view_helpers;
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(tor->torrent_announcer != nullptr);
@ -1709,6 +1744,8 @@ tr_tracker_view tr_announcerTracker(tr_torrent const* tor, size_t nth)
// so announcer needs to update the tr_tier / tr_trackers to match
void tr_announcer_impl::resetTorrent(tr_torrent* tor)
{
using namespace announce_helpers;
// make a new tr_announcer_tier
auto* const older = tor->torrent_announcer;
tor->torrent_announcer = new tr_torrent_announcer{ this, tor };

View File

@ -27,11 +27,9 @@
#include "tr-assert.h"
#include "utils.h"
/***
****
***/
static void log_openssl_error(char const* file, int line)
namespace
{
void log_openssl_error(char const* file, int line)
{
unsigned long const error_code = ERR_get_error();
@ -64,7 +62,7 @@ static void log_openssl_error(char const* file, int line)
#define log_error() log_openssl_error(__FILE__, __LINE__)
static bool check_openssl_result(int result, int expected_result, bool expected_equal, char const* file, int line)
bool check_openssl_result(int result, int expected_result, bool expected_equal, char const* file, int line)
{
bool const ret = (result == expected_result) == expected_equal;
@ -77,13 +75,8 @@ static bool check_openssl_result(int result, int expected_result, bool expected_
}
#define check_result(result) check_openssl_result((result), 1, true, __FILE__, __LINE__)
#define check_result_neq(result, x_result) check_openssl_result((result), (x_result), false, __FILE__, __LINE__)
/***
****
***/
namespace
namespace sha_helpers
{
class ShaHelper
@ -196,55 +189,26 @@ private:
ShaHelper helper_{ EVP_sha256 };
};
} // namespace sha_helpers
} // namespace
// --- sha
std::unique_ptr<tr_sha1> tr_sha1::create()
{
using namespace sha_helpers;
return std::make_unique<Sha1Impl>();
}
std::unique_ptr<tr_sha256> tr_sha256::create()
{
using namespace sha_helpers;
return std::make_unique<Sha256Impl>();
}
/***
****
***/
#if OPENSSL_VERSION_NUMBER < 0x0090802fL
static EVP_CIPHER_CTX* openssl_evp_cipher_context_new()
{
auto* const handle = new EVP_CIPHER_CTX{};
if (handle != nullptr)
{
EVP_CIPHER_CTX_init(handle);
}
return handle;
}
static void openssl_evp_cipher_context_free(EVP_CIPHER_CTX* handle)
{
if (handle == nullptr)
{
return;
}
EVP_CIPHER_CTX_cleanup(handle);
delete handle;
}
#define EVP_CIPHER_CTX_new() openssl_evp_cipher_context_new()
#define EVP_CIPHER_CTX_free(x) openssl_evp_cipher_context_free((x))
#endif
/***
****
***/
// --- x509
tr_x509_store_t tr_ssl_get_x509_store(tr_ssl_ctx_t handle)
{
@ -288,9 +252,7 @@ void tr_x509_cert_free(tr_x509_cert_t handle)
X509_free(static_cast<X509*>(handle));
}
/***
****
***/
// --- rand
bool tr_rand_buffer_crypto(void* buffer, size_t length)
{

View File

@ -15,7 +15,9 @@
#include "tr-macros.h"
#include "utils.h"
static char* tr_strvDup(std::string_view in)
namespace
{
[[nodiscard]] char* tr_strvdup(std::string_view in)
{
auto const n = std::size(in);
auto* const ret = new char[n + 1];
@ -23,6 +25,7 @@ static char* tr_strvDup(std::string_view in)
ret[n] = '\0';
return ret;
}
} // namespace
void tr_error_free(tr_error* error)
{
@ -43,7 +46,7 @@ void tr_error_set(tr_error** error, int code, std::string_view message)
}
TR_ASSERT(*error == nullptr);
*error = new tr_error{ code, tr_strvDup(message) };
*error = new tr_error{ code, tr_strvdup(message) };
}
void tr_error_propagate(tr_error** new_error, tr_error** old_error)
@ -86,7 +89,7 @@ void tr_error_prefix(tr_error** error, char const* prefix)
}
auto* err = *error;
auto* const new_message = tr_strvDup(fmt::format(FMT_STRING("{:s}{:s}"), prefix, err->message));
auto* const new_message = tr_strvdup(fmt::format(FMT_STRING("{:s}{:s}"), prefix, err->message));
delete[] err->message;
err->message = new_message;
}

1
libtransmission/makelog Normal file
View File

@ -0,0 +1 @@
ninja: error: loading 'build.ninja': No such file or directory

View File

@ -467,6 +467,16 @@ public:
pool_is_all_seeds_.reset();
}
[[nodiscard]] peer_atom* get_existing_atom(tr_address const& addr)
{
auto const test = [&addr](auto const& atom)
{
return atom.addr == addr;
};
auto const it = std::find_if(std::begin(pool), std::end(pool), test);
return it != std::end(pool) ? &*it : nullptr;
}
Handshakes outgoing_handshakes;
uint16_t interested_count = 0;
@ -559,6 +569,12 @@ struct tr_peerMgr
void refillUpkeep() const;
void makeNewPeerConnections(size_t max);
[[nodiscard]] tr_swarm* get_existing_swarm(tr_sha1_digest_t const& hash) const
{
auto* const tor = session->torrents().get(hash);
return tor == nullptr ? nullptr : tor->swarm;
}
tr_session* const session;
Handshakes incoming_handshakes;
@ -623,24 +639,6 @@ tr_peer::~tr_peer()
***
**/
static tr_swarm* getExistingSwarm(tr_peerMgr* manager, tr_sha1_digest_t const& hash)
{
auto* const tor = manager->session->torrents().get(hash);
return tor == nullptr ? nullptr : tor->swarm;
}
static struct peer_atom* getExistingAtom(tr_swarm const* cswarm, tr_address const& addr)
{
auto* swarm = const_cast<tr_swarm*>(cswarm);
auto const test = [&addr](auto const& atom)
{
return atom.addr == addr;
};
auto const it = std::find_if(std::begin(swarm->pool), std::end(swarm->pool), test);
return it != std::end(swarm->pool) ? &*it : nullptr;
}
static bool peerIsInUse(tr_swarm const* swarm, struct peer_atom const* atom)
{
return atom->is_connected || swarm->outgoing_handshakes.count(atom->addr) != 0U ||
@ -701,7 +699,7 @@ static void atomSetSeed(tr_swarm* swarm, peer_atom& atom)
static bool tr_peerMgrPeerIsSeed(tr_torrent const* tor, tr_address const& addr)
{
if (auto const* atom = getExistingAtom(tor->swarm, addr); atom != nullptr)
if (auto const* atom = tor->swarm->get_existing_atom(addr); atom != nullptr)
{
return atom->isSeed();
}
@ -711,7 +709,7 @@ static bool tr_peerMgrPeerIsSeed(tr_torrent const* tor, tr_address const& addr)
void tr_peerMgrSetUtpSupported(tr_torrent* tor, tr_address const& addr)
{
if (auto* const atom = getExistingAtom(tor->swarm, addr); atom != nullptr)
if (auto* const atom = tor->swarm->get_existing_atom(addr); atom != nullptr)
{
atom->flags |= ADDED_F_UTP_FLAGS;
}
@ -719,7 +717,7 @@ void tr_peerMgrSetUtpSupported(tr_torrent* tor, tr_address const& addr)
void tr_peerMgrSetUtpFailed(tr_torrent* tor, tr_address const& addr, bool failed)
{
if (auto* const atom = getExistingAtom(tor->swarm, addr); atom != nullptr)
if (auto* const atom = tor->swarm->get_existing_atom(addr); atom != nullptr)
{
atom->utp_failed = failed;
}
@ -1046,7 +1044,7 @@ static struct peer_atom* ensureAtomExists(
TR_ASSERT(addr.is_valid());
TR_ASSERT(from < TR_PEER_FROM__MAX);
struct peer_atom* a = getExistingAtom(s, addr);
struct peer_atom* a = s->get_existing_atom(addr);
if (a == nullptr)
{
@ -1097,7 +1095,7 @@ static bool on_handshake_done(tr_peerMgr* manager, tr_handshake::Result const& r
bool const ok = result.is_connected;
bool success = false;
tr_swarm* const s = getExistingSwarm(manager, result.io->torrent_hash());
auto* const s = manager->get_existing_swarm(result.io->torrent_hash());
auto const [addr, port] = result.io->socket_address();
@ -1116,7 +1114,7 @@ static bool on_handshake_done(tr_peerMgr* manager, tr_handshake::Result const& r
{
if (s != nullptr)
{
struct peer_atom* atom = getExistingAtom(s, addr);
struct peer_atom* atom = s->get_existing_atom(addr);
if (atom != nullptr)
{

View File

@ -67,13 +67,11 @@
#include "utils.h"
#include "platform-quota.h"
/***
****
***/
namespace
{
#ifndef _WIN32
static char const* getdev(std::string_view path)
[[nodiscard]] char const* getdev(std::string_view path)
{
#ifdef HAVE_GETMNTENT
@ -141,7 +139,7 @@ static char const* getdev(std::string_view path)
#endif
}
static char const* getfstype(std::string_view device)
[[nodiscard]] char const* getfstype(std::string_view device)
{
#ifdef HAVE_GETMNTENT
@ -209,7 +207,7 @@ static char const* getfstype(std::string_view device)
#endif
}
static std::string getblkdev(std::string_view path)
std::string getblkdev(std::string_view path)
{
for (;;)
{
@ -235,7 +233,7 @@ extern "C"
#include <quota.h>
}
struct tr_disk_space getquota(char const* device)
[[nodiscard]] tr_disk_space getquota(char const* device)
{
struct quotahandle* qh;
struct quotakey qk;
@ -285,7 +283,7 @@ struct tr_disk_space getquota(char const* device)
#else
static struct tr_disk_space getquota(char const* device)
[[nodiscard]] tr_disk_space getquota(char const* device)
{
#if defined(__DragonFly__)
struct ufs_dqblk dq = {};
@ -371,7 +369,7 @@ static struct tr_disk_space getquota(char const* device)
#ifdef HAVE_XQM
static struct tr_disk_space getxfsquota(char const* device)
[[nodiscard]] tr_disk_space getxfsquota(char const* device)
{
struct tr_disk_space disk_space = { -1, -1 };
struct fs_disk_quota dq;
@ -410,7 +408,7 @@ static struct tr_disk_space getxfsquota(char const* device)
#endif /* _WIN32 */
static tr_disk_space getQuotaSpace([[maybe_unused]] tr_device_info const& info)
[[nodiscard]] tr_disk_space getQuotaSpace([[maybe_unused]] tr_device_info const& info)
{
struct tr_disk_space ret = { -1, -1 };
@ -432,7 +430,7 @@ static tr_disk_space getQuotaSpace([[maybe_unused]] tr_device_info const& info)
return ret;
}
static struct tr_disk_space getDiskSpace(char const* path)
[[nodiscard]] tr_disk_space getDiskSpace(char const* path)
{
#ifdef _WIN32
@ -468,6 +466,8 @@ static struct tr_disk_space getDiskSpace(char const* path)
#endif
}
} // namespace
tr_device_info tr_device_info_create(std::string_view path)
{
auto out = tr_device_info{};

View File

@ -45,13 +45,10 @@
using namespace std::literals;
/***
**** PATHS
***/
namespace
{
#ifdef _WIN32
static std::string win32_get_known_folder_ex(REFKNOWNFOLDERID folder_id, DWORD flags)
std::string win32_get_known_folder_ex(REFKNOWNFOLDERID folder_id, DWORD flags)
{
if (PWSTR path; SHGetKnownFolderPath(folder_id, flags | KF_FLAG_DONT_UNEXPAND, nullptr, &path) == S_OK)
{
@ -63,14 +60,13 @@ static std::string win32_get_known_folder_ex(REFKNOWNFOLDERID folder_id, DWORD f
return {};
}
static auto win32_get_known_folder(REFKNOWNFOLDERID folder_id)
auto win32_get_known_folder(REFKNOWNFOLDERID folder_id)
{
return win32_get_known_folder_ex(folder_id, KF_FLAG_DONT_VERIFY);
}
#endif
static std::string getHomeDir()
std::string getHomeDir()
{
if (auto dir = tr_env_get_string("HOME"sv); !std::empty(dir))
{
@ -100,7 +96,7 @@ static std::string getHomeDir()
return {};
}
static std::string xdgConfigHome()
std::string xdgConfigHome()
{
if (auto dir = tr_env_get_string("XDG_CONFIG_HOME"sv); !std::empty(dir))
{
@ -110,6 +106,51 @@ static std::string xdgConfigHome()
return fmt::format("{:s}/.config"sv, getHomeDir());
}
std::string getXdgEntryFromUserDirs(std::string_view key)
{
auto content = std::vector<char>{};
if (auto const filename = fmt::format("{:s}/{:s}"sv, xdgConfigHome(), "user-dirs.dirs"sv);
!tr_sys_path_exists(filename) || !tr_loadFile(filename, content) || std::empty(content))
{
return {};
}
// search for key="val" and extract val
auto const search = fmt::format(FMT_STRING("{:s}=\""), key);
auto begin = std::search(std::begin(content), std::end(content), std::begin(search), std::end(search));
if (begin == std::end(content))
{
return {};
}
std::advance(begin, std::size(search));
auto const end = std::find(begin, std::end(content), '"');
if (end == std::end(content))
{
return {};
}
auto val = std::string{ begin, end };
// if val contains "$HOME", replace that with getHomeDir()
auto constexpr Home = "$HOME"sv;
if (auto const it = std::search(std::begin(val), std::end(val), std::begin(Home), std::end(Home)); it != std::end(val))
{
val.replace(it, it + std::size(Home), getHomeDir());
}
return val;
}
[[nodiscard]] bool isWebClientDir(std::string_view path)
{
auto const filename = tr_pathbuf{ path, '/', "index.html"sv };
bool const found = tr_sys_path_exists(filename);
tr_logAddTrace(fmt::format(FMT_STRING("Searching for web interface file '{:s}'"), filename));
return found;
}
} // namespace
// ---
std::string tr_getDefaultConfigDir(std::string_view appname)
{
if (std::empty(appname))
@ -149,40 +190,6 @@ size_t tr_getDefaultConfigDirToBuf(char const* appname, char* buf, size_t buflen
return tr_strvToBuf(tr_getDefaultConfigDir(appname != nullptr ? appname : ""), buf, buflen);
}
static std::string getXdgEntryFromUserDirs(std::string_view key)
{
auto content = std::vector<char>{};
if (auto const filename = fmt::format("{:s}/{:s}"sv, xdgConfigHome(), "user-dirs.dirs"sv);
!tr_sys_path_exists(filename) || !tr_loadFile(filename, content) || std::empty(content))
{
return {};
}
// search for key="val" and extract val
auto const search = fmt::format(FMT_STRING("{:s}=\""), key);
auto begin = std::search(std::begin(content), std::end(content), std::begin(search), std::end(search));
if (begin == std::end(content))
{
return {};
}
std::advance(begin, std::size(search));
auto const end = std::find(begin, std::end(content), '"');
if (end == std::end(content))
{
return {};
}
auto val = std::string{ begin, end };
// if val contains "$HOME", replace that with getHomeDir()
auto constexpr Home = "$HOME"sv;
if (auto const it = std::search(std::begin(val), std::end(val), std::begin(Home), std::end(Home)); it != std::end(val))
{
val.replace(it, it + std::size(Home), getHomeDir());
}
return val;
}
std::string tr_getDefaultDownloadDir()
{
if (auto dir = getXdgEntryFromUserDirs("XDG_DOWNLOAD_DIR"sv); !std::empty(dir))
@ -209,17 +216,7 @@ size_t tr_getDefaultDownloadDirToBuf(char* buf, size_t buflen)
return tr_strvToBuf(tr_getDefaultDownloadDir(), buf, buflen);
}
/***
****
***/
static bool isWebClientDir(std::string_view path)
{
auto const filename = tr_pathbuf{ path, '/', "index.html"sv };
bool const found = tr_sys_path_exists(filename);
tr_logAddTrace(fmt::format(FMT_STRING("Searching for web interface file '{:s}'"), filename));
return found;
}
// ---
std::string tr_getWebClientDir([[maybe_unused]] tr_session const* session)
{

View File

@ -35,7 +35,6 @@
namespace
{
enum class UpnpState
{
Idle,
@ -45,29 +44,6 @@ enum class UpnpState
WillMap, // next action is UPNP_AddPortMapping()
WillUnmap // next action is UPNP_DeletePortMapping()
};
constexpr auto portFwdState(UpnpState upnp_state, bool is_mapped)
{
switch (upnp_state)
{
case UpnpState::WillDiscover:
case UpnpState::Discovering:
return TR_PORT_UNMAPPED;
case UpnpState::WillMap:
return TR_PORT_MAPPING;
case UpnpState::WillUnmap:
return TR_PORT_UNMAPPING;
case UpnpState::Idle:
return is_mapped ? TR_PORT_MAPPED : TR_PORT_UNMAPPED;
default: // UpnpState::FAILED:
return TR_PORT_ERROR;
}
}
} // namespace
struct tr_upnp
@ -102,25 +78,31 @@ struct tr_upnp
std::optional<std::future<UPNPDev*>> discover_future;
};
/**
***
**/
tr_upnp* tr_upnpInit()
namespace
{
return new tr_upnp();
constexpr auto port_fwd_state(UpnpState upnp_state, bool is_mapped)
{
switch (upnp_state)
{
case UpnpState::WillDiscover:
case UpnpState::Discovering:
return TR_PORT_UNMAPPED;
case UpnpState::WillMap:
return TR_PORT_MAPPING;
case UpnpState::WillUnmap:
return TR_PORT_UNMAPPING;
case UpnpState::Idle:
return is_mapped ? TR_PORT_MAPPED : TR_PORT_UNMAPPED;
default: // UpnpState::FAILED:
return TR_PORT_ERROR;
}
}
void tr_upnpClose(tr_upnp* handle)
{
delete handle;
}
/**
*** Wrappers for miniupnpc functions
**/
static struct UPNPDev* tr_upnpDiscover(int msec, char const* bindaddr)
[[nodiscard]] UPNPDev* upnp_discover(int msec, char const* bindaddr)
{
UPNPDev* ret = nullptr;
auto have_err = bool{};
@ -148,7 +130,7 @@ static struct UPNPDev* tr_upnpDiscover(int msec, char const* bindaddr)
return ret;
}
static int tr_upnpGetSpecificPortMappingEntry(tr_upnp const* handle, char const* proto)
[[nodiscard]] int get_specific_port_mapping_entry(tr_upnp const* handle, char const* proto)
{
auto int_client = std::array<char, 16>{};
auto int_port = std::array<char, 16>{};
@ -191,7 +173,7 @@ static int tr_upnpGetSpecificPortMappingEntry(tr_upnp const* handle, char const*
return err;
}
static int tr_upnpAddPortMapping(tr_upnp const* handle, char const* proto, tr_port port, char const* desc)
[[nodiscard]] int upnp_add_port_mapping(tr_upnp const* handle, char const* proto, tr_port port, char const* desc)
{
int const old_errno = errno;
errno = 0;
@ -230,17 +212,13 @@ static int tr_upnpAddPortMapping(tr_upnp const* handle, char const* proto, tr_po
return err;
}
static void tr_upnpDeletePortMapping(tr_upnp const* handle, char const* proto, tr_port port)
void tr_upnpDeletePortMapping(tr_upnp const* handle, char const* proto, tr_port port)
{
auto const port_str = fmt::format(FMT_STRING("{:d}"), port.host());
UPNP_DeletePortMapping(handle->urls.controlURL, handle->data.first.servicetype, port_str.c_str(), proto, nullptr);
}
/**
***
**/
enum
{
UPNP_IGD_NONE = 0,
@ -249,19 +227,32 @@ enum
UPNP_IGD_INVALID = 3
};
static auto* discoverThreadfunc(std::string bindaddr) // NOLINT performance-unnecessary-value-param
auto* discover_thread_func(std::string bindaddr) // NOLINT performance-unnecessary-value-param
{
// If multicastif is not NULL, it will be used instead of the default
// multicast interface for sending SSDP discover packets.
char const* multicastif = std::empty(bindaddr) ? nullptr : bindaddr.c_str();
return tr_upnpDiscover(2000, multicastif);
return upnp_discover(2000, multicastif);
}
template<typename T>
static bool isFutureReady(std::future<T> const& future)
bool is_future_ready(std::future<T> const& future)
{
return future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
} // namespace
// ---
tr_upnp* tr_upnpInit()
{
return new tr_upnp();
}
void tr_upnpClose(tr_upnp* handle)
{
delete handle;
}
tr_port_forwarding_state tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_enabled, bool do_port_check, std::string bindaddr)
{
@ -269,7 +260,7 @@ tr_port_forwarding_state tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_ena
{
TR_ASSERT(!handle->discover_future);
auto task = std::packaged_task<UPNPDev*(std::string)>{ discoverThreadfunc };
auto task = std::packaged_task<UPNPDev*(std::string)>{ discover_thread_func };
handle->discover_future = task.get_future();
handle->state = UpnpState::Discovering;
@ -277,7 +268,7 @@ tr_port_forwarding_state tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_ena
}
if (is_enabled && handle->state == UpnpState::Discovering && handle->discover_future &&
isFutureReady(*handle->discover_future))
is_future_ready(*handle->discover_future))
{
auto* const devlist = handle->discover_future->get();
handle->discover_future.reset();
@ -309,8 +300,8 @@ tr_port_forwarding_state tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_ena
}
if (is_enabled && handle->isMapped && do_port_check &&
((tr_upnpGetSpecificPortMappingEntry(handle, "TCP") != UPNPCOMMAND_SUCCESS) ||
(tr_upnpGetSpecificPortMappingEntry(handle, "UDP") != UPNPCOMMAND_SUCCESS)))
((get_specific_port_mapping_entry(handle, "TCP") != UPNPCOMMAND_SUCCESS) ||
(get_specific_port_mapping_entry(handle, "UDP") != UPNPCOMMAND_SUCCESS)))
{
tr_logAddInfo(fmt::format(_("Port {port} is not forwarded"), fmt::arg("port", handle->port.host())));
handle->isMapped = false;
@ -347,8 +338,8 @@ tr_port_forwarding_state tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_ena
else
{
auto const desc = fmt::format(FMT_STRING("Transmission at {:d}"), port.host());
int const err_tcp = tr_upnpAddPortMapping(handle, "TCP", port, desc.c_str());
int const err_udp = tr_upnpAddPortMapping(handle, "UDP", port, desc.c_str());
int const err_tcp = upnp_add_port_mapping(handle, "TCP", port, desc.c_str());
int const err_udp = upnp_add_port_mapping(handle, "UDP", port, desc.c_str());
handle->isMapped = err_tcp == 0 || err_udp == 0;
}
@ -374,5 +365,5 @@ tr_port_forwarding_state tr_upnpPulse(tr_upnp* handle, tr_port port, bool is_ena
}
}
return portFwdState(handle->state, handle->isMapped);
return port_fwd_state(handle->state, handle->isMapped);
}

View File

@ -27,7 +27,9 @@
using namespace std::literals;
static void handle_sigchld(int /*i*/)
namespace
{
void handle_sigchld(int /*i*/)
{
int rc = 0;
@ -40,7 +42,7 @@ static void handle_sigchld(int /*i*/)
/* FIXME: Call old handler, if any */
}
static void set_system_error(tr_error** error, int code, std::string_view what)
void set_system_error(tr_error** error, int code, std::string_view what)
{
if (error == nullptr)
{
@ -50,7 +52,7 @@ static void set_system_error(tr_error** error, int code, std::string_view what)
tr_error_set(error, code, fmt::format(FMT_STRING("{:s} failed: {:s} ({:d})"), what, tr_strerror(code), code));
}
static bool tr_spawn_async_in_child(
[[nodiscard]] bool tr_spawn_async_in_child(
char const* const* cmd,
std::map<std::string_view, std::string_view> const& env,
std::string_view work_dir)
@ -82,7 +84,7 @@ static bool tr_spawn_async_in_child(
return true;
}
static bool tr_spawn_async_in_parent(int pipe_fd, tr_error** error)
[[nodiscard]] bool tr_spawn_async_in_parent(int pipe_fd, tr_error** error)
{
int child_errno = 0;
ssize_t count = 0;
@ -114,6 +116,7 @@ static bool tr_spawn_async_in_parent(int pipe_fd, tr_error** error)
return true;
}
} // namespace
bool tr_spawn_async(
char const* const* cmd,

File diff suppressed because it is too large Load Diff

View File

@ -73,10 +73,12 @@ void tr_utpClose(tr_session* /*session*/)
#else
namespace
{
/* Greg says 50ms works for them. */
static auto constexpr UtpInterval = 50ms;
auto constexpr UtpInterval = 50ms;
static void utp_on_accept(tr_session* const session, UTPSocket* const utp_sock)
void utp_on_accept(tr_session* const session, UTPSocket* const utp_sock)
{
auto from_storage = sockaddr_storage{};
auto* const from = (struct sockaddr*)&from_storage;
@ -102,7 +104,7 @@ static void utp_on_accept(tr_session* const session, UTPSocket* const utp_sock)
}
}
static void utp_send_to(
void utp_send_to(
tr_session const* const ss,
uint8_t const* const buf,
size_t const buflen,
@ -112,7 +114,7 @@ static void utp_send_to(
ss->udp_core_->sendto(buf, buflen, to, tolen);
}
static uint64 utp_callback(utp_callback_arguments* args)
uint64 utp_callback(utp_callback_arguments* args)
{
auto* const session = static_cast<tr_session*>(utp_context_get_userdata(args->context));
@ -139,7 +141,7 @@ static uint64 utp_callback(utp_callback_arguments* args)
return 0;
}
static void reset_timer(tr_session* session)
void reset_timer(tr_session* session)
{
auto interval = std::chrono::milliseconds{};
auto const random_percent = tr_rand_int(1000U) / 1000.0;
@ -167,7 +169,7 @@ static void reset_timer(tr_session* session)
session->utp_timer->startSingleShot(interval);
}
static void timer_callback(void* vsession)
void timer_callback(void* vsession)
{
auto* session = static_cast<tr_session*>(vsession);
@ -177,6 +179,7 @@ static void timer_callback(void* vsession)
utp_check_timeouts(session->utp_context);
reset_timer(session);
}
} // namespace
void tr_utpInit(tr_session* session)
{