diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index b68a94eb4..7bcc23ae8 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -65,6 +65,10 @@ #include #include +#if (LIBTORRENT_VERSION_NUM >= 10200) +#include +#endif + #include "base/algorithm.h" #include "base/exceptions.h" #include "base/global.h" @@ -1843,17 +1847,15 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne params.savePath = normalizeSavePath(params.savePath, ""); if (!params.category.isEmpty()) { - if (!m_categories.contains(params.category) && !addCategory(params.category)) { - qWarning() << "Couldn't create category" << params.category; + if (!m_categories.contains(params.category) && !addCategory(params.category)) params.category = ""; - } } + const bool fromMagnetUri = magnetUri.isValid(); // If empty then Automatic mode, otherwise Manual mode QString savePath = params.savePath.isEmpty() ? categorySavePath(params.category) : params.savePath; lt::add_torrent_params p; InfoHash hash; - const bool fromMagnetUri = magnetUri.isValid(); if (fromMagnetUri) { hash = magnetUri.hash(); @@ -1887,8 +1889,58 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne p = magnetUri.addTorrentParams(); } - else if (torrentInfo.isValid()) { - if (!params.restored) { + else { + if (!torrentInfo.isValid()) { + // We can have an invalid torrentInfo when there isn't a matching + // .torrent file to the .fastresume we loaded. Possibly from a + // failed upgrade. + return false; + } + + hash = torrentInfo.hash(); + } + + // We should not add the torrent if it is already + // processed or is pending to add to session + if (m_addingTorrents.contains(hash) || m_loadedMetadata.contains(hash)) + return false; + + TorrentHandle *const torrent = m_torrents.value(hash); + if (torrent) { // a duplicate torrent is added + if (torrent->isPrivate() || (!fromMagnetUri && torrentInfo.isPrivate())) + return false; + + // merge trackers and web seeds + torrent->addTrackers(fromMagnetUri ? magnetUri.trackers() : torrentInfo.trackers()); + torrent->addUrlSeeds(fromMagnetUri ? magnetUri.urlSeeds() : torrentInfo.urlSeeds()); + return true; + } + + // Record if .fastresume is complete, that is whether it contains + // the required fields to resume a torrent. + bool hasCompleteFastresume = false; + + if (!fromMagnetUri) { + if (params.restored) { // load from existing fastresume +#if (LIBTORRENT_VERSION_NUM < 10200) + p.resume_data = std::vector {fastresumeData.constData() + , (fastresumeData.constData() + fastresumeData.size())}; + p.flags |= lt::add_torrent_params::flag_use_resume_save_path; + + // Still setup the default parameters and let libtorrent handle + // the parameter merging + hasCompleteFastresume = false; +#else + lt::error_code ec; + p = lt::read_resume_data(fastresumeData, ec); + + // libtorrent will always apply `file_priorities` to torrents, + // if the field is present then the fastresume is considered to + // be correctly generated and should be complete. + hasCompleteFastresume = !p.file_priorities.empty(); +#endif + } + else { // new torrent if (!params.hasRootFolder) torrentInfo.stripRootFolder(); @@ -1906,108 +1958,78 @@ bool Session::addTorrent_impl(CreateTorrentParams params, const MagnetUri &magne if (!contentName.isEmpty() && (contentName != torrentInfo.name())) params.name = contentName; } + + Q_ASSERT(p.file_priorities.empty()); + std::transform(params.filePriorities.cbegin(), params.filePriorities.cend() + , std::back_inserter(p.file_priorities), [](const DownloadPriority priority) + { +#if (LIBTORRENT_VERSION_NUM < 10200) + return static_cast(priority); +#else + return static_cast( + static_cast(priority)); +#endif + }); } p.ti = torrentInfo.nativeInfo(); - hash = torrentInfo.hash(); - } - else { - // We can have an invalid torrentInfo when there isn't a matching - // .torrent file to the .fastresume we loaded. Possibly from a - // failed upgrade. - return false; - } - - // We should not add torrent if it already - // processed or adding to session - if (m_addingTorrents.contains(hash) || m_loadedMetadata.contains(hash)) return false; - - TorrentHandle *const torrent = m_torrents.value(hash); - if (torrent) { - if (torrent->isPrivate() || (!fromMagnetUri && torrentInfo.isPrivate())) - return false; - torrent->addTrackers(fromMagnetUri ? magnetUri.trackers() : torrentInfo.trackers()); - torrent->addUrlSeeds(fromMagnetUri ? magnetUri.urlSeeds() : torrentInfo.urlSeeds()); - return true; } - qDebug("Adding torrent..."); - qDebug(" -> Hash: %s", qUtf8Printable(hash)); - - // Preallocation mode - if (isPreallocationEnabled()) - p.storage_mode = lt::storage_mode_allocate; - else - p.storage_mode = lt::storage_mode_sparse; - + if (!hasCompleteFastresume) { + // Common #if (LIBTORRENT_VERSION_NUM < 10200) - p.flags |= lt::add_torrent_params::flag_paused; // Start in pause - p.flags &= ~lt::add_torrent_params::flag_auto_managed; // Because it is added in paused state - p.flags &= ~lt::add_torrent_params::flag_duplicate_is_error; // Already checked + p.flags |= lt::add_torrent_params::flag_paused; // Start in pause + p.flags &= ~lt::add_torrent_params::flag_auto_managed; // Because it is added in paused state + p.flags &= ~lt::add_torrent_params::flag_duplicate_is_error; // Already checked #else - p.flags |= lt::torrent_flags::paused; // Start in pause - p.flags &= ~lt::torrent_flags::auto_managed; // Because it is added in paused state - p.flags &= ~lt::torrent_flags::duplicate_is_error; // Already checked + p.flags |= lt::torrent_flags::paused; // Start in pause + p.flags &= ~lt::torrent_flags::auto_managed; // Because it is added in paused state + p.flags &= ~lt::torrent_flags::duplicate_is_error; // Already checked #endif - // Seeding mode - // Skip checking and directly start seeding (new in libtorrent v0.15) - if (params.skipChecking) { -#if (LIBTORRENT_VERSION_NUM < 10200) - p.flags |= lt::add_torrent_params::flag_seed_mode; -#else - p.flags |= lt::torrent_flags::seed_mode; -#endif - } - else { + // Limits + p.max_connections = maxConnectionsPerTorrent(); + p.max_uploads = maxUploadsPerTorrent(); + p.save_path = Utils::Fs::toNativePath(savePath).toStdString(); + p.upload_limit = params.uploadLimit; + p.download_limit = params.downloadLimit; + + // Preallocation mode + p.storage_mode = isPreallocationEnabled() + ? lt::storage_mode_allocate : lt::storage_mode_sparse; + + // Seeding mode + // Skip checking and directly start seeding + if (params.skipChecking) { #if (LIBTORRENT_VERSION_NUM < 10200) - p.flags &= ~lt::add_torrent_params::flag_seed_mode; + p.flags |= lt::add_torrent_params::flag_seed_mode; #else - p.flags &= ~lt::torrent_flags::seed_mode; + p.flags |= lt::torrent_flags::seed_mode; #endif - } - - if (!fromMagnetUri) { - if (params.restored) { - // Set torrent fast resume data - p.resume_data = std::vector {fastresumeData.constData(), fastresumeData.constData() + fastresumeData.size()}; - p.flags |= lt::add_torrent_params::flag_use_resume_save_path; } else { - Q_ASSERT(p.file_priorities.empty()); - std::transform(params.filePriorities.cbegin(), params.filePriorities.cend() - , std::back_inserter(p.file_priorities), [](DownloadPriority priority) - { #if (LIBTORRENT_VERSION_NUM < 10200) - return static_cast(priority); + p.flags &= ~lt::add_torrent_params::flag_seed_mode; #else - return static_cast( - static_cast(priority)); + p.flags &= ~lt::torrent_flags::seed_mode; #endif - }); } - } - if (params.restored && !params.paused) { - // Make sure the torrent will restored in "paused" state - // Then we will start it if needed + if (params.restored && !params.paused) { + // Make sure the torrent will restored in "paused" state + // Then we will start it if needed #if (LIBTORRENT_VERSION_NUM < 10200) - p.flags |= lt::add_torrent_params::flag_stop_when_ready; + p.flags |= lt::add_torrent_params::flag_stop_when_ready; #else - p.flags |= lt::torrent_flags::stop_when_ready; + p.flags |= lt::torrent_flags::stop_when_ready; #endif + } } - // Limits - p.max_connections = maxConnectionsPerTorrent(); - p.max_uploads = maxUploadsPerTorrent(); - p.save_path = Utils::Fs::toNativePath(savePath).toStdString(); - p.upload_limit = params.uploadLimit; - p.download_limit = params.downloadLimit; - m_addingTorrents.insert(hash, params); // Adding torrent to BitTorrent session m_nativeSession->async_add_torrent(p); + return true; }