You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
transmission/f551b4adbff0d59557d61867d0b...

501 lines
16 KiB

From f551b4adbff0d59557d61867d0b6518c50f5a73f Mon Sep 17 00:00:00 2001
From: Charles Kerr <charles@charleskerr.com>
Date: Mon, 13 Feb 2023 12:33:33 -0600
Subject: [PATCH] fix: magnet links are always paused when added (#4856)
---
libtransmission/peer-mgr.cc | 8 +-
libtransmission/resume.cc | 6 +-
libtransmission/torrent-magnet.cc | 34 +++----
libtransmission/torrent-magnet.h | 2 +
libtransmission/torrent.cc | 148 ++++++++++++++----------------
libtransmission/torrent.h | 9 +-
libtransmission/transmission.h | 2 +-
macosx/Torrent.mm | 2 +-
8 files changed, 101 insertions(+), 110 deletions(-)
diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc
index 4cf1d332c8..8e826dc3fa 100644
--- a/libtransmission/peer-mgr.cc
+++ b/libtransmission/peer-mgr.cc
@@ -43,6 +43,7 @@
#include "session.h"
#include "timer.h"
#include "torrent.h"
+#include "torrent-magnet.h"
#include "tr-assert.h"
#include "tr-utp.h"
#include "utils.h"
@@ -2391,8 +2392,11 @@ void tr_peerMgr::bandwidthPulse()
session->top_bandwidth_.allocate(Msec);
// torrent upkeep
- auto& torrents = session->torrents();
- std::for_each(std::begin(torrents), std::end(torrents), [](auto* tor) { tor->do_idle_work(); });
+ for (auto* const tor : session->torrents())
+ {
+ tor->do_idle_work();
+ tr_torrentMagnetDoIdleWork(tor);
+ }
/* pump the queues */
queuePulse(session, TR_UP);
diff --git a/libtransmission/resume.cc b/libtransmission/resume.cc
index 80c00dbd28..9716ae876c 100644
--- a/libtransmission/resume.cc
+++ b/libtransmission/resume.cc
@@ -712,7 +712,7 @@ auto loadFromFile(tr_torrent* tor, tr_resume::fields_t fields_to_load, bool* did
if (auto val = bool{}; (fields_to_load & tr_resume::Run) != 0 && tr_variantDictFindBool(&top, TR_KEY_paused, &val))
{
- tor->isRunning = !val;
+ tor->start_when_stable = !val;
fields_loaded |= tr_resume::Run;
}
@@ -831,7 +831,7 @@ auto setFromCtor(tr_torrent* tor, tr_resume::fields_t fields, tr_ctor const* cto
{
if (auto is_paused = bool{}; tr_ctorGetPaused(ctor, mode, &is_paused))
{
- tor->isRunning = !is_paused;
+ tor->start_when_stable = !is_paused;
ret |= tr_resume::Run;
}
}
@@ -907,7 +907,7 @@ void save(tr_torrent* tor)
tr_variantDictAddInt(&top, TR_KEY_uploaded, tor->uploadedPrev + tor->uploadedCur);
tr_variantDictAddInt(&top, TR_KEY_max_peers, tor->peerLimit());
tr_variantDictAddInt(&top, TR_KEY_bandwidth_priority, tor->getPriority());
- tr_variantDictAddBool(&top, TR_KEY_paused, !tor->isRunning && !tor->isQueued());
+ tr_variantDictAddBool(&top, TR_KEY_paused, !tor->start_when_stable);
savePeers(&top, tor);
if (tor->hasMetainfo())
diff --git a/libtransmission/torrent-magnet.cc b/libtransmission/torrent-magnet.cc
index 1d91cbfef1..c32defb433 100644
--- a/libtransmission/torrent-magnet.cc
+++ b/libtransmission/torrent-magnet.cc
@@ -176,13 +176,6 @@ bool tr_torrentUseMetainfoFromFile(
delete tor->incompleteMetadata;
tor->incompleteMetadata = nullptr;
}
- tor->isStopping = true;
- tor->magnetVerify = true;
- if (tor->session->shouldPauseAddedTorrents())
- {
- tor->startAfterVerify = false;
- }
- tor->markEdited();
return true;
}
@@ -310,13 +303,6 @@ void on_have_all_metainfo(tr_torrent* tor, tr_incomplete_metadata* m)
{
delete tor->incompleteMetadata;
tor->incompleteMetadata = nullptr;
- tor->isStopping = true;
- tor->magnetVerify = true;
- if (tor->session->shouldPauseAddedTorrents() && !tor->magnetStartAfterVerify)
- {
- tor->startAfterVerify = false;
- }
- tor->markEdited();
}
else /* drat. */
{
@@ -340,6 +326,19 @@ void on_have_all_metainfo(tr_torrent* tor, tr_incomplete_metadata* m)
} // namespace set_metadata_piece_helpers
} // namespace
+void tr_torrentMagnetDoIdleWork(tr_torrent* const tor)
+{
+ using namespace set_metadata_piece_helpers;
+
+ TR_ASSERT(tr_isTorrent(tor));
+
+ if (auto* const m = tor->incompleteMetadata; m != nullptr && std::empty(m->pieces_needed))
+ {
+ tr_logAddDebugTor(tor, fmt::format("we now have all the metainfo!"));
+ on_have_all_metainfo(tor, m);
+ }
+}
+
void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, size_t len)
{
using namespace set_metadata_piece_helpers;
@@ -384,13 +383,6 @@ void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, si
needed.erase(iter);
tr_logAddDebugTor(tor, fmt::format("saving metainfo piece {}... {} remain", piece, std::size(needed)));
-
- // are we done?
- if (std::empty(needed))
- {
- tr_logAddDebugTor(tor, fmt::format("metainfo piece {} was the last one", piece));
- on_have_all_metainfo(tor, m);
- }
}
// ---
diff --git a/libtransmission/torrent-magnet.h b/libtransmission/torrent-magnet.h
index 8af953bec9..cb5d7e1fcb 100644
--- a/libtransmission/torrent-magnet.h
+++ b/libtransmission/torrent-magnet.h
@@ -33,6 +33,8 @@ bool tr_torrentSetMetadataSizeHint(tr_torrent* tor, int64_t metadata_size);
double tr_torrentGetMetadataPercent(tr_torrent const* tor);
+void tr_torrentMagnetDoIdleWork(tr_torrent* tor);
+
bool tr_torrentUseMetainfoFromFile(
tr_torrent* tor,
tr_torrent_metainfo const* metainfo,
diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc
index 1e74f8152b..4b5a0b1dea 100644
--- a/libtransmission/torrent.cc
+++ b/libtransmission/torrent.cc
@@ -830,6 +830,8 @@ void torrentStart(tr_torrent* tor, torrent_start_opts opts)
{
using namespace start_stop_helpers;
+ auto const lock = tor->unique_lock();
+
switch (tor->activity())
{
case TR_STATUS_SEED:
@@ -849,7 +851,6 @@ void torrentStart(tr_torrent* tor, torrent_start_opts opts)
case TR_STATUS_CHECK_WAIT:
/* verifying right now... wait until that's done so
* we'll know what completeness to use/announce */
- tor->startAfterVerify = true;
return;
case TR_STATUS_STOPPED:
@@ -868,9 +869,6 @@ void torrentStart(tr_torrent* tor, torrent_start_opts opts)
return;
}
- /* otherwise, start it now... */
- auto const lock = tor->unique_lock();
-
/* allow finished torrents to be resumed */
if (tr_torrentIsSeedRatioDone(tor))
{
@@ -895,6 +893,9 @@ void torrentStop(tr_torrent* const tor)
TR_ASSERT(tor->session->amInSessionThread());
auto const lock = tor->unique_lock();
+ tor->isRunning = false;
+ tor->isStopping = false;
+
if (!tor->session->isClosing())
{
tr_logAddInfoTor(tor, _("Pausing torrent"));
@@ -913,16 +914,6 @@ void torrentStop(tr_torrent* const tor)
}
torrentSetQueued(tor, false);
-
- if (tor->magnetVerify)
- {
- tor->magnetVerify = false;
- tr_logAddTraceTor(tor, "Magnet Verify");
- tor->refreshCurrentDir();
- tr_torrentVerify(tor);
-
- callScriptIfEnabled(tor, TR_SCRIPT_ON_TORRENT_ADDED);
- }
}
} // namespace
@@ -935,8 +926,7 @@ void tr_torrentStop(tr_torrent* tor)
auto const lock = tor->unique_lock();
- tor->isRunning = false;
- tor->isStopping = false;
+ tor->start_when_stable = false;
tor->setDirty();
tor->session->runInSessionThread(torrentStop, tor);
}
@@ -965,7 +955,6 @@ void tr_torrentFreeInSessionThread(tr_torrent* tor)
tr_logAddInfoTor(tor, _("Removing torrent"));
}
- tor->magnetVerify = false;
torrentStop(tor);
if (tor->isDeleting)
@@ -975,7 +964,6 @@ void tr_torrentFreeInSessionThread(tr_torrent* tor)
tr_torrent_metainfo::removeFile(tor->session->resumeDir(), tor->name(), tor->infoHashString(), ".resume"sv);
}
- tor->isRunning = false;
freeTorrent(tor);
}
@@ -1036,6 +1024,34 @@ void torrentInitFromInfoDict(tr_torrent* tor)
tor->checked_pieces_ = tr_bitfield{ size_t(tor->pieceCount()) };
}
+void on_metainfo_completed(tr_torrent* tor)
+{
+ // we can look for files now that we know what files are in the torrent
+ tor->refreshCurrentDir();
+
+ callScriptIfEnabled(tor, TR_SCRIPT_ON_TORRENT_ADDED);
+
+ if (tor->session->shouldFullyVerifyAddedTorrents() || !isNewTorrentASeed(tor))
+ {
+ tr_torrentVerify(tor);
+ }
+ else
+ {
+ tor->completion.setHasAll();
+ tor->doneDate = tor->addedDate;
+ tor->recheckCompleteness();
+
+ if (tor->start_when_stable)
+ {
+ torrentStart(tor, {});
+ }
+ else if (tor->isRunning)
+ {
+ tr_torrentStop(tor);
+ }
+ }
+}
+
void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
{
tr_session* session = tr_ctorGetSession(ctor);
@@ -1081,7 +1097,7 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
tor->anyDate = now;
tr_resume::fields_t loaded = {};
- if (tor->hasMetainfo())
+
{
// tr_resume::load() calls a lot of tr_torrentSetFoo() methods
// that set things as dirty, but... these settings being loaded are
@@ -1106,9 +1122,6 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
tor->refreshCurrentDir();
- bool const do_start = tor->isRunning;
- tor->isRunning = false;
-
if ((loaded & tr_resume::Speedlimit) == 0)
{
tor->useSpeedLimit(TR_UP, false);
@@ -1174,37 +1187,14 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
tor->torrent_announcer = session->announcer_->addTorrent(tor, &tr_torrent::onTrackerResponse);
- if (is_new_torrent)
+ if (auto const has_metainfo = tor->hasMetainfo(); is_new_torrent && has_metainfo)
{
- if (tor->hasMetainfo())
- {
- callScriptIfEnabled(tor, TR_SCRIPT_ON_TORRENT_ADDED);
- }
-
- if (!tor->hasMetainfo() && !do_start)
- {
- auto opts = torrent_start_opts{};
- opts.bypass_queue = true;
- opts.has_local_data = has_local_data;
- torrentStart(tor, opts);
- }
- else if (!session->shouldFullyVerifyAddedTorrents() && isNewTorrentASeed(tor))
- {
- tor->completion.setHasAll();
- tor->doneDate = tor->addedDate;
- tor->recheckCompleteness();
- }
- else
- {
- tor->startAfterVerify = do_start;
- tr_torrentVerify(tor);
- }
+ on_metainfo_completed(tor);
}
- else if (do_start)
+ else if (tor->start_when_stable || !has_metainfo)
{
- // if checked_pieces_ got populated from the loading the resume
- // file above, then torrentStart doesn't need to check again
auto opts = torrent_start_opts{};
+ opts.bypass_queue = !has_metainfo; // to fetch metainfo from peers
opts.has_local_data = has_local_data;
torrentStart(tor, opts);
}
@@ -1216,16 +1206,20 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
} // namespace torrent_init_helpers
} // namespace
-void tr_torrent::setMetainfo(tr_torrent_metainfo const& tm)
+void tr_torrent::setMetainfo(tr_torrent_metainfo tm)
{
using namespace torrent_init_helpers;
- metainfo_ = tm;
+ TR_ASSERT(!hasMetainfo());
+ metainfo_ = std::move(tm);
torrentInitFromInfoDict(this);
tr_peerMgrOnTorrentGotMetainfo(this);
session->onMetadataCompleted(this);
this->setDirty();
+ this->markEdited();
+
+ on_metainfo_completed(this);
}
tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of)
@@ -1763,33 +1757,35 @@ void tr_torrentAmountFinished(tr_torrent const* tor, float* tabs, int n_tabs)
// --- Start/Stop Callback
-void tr_torrentStart(tr_torrent* tor)
+namespace
+{
+void tr_torrentStartImpl(tr_torrent* tor, bool bypass_queue)
{
- if (tr_isTorrent(tor))
+ if (!tr_isTorrent(tor))
{
- tor->startAfterVerify = true;
- torrentStart(tor, {});
+ return;
}
+
+ tor->start_when_stable = true;
+ auto opts = torrent_start_opts{};
+ opts.bypass_queue = bypass_queue;
+ torrentStart(tor, opts);
+}
+} // namespace
+
+void tr_torrentStart(tr_torrent* tor)
+{
+ tr_torrentStartImpl(tor, false);
}
void tr_torrentStartNow(tr_torrent* tor)
{
- if (tr_isTorrent(tor))
- {
- auto opts = torrent_start_opts{};
- opts.bypass_queue = true;
- torrentStart(tor, opts);
- }
+ tr_torrentStartImpl(tor, true);
}
void tr_torrentStartMagnet(tr_torrent* tor)
{
- if (tr_isTorrent(tor))
- {
- tor->magnetStartAfterVerify = true;
- tor->startAfterVerify = true;
- torrentStart(tor, {});
- }
+ tr_torrentStart(tor);
}
// ---
@@ -1809,10 +1805,8 @@ void onVerifyDoneThreadFunc(tr_torrent* const tor)
tor->recheckCompleteness();
- if (tor->startAfterVerify)
+ if (tor->start_when_stable)
{
- tor->startAfterVerify = false;
-
auto opts = torrent_start_opts{};
opts.has_local_data = !tor->checked_pieces_.hasNone();
torrentStart(tor, opts);
@@ -1832,20 +1826,18 @@ void verifyTorrent(tr_torrent* const tor)
/* if the torrent's already being verified, stop it */
tor->session->verifyRemove(tor);
- bool const start_after = (tor->isRunning || tor->startAfterVerify) && !tor->isStopping;
-
- if (tor->isRunning)
+ if (!tor->hasMetainfo())
{
- tr_torrentStop(tor);
+ return;
}
- if (setLocalErrorIfFilesDisappeared(tor))
+ if (tor->isRunning)
{
- tor->startAfterVerify = false;
+ torrentStop(tor);
}
- else
+
+ if (!setLocalErrorIfFilesDisappeared(tor))
{
- tor->startAfterVerify = start_after;
tor->session->verifyAdd(tor);
}
}
diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h
index deebb77337..a1a3031aa8 100644
--- a/libtransmission/torrent.h
+++ b/libtransmission/torrent.h
@@ -109,7 +109,8 @@ struct tr_torrent final : public tr_completion::torrent_view
// but more refactoring is needed before that can happen
// because much of tr_torrent's impl is in the non-member C bindings
- void setMetainfo(tr_torrent_metainfo const& tm);
+ // Used to add metainfo to a magnet torrent.
+ void setMetainfo(tr_torrent_metainfo tm);
[[nodiscard]] auto unique_lock() const
{
@@ -903,10 +904,10 @@ struct tr_torrent final : public tr_completion::torrent_view
bool is_queued = false;
bool isRunning = false;
bool isStopping = false;
- bool startAfterVerify = false;
- bool magnetStartAfterVerify = false;
- bool magnetVerify = false;
+ // start the torrent after all the startup scaffolding is done,
+ // e.g. fetching metadata from peers and/or verifying the torrent
+ bool start_when_stable = false;
private:
[[nodiscard]] constexpr bool isPieceTransferAllowed(tr_direction direction) const noexcept
diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h
index 11bb8743dd..82bf1d5e54 100644
--- a/libtransmission/transmission.h
+++ b/libtransmission/transmission.h
@@ -601,7 +601,7 @@ void tr_sessionSetAntiBruteForceEnabled(tr_session* session, bool enabled);
/** @brief Like `tr_torrentStart()`, but resumes right away regardless of the queues. */
void tr_torrentStartNow(tr_torrent* tor);
-/** @brief Like tr_torrentStart(), but sets magnetStartAfterVerify to true. */
+/** @brief DEPRECATED. Equivalent to tr_torrentStart(). Use that instead. */
void tr_torrentStartMagnet(tr_torrent*);
/** @brief Return the queued torrent's position in the queue it's in. [0...n) */
diff --git a/macosx/Torrent.mm b/macosx/Torrent.mm
index bd5ad7972f..98e69882d3 100644
--- a/macosx/Torrent.mm
+++ b/macosx/Torrent.mm
@@ -280,7 +280,7 @@ - (void)startMagnetTransferAfterMetaDownload
{
if ([self alertForRemainingDiskSpace])
{
- tr_torrentStartMagnet(self.fHandle);
+ tr_torrentStart(self.fHandle);
[self update];
//capture, specifically, stop-seeding settings changing to unlimited