mirror of
https://github.com/transmission/transmission
synced 2024-12-27 18:18:10 +00:00
1cc9da26ba
* refactor: implement FileTreeItem::children_ with a std::vector
* fix: std::move should not be called on forwarding reference
* fix: uninitialized scalar variable
* fix: unchecked return value from library
* fix: dereference before null check
* fix: unchecked return value from library
* fix: unchecked return value from library
* fixup! refactor: implement FileTreeItem::children_ with a std::vector
* fix: signed-unsigned comparison in libtransmission tests
* fix: avoid unnecessary copy by using const reference
* fix: function should be declared const
* refactor: use fmt::format to build log timestamps
* fix: use init-statement to reduce variable scope
* fixup! refactor: use fmt::format to build log timestamps
* fix: remove tau_tracker destructor for rule-of-zero
* fix: remove tr_peerIo destructor for rule-of-zero
* Revert "fix: dereference before null check"
This reverts commit cd78967815
.
* fix: signed-unsigned comparison in libtransmission tests
* fix: use init-statement to reduce variable scope
* fix: extract nested code block into separate method
* fix: extract nested code block into separate method
* fix: extract nested code block into separate method
* fix: use init-statement to reduce variable scope
* fix: extract nested code block into separate method
* fix: signed-unsigned comparison in libtransmission tests
* fixup! fix: extract nested code block into separate method
* fix: mark possibly-unused as [[maybe_unused]]
* fix: invalid stack memory reference in tr_found_file_t
* fix: signed-unsigned comparison in libtransmission tests
306 lines
9.6 KiB
C++
306 lines
9.6 KiB
C++
// This file Copyright (C) 2022 Mnemosyne LLC.
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0), GPLv3 (SPDX: GPL-3.0),
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
// License text can be found in the licenses/ folder.
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <string_view>
|
|
|
|
#define LIBTRANSMISSION_ANNOUNCER_MODULE
|
|
|
|
#include "transmission.h"
|
|
|
|
#include "announcer-common.h"
|
|
#include "crypto-utils.h"
|
|
#include "net.h"
|
|
|
|
#include "test-fixtures.h"
|
|
|
|
using AnnouncerTest = ::testing::Test;
|
|
|
|
using namespace std::literals;
|
|
|
|
static char const* const LogName = "LogName";
|
|
|
|
TEST_F(AnnouncerTest, parseHttpAnnounceResponseNoPeers)
|
|
{
|
|
// clang-format off
|
|
auto constexpr NoPeers =
|
|
"d"
|
|
"8:complete" "i3e"
|
|
"10:downloaded" "i2e"
|
|
"10:incomplete" "i0e"
|
|
"8:interval" "i1803e"
|
|
"12:min interval" "i1800e"
|
|
"5:peers" "0:"
|
|
"11:external ip" "4:\x01\x02\x03\x04"
|
|
"e"sv;
|
|
// clang-format on
|
|
|
|
auto response = tr_announce_response{};
|
|
tr_announcerParseHttpAnnounceResponse(response, NoPeers, LogName);
|
|
EXPECT_EQ(1803, response.interval);
|
|
EXPECT_EQ(1800, response.min_interval);
|
|
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(0U, std::size(response.pex));
|
|
EXPECT_EQ(0U, std::size(response.pex6));
|
|
EXPECT_EQ(""sv, response.errmsg);
|
|
EXPECT_EQ(""sv, response.warning);
|
|
}
|
|
|
|
TEST_F(AnnouncerTest, parseHttpAnnounceResponsePexCompact)
|
|
{
|
|
// clang-format off
|
|
auto constexpr IPv4Peers =
|
|
"d"
|
|
"8:complete" "i3e"
|
|
"10:downloaded" "i2e"
|
|
"10:incomplete" "i0e"
|
|
"8:interval" "i1803e"
|
|
"12:min interval" "i1800e"
|
|
"5:peers"
|
|
"6:\x7F\x00\x00\x01\xfc\x27"
|
|
"e"sv;
|
|
// clang-format on
|
|
|
|
auto response = tr_announce_response{};
|
|
tr_announcerParseHttpAnnounceResponse(response, IPv4Peers, LogName);
|
|
EXPECT_EQ(1803, response.interval);
|
|
EXPECT_EQ(1800, response.min_interval);
|
|
EXPECT_EQ(3, response.seeders);
|
|
EXPECT_EQ(0, response.leechers);
|
|
EXPECT_EQ(2, response.downloads);
|
|
EXPECT_EQ(""sv, response.errmsg);
|
|
EXPECT_EQ(""sv, response.warning);
|
|
EXPECT_EQ(1U, std::size(response.pex));
|
|
EXPECT_EQ(0U, std::size(response.pex6));
|
|
|
|
if (std::size(response.pex) == 1)
|
|
{
|
|
EXPECT_EQ("[127.0.0.1]:64551"sv, response.pex[0].to_string());
|
|
}
|
|
}
|
|
|
|
TEST_F(AnnouncerTest, parseHttpAnnounceResponsePexList)
|
|
{
|
|
// clang-format off
|
|
auto constexpr IPv4Peers =
|
|
"d"
|
|
"8:complete" "i3e"
|
|
"10:downloaded" "i2e"
|
|
"10:incomplete" "i0e"
|
|
"8:interval" "i1803e"
|
|
"12:min interval" "i1800e"
|
|
"5:peers"
|
|
"l"
|
|
"d"
|
|
"7:peer id" "20:-TR300Z-0123456789AB"
|
|
"2:ip" "7:8.8.4.4"
|
|
"4:port" "i53e"
|
|
"e"
|
|
"e"
|
|
"e"sv;
|
|
// clang-format on
|
|
|
|
auto response = tr_announce_response{};
|
|
tr_announcerParseHttpAnnounceResponse(response, IPv4Peers, LogName);
|
|
EXPECT_EQ(1803, response.interval);
|
|
EXPECT_EQ(1800, response.min_interval);
|
|
EXPECT_EQ(3, response.seeders);
|
|
EXPECT_EQ(0, response.leechers);
|
|
EXPECT_EQ(2, response.downloads);
|
|
EXPECT_EQ(""sv, response.errmsg);
|
|
EXPECT_EQ(""sv, response.warning);
|
|
EXPECT_EQ(1U, std::size(response.pex));
|
|
EXPECT_EQ(0U, std::size(response.pex6));
|
|
|
|
if (std::size(response.pex) == 1)
|
|
{
|
|
EXPECT_EQ("[8.8.4.4]:53"sv, response.pex[0].to_string());
|
|
}
|
|
}
|
|
|
|
TEST_F(AnnouncerTest, parseHttpAnnounceResponseFailureReason)
|
|
{
|
|
// clang-format off
|
|
auto constexpr NoPeers =
|
|
"d"
|
|
"8:complete" "i3e"
|
|
"14:failure reason" "6:foobar"
|
|
"10:downloaded" "i2e"
|
|
"10:incomplete" "i0e"
|
|
"8:interval" "i1803e"
|
|
"12:min interval" "i1800e"
|
|
"5:peers" "0:"
|
|
"e"sv;
|
|
// clang-format on
|
|
|
|
auto response = tr_announce_response{};
|
|
tr_announcerParseHttpAnnounceResponse(response, NoPeers, LogName);
|
|
EXPECT_EQ(1803, response.interval);
|
|
EXPECT_EQ(1800, response.min_interval);
|
|
EXPECT_EQ(3, response.seeders);
|
|
EXPECT_EQ(0, response.leechers);
|
|
EXPECT_EQ(2, response.downloads);
|
|
EXPECT_EQ(0U, std::size(response.pex));
|
|
EXPECT_EQ(0U, std::size(response.pex6));
|
|
EXPECT_EQ("foobar"sv, response.errmsg);
|
|
EXPECT_EQ(""sv, response.warning);
|
|
}
|
|
|
|
TEST_F(AnnouncerTest, parseHttpScrapeResponseMulti)
|
|
{
|
|
// clang-format off
|
|
auto constexpr ResponseBenc =
|
|
"d"
|
|
"5:files"
|
|
"d"
|
|
"20:aaaaaaaaaaaaaaaaaaaa"
|
|
"d"
|
|
"8:complete" "i1e"
|
|
"10:incomplete" "i2e"
|
|
"10:downloaded" "i3e"
|
|
"e"
|
|
|
|
"20:bbbbbbbbbbbbbbbbbbbb"
|
|
"d"
|
|
"8:complete" "i4e"
|
|
"10:incomplete" "i5e"
|
|
"10:downloaded" "i6e"
|
|
"e"
|
|
|
|
"20:cccccccccccccccccccc"
|
|
"d"
|
|
"8:complete" "i7e"
|
|
"10:incomplete" "i8e"
|
|
"10:downloaded" "i9e"
|
|
"e"
|
|
"e"
|
|
"e"sv;
|
|
// clang-format on
|
|
|
|
auto response = tr_scrape_response{};
|
|
std::fill_n(std::data(response.rows[0].info_hash), std::size(response.rows[0].info_hash), std::byte{ 'a' });
|
|
std::fill_n(std::data(response.rows[1].info_hash), std::size(response.rows[1].info_hash), std::byte{ 'b' });
|
|
std::fill_n(std::data(response.rows[2].info_hash), std::size(response.rows[2].info_hash), std::byte{ 'c' });
|
|
response.row_count = 3;
|
|
tr_announcerParseHttpScrapeResponse(response, ResponseBenc, LogName);
|
|
|
|
EXPECT_EQ(1, response.rows[0].seeders);
|
|
EXPECT_EQ(2, response.rows[0].leechers);
|
|
EXPECT_EQ(3, response.rows[0].downloads);
|
|
|
|
EXPECT_EQ(4, response.rows[1].seeders);
|
|
EXPECT_EQ(5, response.rows[1].leechers);
|
|
EXPECT_EQ(6, response.rows[1].downloads);
|
|
|
|
EXPECT_EQ(7, response.rows[2].seeders);
|
|
EXPECT_EQ(8, response.rows[2].leechers);
|
|
EXPECT_EQ(9, response.rows[2].downloads);
|
|
}
|
|
|
|
TEST_F(AnnouncerTest, parseHttpScrapeResponseMultiWithUnexpected)
|
|
{
|
|
// clang-format off
|
|
auto constexpr ResponseBenc =
|
|
"d"
|
|
"5:files"
|
|
"d"
|
|
"20:aaaaaaaaaaaaaaaaaaaa"
|
|
"d"
|
|
"8:complete" "i1e"
|
|
"10:incomplete" "i2e"
|
|
"10:downloaded" "i3e"
|
|
"e"
|
|
|
|
"20:bbbbbbbbbbbbbbbbbbbb"
|
|
"d"
|
|
"8:complete" "i4e"
|
|
"10:incomplete" "i5e"
|
|
"10:downloaded" "i6e"
|
|
"e"
|
|
|
|
"20:cccccccccccccccccccc"
|
|
"d"
|
|
"8:complete" "i7e"
|
|
"10:incomplete" "i8e"
|
|
"10:downloaded" "i9e"
|
|
"e"
|
|
|
|
"20:dddddddddddddddddddd"
|
|
"d"
|
|
"8:complete" "i7e"
|
|
"10:incomplete" "i8e"
|
|
"10:downloaded" "i9e"
|
|
"e"
|
|
"e"
|
|
"e"sv;
|
|
// clang-format on
|
|
|
|
auto response = tr_scrape_response{};
|
|
std::fill_n(std::data(response.rows[0].info_hash), std::size(response.rows[0].info_hash), std::byte{ 'a' });
|
|
std::fill_n(std::data(response.rows[1].info_hash), std::size(response.rows[1].info_hash), std::byte{ 'b' });
|
|
std::fill_n(std::data(response.rows[2].info_hash), std::size(response.rows[2].info_hash), std::byte{ 'c' });
|
|
response.row_count = 3;
|
|
tr_announcerParseHttpScrapeResponse(response, ResponseBenc, LogName);
|
|
|
|
EXPECT_EQ(1, response.rows[0].seeders);
|
|
EXPECT_EQ(2, response.rows[0].leechers);
|
|
EXPECT_EQ(3, response.rows[0].downloads);
|
|
|
|
EXPECT_EQ(4, response.rows[1].seeders);
|
|
EXPECT_EQ(5, response.rows[1].leechers);
|
|
EXPECT_EQ(6, response.rows[1].downloads);
|
|
|
|
EXPECT_EQ(7, response.rows[2].seeders);
|
|
EXPECT_EQ(8, response.rows[2].leechers);
|
|
EXPECT_EQ(9, response.rows[2].downloads);
|
|
}
|
|
|
|
TEST_F(AnnouncerTest, parseHttpScrapeResponseMultiWithMissing)
|
|
{
|
|
// clang-format off
|
|
auto constexpr ResponseBenc =
|
|
"d"
|
|
"5:files"
|
|
"d"
|
|
"20:aaaaaaaaaaaaaaaaaaaa"
|
|
"d"
|
|
"8:complete" "i1e"
|
|
"10:incomplete" "i2e"
|
|
"10:downloaded" "i3e"
|
|
"e"
|
|
|
|
"20:cccccccccccccccccccc"
|
|
"d"
|
|
"8:complete" "i7e"
|
|
"10:incomplete" "i8e"
|
|
"10:downloaded" "i9e"
|
|
"e"
|
|
"e"
|
|
"e"sv;
|
|
// clang-format on
|
|
|
|
auto response = tr_scrape_response{};
|
|
std::fill_n(std::data(response.rows[0].info_hash), std::size(response.rows[0].info_hash), std::byte{ 'a' });
|
|
std::fill_n(std::data(response.rows[1].info_hash), std::size(response.rows[1].info_hash), std::byte{ 'b' });
|
|
std::fill_n(std::data(response.rows[2].info_hash), std::size(response.rows[2].info_hash), std::byte{ 'c' });
|
|
response.row_count = 3;
|
|
tr_announcerParseHttpScrapeResponse(response, ResponseBenc, LogName);
|
|
|
|
EXPECT_EQ(1, response.rows[0].seeders);
|
|
EXPECT_EQ(2, response.rows[0].leechers);
|
|
EXPECT_EQ(3, response.rows[0].downloads);
|
|
|
|
EXPECT_EQ(0, response.rows[1].seeders);
|
|
EXPECT_EQ(0, response.rows[1].leechers);
|
|
EXPECT_EQ(0, response.rows[1].downloads);
|
|
|
|
EXPECT_EQ(7, response.rows[2].seeders);
|
|
EXPECT_EQ(8, response.rows[2].leechers);
|
|
EXPECT_EQ(9, response.rows[2].downloads);
|
|
}
|