From 17b6dcfbef072cee3d7a57901f8ae9ce86459d0e Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Sat, 13 Jan 2024 20:35:46 +0300 Subject: [PATCH] Don't stuck loading on mismatching info-hashes in resume data PR #20262. Closes #20251. --- .../bittorrent/bencoderesumedatastorage.cpp | 10 ++++++ src/base/bittorrent/sessionimpl.cpp | 32 ++++++++++++------- src/base/bittorrent/sessionimpl.h | 5 ++- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/base/bittorrent/bencoderesumedatastorage.cpp b/src/base/bittorrent/bencoderesumedatastorage.cpp index 4e6d0e46e..8ec392c9b 100644 --- a/src/base/bittorrent/bencoderesumedatastorage.cpp +++ b/src/base/bittorrent/bencoderesumedatastorage.cpp @@ -288,6 +288,16 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre return nonstd::make_unexpected(tr("Cannot parse torrent info: %1").arg(QString::fromStdString(ec.message()))); p.ti = torrentInfo; + +#ifdef QBT_USES_LIBTORRENT2 + if (((p.info_hashes.has_v1() && (p.info_hashes.v1 != p.ti->info_hashes().v1)) + || (p.info_hashes.has_v2() && (p.info_hashes.v2 != p.ti->info_hashes().v2)))) +#else + if (!p.info_hash.is_all_zeros() && (p.info_hash != p.ti->info_hash())) +#endif + { + return nonstd::make_unexpected(tr("Mismatching info-hash detected in resume data")); + } } p.save_path = Profile::instance()->fromPortablePath( diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index d4f96515c..730738dd2 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2023 Vladimir Golovnev + * Copyright (C) 2015-2024 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -1217,13 +1217,13 @@ void SessionImpl::prepareStartup() context->isLoadFinished = true; }); - connect(this, &SessionImpl::torrentsLoaded, context, [this, context](const QVector &torrents) + connect(this, &SessionImpl::addTorrentAlertsReceived, context, [this, context](const qsizetype alertsCount) { - context->processingResumeDataCount -= torrents.count(); - context->finishedResumeDataCount += torrents.count(); + context->processingResumeDataCount -= alertsCount; + context->finishedResumeDataCount += alertsCount; if (!context->isLoadedResumeDataHandlingEnqueued) { - QMetaObject::invokeMethod(this, [this, context]() { handleLoadedResumeData(context); }, Qt::QueuedConnection); + QMetaObject::invokeMethod(this, [this, context] { handleLoadedResumeData(context); }, Qt::QueuedConnection); context->isLoadedResumeDataHandlingEnqueued = true; } @@ -5460,11 +5460,14 @@ void SessionImpl::handleAddTorrentAlerts(const std::vector &alerts) if (!isRestored()) loadedTorrents.reserve(MAX_PROCESSING_RESUMEDATA_COUNT); + qsizetype alertsCount = 0; for (const lt::alert *a : alerts) { if (a->type() != lt::add_torrent_alert::alert_type) continue; + ++alertsCount; + const auto *alert = static_cast(a); if (alert->error) { @@ -5474,6 +5477,7 @@ void SessionImpl::handleAddTorrentAlerts(const std::vector &alerts) const lt::add_torrent_params ¶ms = alert->params; const bool hasMetadata = (params.ti && params.ti->is_valid()); + #ifdef QBT_USES_LIBTORRENT2 const InfoHash infoHash {(hasMetadata ? params.ti->info_hashes() : params.info_hashes)}; if (infoHash.isHybrid()) @@ -5498,10 +5502,9 @@ void SessionImpl::handleAddTorrentAlerts(const std::vector &alerts) } } - return; + continue; } - #ifdef QBT_USES_LIBTORRENT2 const InfoHash infoHash {alert->handle.info_hashes()}; #else @@ -5519,7 +5522,7 @@ void SessionImpl::handleAddTorrentAlerts(const std::vector &alerts) loadedTorrents.append(torrent); } else if (const auto downloadedMetadataIter = m_downloadedMetadata.find(torrentID) - ; downloadedMetadataIter != m_downloadedMetadata.end()) + ; downloadedMetadataIter != m_downloadedMetadata.end()) { downloadedMetadataIter.value() = alert->handle; if (infoHash.isHybrid()) @@ -5531,11 +5534,16 @@ void SessionImpl::handleAddTorrentAlerts(const std::vector &alerts) } } - if (!loadedTorrents.isEmpty()) + if (alertsCount > 0) { - if (isRestored()) - m_torrentsQueueChanged = true; - emit torrentsLoaded(loadedTorrents); + emit addTorrentAlertsReceived(alertsCount); + + if (!loadedTorrents.isEmpty()) + { + if (isRestored()) + m_torrentsQueueChanged = true; + emit torrentsLoaded(loadedTorrents); + } } } diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index a8c1f967b..eb8c51854 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2023 Vladimir Golovnev + * Copyright (C) 2015-2024 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -475,6 +475,9 @@ namespace BitTorrent void invokeAsync(std::function func); + signals: + void addTorrentAlertsReceived(qsizetype count); + private slots: void configureDeferred(); void readAlerts();