From 581c3f98544aebb19efc93e3ecdb24cd39b73ea2 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 20 Feb 2022 13:00:52 -0600 Subject: [PATCH] refactor: do not mix torrent, default trackers --- extras/rpc-spec.md | 2 + libtransmission/announce-list.cc | 23 ++++++ libtransmission/announce-list.h | 1 + libtransmission/announcer.cc | 16 ++++- libtransmission/rpcimpl.cc | 2 +- libtransmission/session.cc | 36 +--------- libtransmission/session.h | 11 ++- libtransmission/torrent.cc | 47 ------------ tests/libtransmission/announce-list-test.cc | 80 +++++++++++++++++++++ 9 files changed, 134 insertions(+), 84 deletions(-) diff --git a/extras/rpc-spec.md b/extras/rpc-spec.md index bc46b0a17..4e648fc6c 100644 --- a/extras/rpc-spec.md +++ b/extras/rpc-spec.md @@ -531,6 +531,7 @@ Response arguments: `path`, `name`, and `id`, holding the torrent ID integer | `blocklist-url` | string | location of the blocklist to use for `blocklist-update` | `cache-size-mb` | number | maximum size of the disk cache (MB) | `config-dir` | string | location of transmission's configuration directory +| `default-trackers` | list of default trackers to use on public torrents | `dht-enabled` | boolean | true means allow dht in public torrents | `download-dir` | string | default path to download torrents | `download-dir-free-space` | number | **DEPRECATED** Use the `free-space` method instead. @@ -940,6 +941,7 @@ Transmission 4.0.0 (`rpc-version-semver` 5.3.0, `rpc-version`: 17) | `/upload` | :warning: undocumented `/upload` endpoint removed | `session-get` | **DEPRECATED** `download-dir-free-space`. Use `free-space` instead. | `free-space` | new return arg `total-capacity` +| `session-get` | new arg `default-trackers` | `session-get` | new arg `rpc-version-semver` | `session-get` | new arg `script-torrent-added-enabled` | `session-get` | new arg `script-torrent-added-filename` diff --git a/libtransmission/announce-list.cc b/libtransmission/announce-list.cc index 42c6e0fec..dc0462f86 100644 --- a/libtransmission/announce-list.cc +++ b/libtransmission/announce-list.cc @@ -98,6 +98,29 @@ bool tr_announce_list::add(std::string_view announce_url_sv, tr_tracker_tier_t t return true; } +void tr_announce_list::add(tr_announce_list const& src) +{ + if (std::empty(src)) + { + return; + } + + auto src_tier = src.at(0).tier; + auto& tgt = *this; + auto tgt_tier = tgt.nextTier(); + + for (auto const& tracker : src) + { + if (src_tier != tracker.tier) + { + src_tier = tracker.tier; + ++tgt_tier; + } + + tgt.add(tracker.announce.full, tgt_tier); + } +} + std::optional tr_announce_list::announceToScrape(std::string_view announce) { // To derive the scrape URL use the following steps: diff --git a/libtransmission/announce-list.h b/libtransmission/announce-list.h index 6614ceabf..9049a163e 100644 --- a/libtransmission/announce-list.h +++ b/libtransmission/announce-list.h @@ -98,6 +98,7 @@ public: } bool add(std::string_view announce_url_sv, tr_tracker_tier_t tier); + void add(tr_announce_list const& that); bool remove(std::string_view announce_url); bool remove(tr_tracker_id_t id); bool replace(tr_tracker_id_t id, std::string_view announce_url_sv); diff --git a/libtransmission/announcer.cc b/libtransmission/announcer.cc index 1e3e36e62..8f27553f9 100644 --- a/libtransmission/announcer.cc +++ b/libtransmission/announcer.cc @@ -505,7 +505,7 @@ struct tr_torrent_announcer { // build the trackers auto tier_to_infos = std::map>{}; - auto const& announce_list = tor->announceList(); + auto const announce_list = getAnnounceList(tor); for (auto const& info : announce_list) { tier_to_infos[info.tier].emplace_back(&info); @@ -575,6 +575,20 @@ struct tr_torrent_announcer tr_tracker_callback callback = nullptr; void* callback_data = nullptr; + +private: + [[nodiscard]] static tr_announce_list getAnnounceList(tr_torrent const* tor) + { + auto announce_list = tor->announceList(); + + // if it's a public torrent, inject the default trackers + if (!tor->isPrivate()) + { + announce_list.add(tor->session->defaultTrackers()); + } + + return announce_list; + } }; static tr_tier* getTier(tr_announcer* announcer, tr_sha1_digest_t const& info_hash, int tier_id) diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index 365fb8440..3c681938c 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -2077,7 +2077,7 @@ static void addSessionField(tr_session* s, tr_variant* d, tr_quark key) break; case TR_KEY_default_trackers: - tr_variantDictAddStr(d, key, s->defaultTrackers()); + tr_variantDictAddStr(d, key, s->defaultTrackersStr()); break; case TR_KEY_download_dir: diff --git a/libtransmission/session.cc b/libtransmission/session.cc index 4f21f367b..d4abeb760 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -412,7 +412,7 @@ void tr_sessionGetSettings(tr_session const* s, tr_variant* d) tr_variantDictAddBool(d, TR_KEY_utp_enabled, s->isUTPEnabled); tr_variantDictAddBool(d, TR_KEY_lpd_enabled, s->isLPDEnabled); tr_variantDictAddStr(d, TR_KEY_download_dir, tr_sessionGetDownloadDir(s)); - tr_variantDictAddStr(d, TR_KEY_default_trackers, s->defaultTrackers()); + tr_variantDictAddStr(d, TR_KEY_default_trackers, s->defaultTrackersStr()); tr_variantDictAddInt(d, TR_KEY_download_queue_size, tr_sessionGetQueueSize(s, TR_DOWN)); tr_variantDictAddBool(d, TR_KEY_download_queue_enabled, tr_sessionGetQueueEnabled(s, TR_DOWN)); tr_variantDictAddInt(d, TR_KEY_speed_limit_down, tr_sessionGetSpeedLimit_KBps(s, TR_DOWN)); @@ -2253,45 +2253,15 @@ int tr_sessionGetCacheLimit_MB(tr_session const* session) void tr_session::setDefaultTrackers(std::string_view trackers) { - /* keep the string */ this->default_trackers_str_ = trackers; - - /* clear out the old list entries */ - this->defaultTrackersList.clear(); - - /* build the new list entries */ - auto urlStart = std::string::npos; - auto constexpr Delimiters = " ,;\r\n\t"sv; - auto fragment = default_trackers_str_; - while ((urlStart = fragment.find_first_not_of(Delimiters)) != std::string::npos) - { - auto urlEnd = fragment.find_first_of(Delimiters, urlStart); - if (urlEnd == std::string::npos) - { - urlEnd = fragment.size() - 1; - } - else - { - urlEnd -= 1; - } - this->defaultTrackersList.push_back(fragment.substr(urlStart, urlEnd)); - - if (fragment.size() > (urlEnd + 1)) - { - fragment = fragment.substr(urlEnd + 1, fragment.size()); - } - else - { - break; - } - } + this->default_trackers_.parse(trackers); } void tr_sessionSetDefaultTrackers(tr_session* session, char const* trackers) { TR_ASSERT(tr_isSession(session)); - session->setDefaultTrackers(trackers ? trackers : ""); + session->setDefaultTrackers(trackers != nullptr ? trackers : ""); } /*** diff --git a/libtransmission/session.h b/libtransmission/session.h index 33ed35c2e..f89f43c47 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -27,6 +27,7 @@ #include "transmission.h" +#include "announce-list.h" #include "net.h" // tr_socket_t #include "quark.h" #include "web.h" @@ -151,12 +152,18 @@ public: } // default trackers + // (trackers to apply automatically to public torrents) - std::string const& defaultTrackers() const + auto const& defaultTrackersStr() const { return default_trackers_str_; } + auto const& defaultTrackers() const + { + return default_trackers_; + } + void setDefaultTrackers(std::string_view trackers); // incomplete dir @@ -396,7 +403,7 @@ public: std::unique_ptr rpc_server_; - std::list defaultTrackersList; + tr_announce_list default_trackers_; // One of 's IPTOS_ values. // See tr_netTos*() in libtransmission/net.h for more info diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index f39be7ce7..3c29ef7d8 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -817,52 +817,6 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) } } -static void tr_torrentAddDefaultTrackers(tr_torrent* tor) -{ - std::list trackerURLs = {}; - int numExistingTrackers = tr_torrentTrackerCount(tor); - int numNewTrackers = tor->session->defaultTrackersList.size(); - - if (!numNewTrackers || tor->isPrivate()) - { - return; - } - - // copy existing tracker URLs - for (int i = 0; i < numExistingTrackers; ++i) - { - auto tracker = tr_torrentTracker(tor, i); - trackerURLs.push_back(tracker.announce); - } - - // add the new ones - for (std::string_view url : tor->session->defaultTrackersList) - { - if (tr_urlIsValidTracker(url)) - { - // check for duplicates - bool duplicate = false; - for (auto trackerURL : trackerURLs) - { - if (trackerURL == url) - { - duplicate = true; - break; - } - } - - if (duplicate) - { - continue; - } - - tor->announceList().add(url); - } - } - /* tell the announcer to reload this torrent's tracker list */ - tr_announcerResetTorrent(tor->session->announcer, tor); -} - tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of) { TR_ASSERT(ctor != nullptr); @@ -889,7 +843,6 @@ tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of) auto* const tor = new tr_torrent{ std::move(metainfo) }; torrentInit(tor, ctor); - tr_torrentAddDefaultTrackers(tor); return tor; } diff --git a/tests/libtransmission/announce-list-test.cc b/tests/libtransmission/announce-list-test.cc index 32a848dfa..48fa4f312 100644 --- a/tests/libtransmission/announce-list-test.cc +++ b/tests/libtransmission/announce-list-test.cc @@ -611,3 +611,83 @@ TEST_F(AnnounceListTest, parseDuplicateUrl) EXPECT_FALSE(announce_list.parse(Text)); } + +TEST_F(AnnounceListTest, addAnnounceListWithSingleTracker) +{ + auto constexpr Trackers = + "https://www.foo.com/announce\n" + "\n" + "https://www.bar.com/announce\n"sv; + auto announce_list = tr_announce_list{}; + announce_list.parse(Trackers); + + auto constexpr AddStr = "https://www.baz.com/announce"sv; + auto tmp = tr_announce_list{}; + tmp.parse(AddStr); + + announce_list.add(tmp); + + auto constexpr Expected = + "https://www.foo.com/announce\n" + "\n" + "https://www.bar.com/announce\n" + "\n" + "https://www.baz.com/announce\n"sv; + EXPECT_EQ(Expected, announce_list.toString()); +} + +TEST_F(AnnounceListTest, addAnnounceWithSingleTier) +{ + auto constexpr Trackers = + "https://www.foo.com/announce\n" + "\n" + "https://www.bar.com/announce\n"sv; + auto announce_list = tr_announce_list{}; + announce_list.parse(Trackers); + + auto constexpr AddStr = + "https://www.baz.com/announce\n" + "https://www.qux.com/announce\n"sv; + auto tmp = tr_announce_list{}; + tmp.parse(AddStr); + + announce_list.add(tmp); + + auto constexpr Expected = + "https://www.foo.com/announce\n" + "\n" + "https://www.bar.com/announce\n" + "\n" + "https://www.baz.com/announce\n" + "https://www.qux.com/announce\n"sv; + EXPECT_EQ(Expected, announce_list.toString()); +} + +TEST_F(AnnounceListTest, addAnnounceListWithMultiTier) +{ + auto constexpr Trackers = + "https://www.foo.com/announce\n" + "\n" + "https://www.bar.com/announce\n"sv; + auto announce_list = tr_announce_list{}; + announce_list.parse(Trackers); + + auto constexpr AddStr = + "https://www.baz.com/announce\n" + "\n" + "https://www.qux.com/announce\n"sv; + auto tmp = tr_announce_list{}; + tmp.parse(AddStr); + + announce_list.add(tmp); + + auto constexpr Expected = + "https://www.foo.com/announce\n" + "\n" + "https://www.bar.com/announce\n" + "\n" + "https://www.baz.com/announce\n" + "\n" + "https://www.qux.com/announce\n"sv; + EXPECT_EQ(Expected, announce_list.toString()); +}