fixup: handle unhandled scrape/announce responses (#2701)

followup to the #2531 benc refactor
This commit is contained in:
Charles Kerr 2022-02-24 07:59:58 -06:00 committed by GitHub
parent 798022ac77
commit 9c3acc7e8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 80 additions and 3 deletions

View File

@ -214,6 +214,10 @@ struct tr_announce_response
/* key generated by and returned from an http tracker.
* if this is provided, subsequent http announces must include this. */
std::string tracker_id;
/* tracker extension that returns the client's public IP address.
* https://www.bittorrent.org/beps/bep_0024.html */
std::optional<tr_address> external_ip;
};
using tr_announce_response_func = void (*)(tr_announce_response const* response, void* userdata);

View File

@ -253,6 +253,10 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std::
{
// unused
}
else if (key == "external ip"sv && std::size(value) == 4)
{
response_.external_ip = tr_address::from_4byte_ipv4(value);
}
else if (!tr_error_is_set(context.error))
{
tr_error_set(context.error, EINVAL, tr_strvJoin("unexpected str: key["sv, key, "] value["sv, value, "]"sv));
@ -402,6 +406,14 @@ void tr_announcerParseHttpScrapeResponse(tr_scrape_response& response, std::stri
{
response_.rows[*row_].leechers = value;
}
else if (row_ && key == "downloaders"sv)
{
response_.rows[*row_].downloaders = value;
}
else if (key == "min_request_interval"sv)
{
response_.min_request_interval = value;
}
else if (!tr_error_is_set(context.error))
{
auto const errmsg = tr_strvJoin("unexpected int: key["sv, key, "] value["sv, std::to_string(value), "]"sv);

View File

@ -995,6 +995,11 @@ static void on_announce_done(tr_announce_response const* response, void* vdata)
tier->isAnnouncing = false;
tier->manualAnnounceAllowedAt = now + tier->announceMinIntervalSec;
if (response->external_ip)
{
data->session->setExternalIP(*response->external_ip);
}
if (!response->did_connect)
{
on_announce_error(tier, _("Could not connect to tracker"), event);

View File

@ -115,7 +115,7 @@ bool tr_address_from_string(tr_address* dst, std::string_view src)
{
// inet_pton() requires zero-terminated strings,
// so make a zero-terminated copy here on the stack.
auto buf = std::array<char, 64>{};
auto buf = std::array<char, TR_ADDRSTRLEN>{};
if (std::size(src) >= std::size(buf))
{
// shouldn't ever be that large; malformed address
@ -127,6 +127,28 @@ bool tr_address_from_string(tr_address* dst, std::string_view src)
return tr_address_from_string(dst, std::data(buf));
}
std::optional<tr_address> tr_address::from_string(std::string_view str)
{
auto addr = tr_address{};
if (!tr_address_from_string(&addr, str))
{
return {};
}
return addr;
}
tr_address tr_address::from_4byte_ipv4(std::string_view in)
{
TR_ASSERT(std::size(in) == 4);
auto addr = tr_address{};
addr.type = TR_AF_INET;
std::copy_n(std::begin(in), 4, reinterpret_cast<char*>(&addr.addr));
return addr;
}
/*
* Compare two tr_address structures.
* Returns:

View File

@ -68,14 +68,37 @@ enum tr_address_type
NUM_TR_AF_INET_TYPES
};
struct tr_address;
int tr_address_compare(tr_address const* a, tr_address const* b);
struct tr_address
{
static tr_address from_4byte_ipv4(std::string_view in);
static std::optional<tr_address> from_string(std::string_view str);
tr_address_type type;
union
{
struct in6_addr addr6;
struct in_addr addr4;
} addr;
bool operator==(tr_address const& that) const
{
return tr_address_compare(this, &that) == 0;
}
bool operator<(tr_address const& that) const
{
return tr_address_compare(this, &that) < 0;
}
bool operator>(tr_address const& that) const
{
return tr_address_compare(this, &that) > 0;
}
};
extern tr_address const tr_inaddr_any;
@ -93,8 +116,6 @@ bool tr_address_from_string(tr_address* dst, std::string_view src);
bool tr_address_from_sockaddr_storage(tr_address* setme, tr_port* port, struct sockaddr_storage const* src);
int tr_address_compare(tr_address const* a, tr_address const* b);
bool tr_address_is_valid_for_peers(tr_address const* addr, tr_port port);
constexpr bool tr_address_is_valid(tr_address const* a)

View File

@ -239,6 +239,16 @@ public:
bool useRpcWhitelist() const;
auto externalIP() const
{
return external_ip_;
}
void setExternalIP(tr_address external_ip)
{
external_ip_ = external_ip;
}
// peer networking
std::string const& peerCongestionAlgorithm() const
@ -419,6 +429,7 @@ private:
std::string default_trackers_str_;
std::string incomplete_dir_;
std::string peer_congestion_algorithm_;
std::optional<tr_address> external_ip_;
std::array<bool, TR_SCRIPT_N_TYPES> scripts_enabled_;
bool blocklist_enabled_ = false;

View File

@ -32,6 +32,7 @@ TEST_F(AnnouncerTest, parseHttpAnnounceResponseNoPeers)
"8:interval" "i1803e"
"12:min interval" "i1800e"
"5:peers" "0:"
"11:external ip" "4:\x01\x02\x03\x04"
"e"sv;
// clang-format on
@ -42,6 +43,7 @@ TEST_F(AnnouncerTest, parseHttpAnnounceResponseNoPeers)
EXPECT_EQ(3, response.seeders);
EXPECT_EQ(0, response.leechers);
EXPECT_EQ(2, response.downloads);
EXPECT_EQ(*tr_address::from_string("1.2.3.4"), response.external_ip);
EXPECT_EQ(0, std::size(response.pex));
EXPECT_EQ(0, std::size(response.pex6));
EXPECT_EQ(""sv, response.errmsg);