45 #include <libtorrent/alert_types.hpp>
46 #include <libtorrent/error_code.hpp>
47 #include <libtorrent/extensions/smart_ban.hpp>
48 #include <libtorrent/extensions/ut_metadata.hpp>
49 #include <libtorrent/extensions/ut_pex.hpp>
50 #include <libtorrent/ip_filter.hpp>
51 #include <libtorrent/magnet_uri.hpp>
52 #include <libtorrent/session.hpp>
53 #include <libtorrent/session_stats.hpp>
54 #include <libtorrent/session_status.hpp>
55 #include <libtorrent/torrent_info.hpp>
60 #include <QHostAddress>
62 #include <QJsonDocument>
63 #include <QJsonObject>
65 #include <QNetworkAddressEntry>
66 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
67 #include <QNetworkConfigurationManager>
69 #include <QNetworkInterface>
70 #include <QRegularExpression>
91 #include "base/version.h"
122 handle.queue_position_up();
124 catch (
const std::exception &exc)
126 qDebug() << Q_FUNC_INFO <<
" fails: " << exc.what();
134 handle.queue_position_down();
136 catch (
const std::exception &exc)
138 qDebug() << Q_FUNC_INFO <<
" fails: " << exc.what();
146 handle.queue_position_top();
148 catch (
const std::exception &exc)
150 qDebug() << Q_FUNC_INFO <<
" fails: " << exc.what();
158 handle.queue_position_bottom();
160 catch (
const std::exception &exc)
162 qDebug() << Q_FUNC_INFO <<
" fails: " << exc.what();
166 QMap<QString, CategoryOptions>
expandCategories(
const QMap<QString, CategoryOptions> &categories)
168 QMap<QString, CategoryOptions> expanded = categories;
170 for (
auto i = categories.cbegin(); i != categories.cend(); ++i)
172 const QString &category = i.key();
175 if (!expanded.contains(subcat))
176 expanded[subcat] = {};
183 QString
toString(
const lt::socket_type_t socketType)
187 #ifdef QBT_USES_LIBTORRENT2
188 case lt::socket_type_t::http:
189 return QLatin1String(
"HTTP");
190 case lt::socket_type_t::http_ssl:
191 return QLatin1String(
"HTTP_SSL");
193 case lt::socket_type_t::i2p:
194 return QLatin1String(
"I2P");
195 case lt::socket_type_t::socks5:
196 return QLatin1String(
"SOCKS5");
197 #ifdef QBT_USES_LIBTORRENT2
198 case lt::socket_type_t::socks5_ssl:
199 return QLatin1String(
"SOCKS5_SSL");
201 case lt::socket_type_t::tcp:
202 return QLatin1String(
"TCP");
203 case lt::socket_type_t::tcp_ssl:
204 return QLatin1String(
"TCP_SSL");
205 #ifdef QBT_USES_LIBTORRENT2
206 case lt::socket_type_t::utp:
207 return QLatin1String(
"UTP");
209 case lt::socket_type_t::udp:
210 return QLatin1String(
"UDP");
212 case lt::socket_type_t::utp_ssl:
213 return QLatin1String(
"UTP_SSL");
215 return QLatin1String(
"INVALID");
222 return QString::fromLatin1(address.to_string().c_str());
224 catch (
const std::exception &)
231 template <
typename T>
247 return val <= m_limit ? m_ret : val;
255 template <
typename T>
258 template <
typename T>
261 template <
typename T>
264 return [lower, upper](
const T
value) -> T
275 QString convertIfaceNameToGuid(
const QString &name)
278 const QUuid uuid(name);
280 return uuid.toString().toUpper();
283 const LONG res = ::ConvertInterfaceNameToLuidW(name.toStdWString().c_str(), &luid);
287 if (::ConvertInterfaceLuidToGuid(&luid, &guid) == 0)
288 return QUuid(guid).toString().toUpper();
302 #define BITTORRENT_KEY(name) "BitTorrent/" name
303 #define BITTORRENT_SESSION_KEY(name) BITTORRENT_KEY("Session/") name
392 ,
clampValue(ChokingAlgorithm::FixedSlots, ChokingAlgorithm::RateBased))
393 , m_seedChokingAlgorithm(
BITTORRENT_SESSION_KEY(
"SeedChokingAlgorithm"), SeedChokingAlgorithm::FastestUpload
394 ,
clampValue(SeedChokingAlgorithm::RoundRobin, SeedChokingAlgorithm::AntiLeech))
402 , m_isDisableAutoTMMWhenCategoryChanged(
BITTORRENT_SESSION_KEY(
"DisableAutoTMMTriggers/CategoryChanged"),
false)
403 , m_isDisableAutoTMMWhenDefaultSavePathChanged(
BITTORRENT_SESSION_KEY(
"DisableAutoTMMTriggers/DefaultSavePathChanged"),
true)
404 , m_isDisableAutoTMMWhenCategorySavePathChanged(
BITTORRENT_SESSION_KEY(
"DisableAutoTMMTriggers/CategorySavePathChanged"),
true)
409 , m_bannedIPs(
"State/BannedIPs"
411 , [](
const QStringList &
value)
413 QStringList tmp =
value;
419 #
if defined(Q_OS_WIN)
420 , m_OSMemoryPriority(
BITTORRENT_KEY(
"OSMemoryPriority"), OSMemoryPriority::BelowNormal)
422 , m_seedingLimitTimer {
new QTimer {
this}}
423 , m_resumeDataTimer {
new QTimer {
this}}
425 , m_ioThread {
new QThread {
this}}
426 , m_recentErroredTorrentsTimer {
new QTimer {
this}}
427 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
428 , m_networkManager {
new QNetworkConfigurationManager {
this}}
434 m_recentErroredTorrentsTimer->setSingleShot(
true);
435 m_recentErroredTorrentsTimer->setInterval(1000);
436 connect(m_recentErroredTorrentsTimer, &QTimer::timeout
437 ,
this, [
this]() { m_recentErroredTorrents.clear(); });
439 m_seedingLimitTimer->setInterval(10000);
442 initializeNativeSession();
443 configureComponents();
445 if (isBandwidthSchedulerEnabled())
446 enableBandwidthScheduler();
449 if (isSubcategoriesEnabled())
455 const QStringList storedTags = m_storedTags.get();
456 m_tags = {storedTags.cbegin(), storedTags.cend()};
459 updateSeedingLimitTimer();
460 populateAdditionalTrackers();
462 enableTracker(isTrackerEnabled());
468 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
470 connect(m_networkManager, &QNetworkConfigurationManager::onlineStateChanged,
this, &Session::networkOnlineStateChanged);
471 connect(m_networkManager, &QNetworkConfigurationManager::configurationAdded,
this, &Session::networkConfigurationChange);
472 connect(m_networkManager, &QNetworkConfigurationManager::configurationRemoved,
this, &Session::networkConfigurationChange);
473 connect(m_networkManager, &QNetworkConfigurationManager::configurationChanged,
this, &Session::networkConfigurationChange);
477 m_fileSearcher->moveToThread(m_ioThread);
478 connect(m_ioThread, &QThread::finished, m_fileSearcher, &QObject::deleteLater);
484 connect(m_resumeDataTimer, &QTimer::timeout,
this, [
this]() { generateResumeData(); });
485 const int saveInterval = saveResumeDataInterval();
486 if (saveInterval > 0)
488 m_resumeDataTimer->setInterval(saveInterval * 60 * 1000);
489 m_resumeDataTimer->start();
509 LogMsg(tr(
"DHT support [%1]").arg(enabled ? tr(
"ON") : tr(
"OFF")),
Log::INFO);
524 LogMsg(tr(
"Local Peer Discovery support [%1]").arg(enabled ? tr(
"ON") : tr(
"OFF"))
552 torrent->handleDownloadPathChanged();
569 torrent->handleAppendExtensionToggled();
632 static const QRegularExpression re(R
"(^([^\\\/]|[^\\\/]([^\\\/]|\/(?=[^\/]))*[^\\\/])$)");
633 if (!name.isEmpty() && (name.indexOf(re) != 0))
635 qDebug() <<
"Incorrect category name:" << name;
649 while ((index = category.indexOf(
'/', index)) >= 0)
651 result << category.left(index);
671 const QString basePath =
savePath();
672 if (categoryName.isEmpty())
675 QString path =
m_categories.value(categoryName).savePath;
687 if (!downloadPathOption.
enabled)
691 if (categoryName.isEmpty())
694 const QString path = (!downloadPathOption.
path.isEmpty()
695 ? downloadPathOption.
path
735 if (options == currentOptions)
738 currentOptions = options;
744 if (torrent->category() == name)
745 torrent->setAutoTMMEnabled(
false);
752 if (torrent->category() == name)
753 torrent->handleCategoryOptionsChanged();
764 if (torrent->belongsToCategory(name))
765 torrent->setCategory(
"");
773 const QString
test = name +
'/';
776 if (category.startsWith(
test))
779 emit categoryRemoved(category);
831 return (!tag.trimmed().isEmpty() && !tag.contains(
','));
836 return m_tags.contains(tag);
855 torrent->removeTag(tag);
978 qDebug(
"Deleting the session");
1047 #if defined(Q_OS_WIN)
1048 applyOSMemoryPriority();
1054 const lt::alert_category_t alertMask = lt::alert::error_notification
1055 | lt::alert::file_progress_notification
1056 | lt::alert::ip_block_notification
1057 | lt::alert::peer_notification
1058 | lt::alert::performance_warning
1059 | lt::alert::port_mapping_notification
1060 | lt::alert::status_notification
1061 | lt::alert::storage_notification
1062 | lt::alert::tracker_notification;
1063 const std::string peerId = lt::generate_fingerprint(
PEER_ID, QBT_VERSION_MAJOR, QBT_VERSION_MINOR, QBT_VERSION_BUGFIX, QBT_VERSION_BUILD);
1065 lt::settings_pack pack;
1066 pack.set_int(lt::settings_pack::alert_mask, alertMask);
1067 pack.set_str(lt::settings_pack::peer_fingerprint, peerId);
1068 pack.set_bool(lt::settings_pack::listen_system_port_fallback,
false);
1070 pack.set_bool(lt::settings_pack::use_dht_as_fallback,
false);
1072 pack.set_int(lt::settings_pack::auto_scrape_interval, 1200);
1073 pack.set_int(lt::settings_pack::auto_scrape_min_interval, 900);
1076 pack.set_bool(lt::settings_pack::enable_upnp,
false);
1077 pack.set_bool(lt::settings_pack::enable_natpmp,
false);
1079 #ifdef QBT_USES_LIBTORRENT2
1081 pack.set_bool(lt::settings_pack::enable_set_file_valid_data,
true);
1085 lt::session_params sessionParams {pack, {}};
1086 #ifdef QBT_USES_LIBTORRENT2
1087 sessionParams.disk_io_constructor = customDiskIOConstructor;
1091 LogMsg(tr(
"Peer ID: ") + QString::fromStdString(peerId));
1111 m_nativeSession->add_extension(std::make_shared<NativeSessionExtension>());
1120 const lt::address addr = lt::make_address(ip.toLatin1().constData(), ec);
1123 filter.add_rule(addr, addr, lt::ip_filter::blocked);
1133 settingsPack.set_int(lt::settings_pack::active_downloads
1134 , maxDownloads > -1 ? maxDownloads +
m_extraLimit : maxDownloads);
1135 settingsPack.set_int(lt::settings_pack::active_limit
1136 , maxActive > -1 ? maxActive +
m_extraLimit : maxActive);
1148 const auto findMetricIndex = [](
const char *name) ->
int
1150 const int index = lt::find_metric_idx(name);
1151 Q_ASSERT(index >= 0);
1178 #ifndef QBT_USES_LIBTORRENT2
1190 settingsPack.set_int(lt::settings_pack::connection_speed,
connectionSpeed());
1194 settingsPack.set_int(lt::settings_pack::listen_queue_size,
socketBacklogSize());
1200 settingsPack.set_int(lt::settings_pack::allowed_enc_level, lt::settings_pack::pe_rc4);
1201 settingsPack.set_bool(lt::settings_pack::prefer_rc4,
true);
1205 settingsPack.set_int(lt::settings_pack::out_enc_policy, lt::settings_pack::pe_enabled);
1206 settingsPack.set_int(lt::settings_pack::in_enc_policy, lt::settings_pack::pe_enabled);
1209 settingsPack.set_int(lt::settings_pack::out_enc_policy, lt::settings_pack::pe_forced);
1210 settingsPack.set_int(lt::settings_pack::in_enc_policy, lt::settings_pack::pe_forced);
1213 settingsPack.set_int(lt::settings_pack::out_enc_policy, lt::settings_pack::pe_disabled);
1214 settingsPack.set_int(lt::settings_pack::in_enc_policy, lt::settings_pack::pe_disabled);
1221 switch (proxyConfig.
type)
1224 settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http);
1227 settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::http_pw);
1230 settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks4);
1233 settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks5);
1236 settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks5_pw);
1240 settingsPack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::none);
1245 settingsPack.set_str(lt::settings_pack::proxy_hostname, proxyConfig.
ip.toStdString());
1246 settingsPack.set_int(lt::settings_pack::proxy_port, proxyConfig.
port);
1248 if (proxyManager->isAuthenticationRequired())
1250 settingsPack.set_str(lt::settings_pack::proxy_username, proxyConfig.
username.toStdString());
1251 settingsPack.set_str(lt::settings_pack::proxy_password, proxyConfig.
password.toStdString());
1258 settingsPack.set_bool(lt::settings_pack::announce_to_all_tiers,
announceToAllTiers());
1260 settingsPack.set_int(lt::settings_pack::peer_turnover,
peerTurnover());
1264 settingsPack.set_int(lt::settings_pack::aio_threads,
asyncIOThreads());
1265 #ifdef QBT_USES_LIBTORRENT2
1266 settingsPack.set_int(lt::settings_pack::hashing_threads,
hashingThreads());
1268 settingsPack.set_int(lt::settings_pack::file_pool_size,
filePoolSize());
1271 settingsPack.set_int(lt::settings_pack::checking_mem_usage, checkingMemUsageSize);
1273 #ifndef QBT_USES_LIBTORRENT2
1275 settingsPack.set_int(lt::settings_pack::cache_size, cacheSize);
1276 settingsPack.set_int(lt::settings_pack::cache_expiry,
diskCacheTTL());
1279 lt::settings_pack::io_buffer_mode_t mode =
useOSCache() ? lt::settings_pack::enable_os_cache
1280 : lt::settings_pack::disable_os_cache;
1281 settingsPack.set_int(lt::settings_pack::disk_io_read_mode, mode);
1282 settingsPack.set_int(lt::settings_pack::disk_io_write_mode, mode);
1284 #ifndef QBT_USES_LIBTORRENT2
1292 ? lt::settings_pack::suggest_read_cache : lt::settings_pack::no_piece_suggestions);
1294 settingsPack.set_int(lt::settings_pack::send_buffer_watermark,
sendBufferWatermark() * 1024);
1313 settingsPack.set_int(lt::settings_pack::active_downloads, -1);
1314 settingsPack.set_int(lt::settings_pack::active_seeds, -1);
1315 settingsPack.set_int(lt::settings_pack::active_limit, -1);
1317 settingsPack.set_int(lt::settings_pack::active_tracker_limit, -1);
1318 settingsPack.set_int(lt::settings_pack::active_dht_limit, -1);
1319 settingsPack.set_int(lt::settings_pack::active_lsd_limit, -1);
1320 settingsPack.set_int(lt::settings_pack::alert_queue_size, std::numeric_limits<int>::max() / 2);
1323 settingsPack.set_int(lt::settings_pack::outgoing_port,
outgoingPortsMin());
1326 settingsPack.set_int(lt::settings_pack::upnp_lease_duration,
UPnPLeaseDuration());
1328 settingsPack.set_int(lt::settings_pack::peer_tos,
peerToS());
1332 settingsPack.set_str(lt::settings_pack::announce_ip,
announceIP().toStdString());
1338 settingsPack.set_int(lt::settings_pack::connections_limit,
maxConnections());
1340 settingsPack.set_int(lt::settings_pack::unchoke_slots_limit,
maxUploads());
1344 case BTProtocol::Both:
1346 settingsPack.set_bool(lt::settings_pack::enable_incoming_tcp,
true);
1347 settingsPack.set_bool(lt::settings_pack::enable_outgoing_tcp,
true);
1348 settingsPack.set_bool(lt::settings_pack::enable_incoming_utp,
true);
1349 settingsPack.set_bool(lt::settings_pack::enable_outgoing_utp,
true);
1352 case BTProtocol::TCP:
1353 settingsPack.set_bool(lt::settings_pack::enable_incoming_tcp,
true);
1354 settingsPack.set_bool(lt::settings_pack::enable_outgoing_tcp,
true);
1355 settingsPack.set_bool(lt::settings_pack::enable_incoming_utp,
false);
1356 settingsPack.set_bool(lt::settings_pack::enable_outgoing_utp,
false);
1359 case BTProtocol::UTP:
1360 settingsPack.set_bool(lt::settings_pack::enable_incoming_tcp,
false);
1361 settingsPack.set_bool(lt::settings_pack::enable_outgoing_tcp,
false);
1362 settingsPack.set_bool(lt::settings_pack::enable_incoming_utp,
true);
1363 settingsPack.set_bool(lt::settings_pack::enable_outgoing_utp,
true);
1369 case MixedModeAlgorithm::TCP:
1371 settingsPack.set_int(lt::settings_pack::mixed_mode_algorithm, lt::settings_pack::prefer_tcp);
1373 case MixedModeAlgorithm::Proportional:
1374 settingsPack.set_int(lt::settings_pack::mixed_mode_algorithm, lt::settings_pack::peer_proportional);
1390 settingsPack.set_bool(lt::settings_pack::enable_dht,
isDHTEnabled());
1392 settingsPack.set_str(lt::settings_pack::dht_bootstrap_nodes,
"dht.libtorrent.org:25401,router.bittorrent.com:6881,router.utorrent.com:6881,dht.transmissionbt.com:6881,dht.aelitis.com:6881");
1393 settingsPack.set_bool(lt::settings_pack::enable_lsd,
isLSDEnabled());
1397 case ChokingAlgorithm::FixedSlots:
1399 settingsPack.set_int(lt::settings_pack::choking_algorithm, lt::settings_pack::fixed_slots_choker);
1401 case ChokingAlgorithm::RateBased:
1402 settingsPack.set_int(lt::settings_pack::choking_algorithm, lt::settings_pack::rate_based_choker);
1408 case SeedChokingAlgorithm::RoundRobin:
1409 settingsPack.set_int(lt::settings_pack::seed_choking_algorithm, lt::settings_pack::round_robin);
1411 case SeedChokingAlgorithm::FastestUpload:
1413 settingsPack.set_int(lt::settings_pack::seed_choking_algorithm, lt::settings_pack::fastest_upload);
1415 case SeedChokingAlgorithm::AntiLeech:
1416 settingsPack.set_int(lt::settings_pack::seed_choking_algorithm, lt::settings_pack::anti_leech);
1427 settingsPack.set_int(lt::settings_pack::max_retry_port_bind, 0);
1429 QStringList endpoints;
1430 QStringList outgoingInterfaces;
1431 const QString portString =
':' + QString::number(
port());
1435 const QHostAddress addr {ip};
1438 const bool isIPv6 = (addr.protocol() == QAbstractSocket::IPv6Protocol);
1439 const QString ip = isIPv6
1443 endpoints << ((isIPv6 ? (
'[' + ip +
']') : ip) + portString);
1445 if ((ip != QLatin1String(
"0.0.0.0")) && (ip != QLatin1String(
"::")))
1446 outgoingInterfaces << ip;
1455 const QString guid = convertIfaceNameToGuid(ip);
1456 if (!guid.isEmpty())
1458 endpoints << (guid + portString);
1459 outgoingInterfaces << guid;
1466 endpoints << (ip + portString);
1467 outgoingInterfaces << ip;
1470 endpoints << (ip + portString);
1471 outgoingInterfaces << ip;
1476 const QString finalEndpoints = endpoints.join(
',');
1477 settingsPack.set_str(lt::settings_pack::listen_interfaces, finalEndpoints.toStdString());
1478 LogMsg(tr(
"Trying to listen on: %1",
"e.g: Trying to listen on: 192.168.0.1:6881")
1481 settingsPack.set_str(lt::settings_pack::outgoing_interfaces, outgoingInterfaces.join(
',').toStdString());
1491 f.add_rule(lt::address_v4::any()
1492 , lt::address_v4::broadcast()
1500 f.add_rule(lt::address_v6::any()
1501 , lt::make_address(
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
1504 catch (
const std::exception &) {}
1509 f.add_rule(lt::make_address(
"10.0.0.0")
1510 , lt::make_address(
"10.255.255.255")
1512 f.add_rule(lt::make_address(
"172.16.0.0")
1513 , lt::make_address(
"172.31.255.255")
1515 f.add_rule(lt::make_address(
"192.168.0.0")
1516 , lt::make_address(
"192.168.255.255")
1519 f.add_rule(lt::make_address(
"169.254.0.0")
1520 , lt::make_address(
"169.254.255.255")
1523 f.add_rule(lt::make_address(
"127.0.0.0")
1524 , lt::make_address(
"127.255.255.255")
1533 f.add_rule(lt::make_address(
"fe80::")
1534 , lt::make_address(
"febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
1537 f.add_rule(lt::make_address(
"fc00::")
1538 , lt::make_address(
"fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
1541 f.add_rule(lt::address_v6::loopback()
1542 , lt::address_v6::loopback()
1545 catch (
const std::exception &) {}
1549 lt::peer_class_type_filter peerClassTypeFilter;
1550 peerClassTypeFilter.add(lt::peer_class_type_filter::tcp_socket, lt::session::tcp_peer_class_id);
1551 peerClassTypeFilter.add(lt::peer_class_type_filter::ssl_tcp_socket, lt::session::tcp_peer_class_id);
1552 peerClassTypeFilter.add(lt::peer_class_type_filter::i2p_socket, lt::session::tcp_peer_class_id);
1555 peerClassTypeFilter.disallow(lt::peer_class_type_filter::utp_socket
1556 , lt::session::global_peer_class_id);
1557 peerClassTypeFilter.disallow(lt::peer_class_type_filter::ssl_utp_socket
1558 , lt::session::global_peer_class_id);
1594 for (QStringView tracker :
asConst(QStringView(trackers).split(u
'\n')))
1596 tracker = tracker.trimmed();
1597 if (!tracker.isEmpty())
1604 qDebug(
"Processing share limits...");
1611 if (torrent->isSeed() && !torrent->isForced())
1615 const qreal ratio = torrent->realRatio();
1616 qreal ratioLimit = torrent->ratioLimit();
1621 if (ratioLimit >= 0)
1623 qDebug(
"Ratio: %f (limit: %f)", ratio, ratioLimit);
1629 LogMsg(tr(
"'%1' reached the maximum ratio you set. Removed.").arg(torrent->name()));
1634 LogMsg(tr(
"'%1' reached the maximum ratio you set. Removed torrent and its files.").arg(torrent->name()));
1640 LogMsg(tr(
"'%1' reached the maximum ratio you set. Paused.").arg(torrent->name()));
1644 torrent->setSuperSeeding(
true);
1645 LogMsg(tr(
"'%1' reached the maximum ratio you set. Enabled super seeding for it.").arg(torrent->name()));
1654 const qlonglong seedingTimeInMinutes = torrent->finishedTime() / 60;
1655 int seedingTimeLimit = torrent->seedingTimeLimit();
1662 if (seedingTimeLimit >= 0)
1668 LogMsg(tr(
"'%1' reached the maximum seeding time you set. Removed.").arg(torrent->name()));
1673 LogMsg(tr(
"'%1' reached the maximum seeding time you set. Removed torrent and its files.").arg(torrent->name()));
1679 LogMsg(tr(
"'%1' reached the maximum seeding time you set. Paused.").arg(torrent->name()));
1683 torrent->setSuperSeeding(
true);
1684 LogMsg(tr(
"'%1' reached the maximum seeding time you set. Enabled super seeding for it.").arg(torrent->name()));
1700 if (
const nonstd::expected<TorrentInfo, QString> loadResult =
TorrentInfo::load(result.
data); loadResult)
1734 for (
int i = 0; i < fileNames.size(); ++i)
1735 p.renamed_files[nativeIndexes[i]] = fileNames[i].toStdString();
1751 return TorrentFilter::ActiveTorrent.match(torrent);
1759 return (!torrent->isSeed() && !torrent->isPaused() && !torrent->isErrored());
1767 return (torrent->isSeed() && !torrent->isPaused());
1778 const lt::address addr = lt::make_address(ip.toLatin1().constData(), ec);
1781 filter.add_rule(addr, addr, lt::ip_filter::blocked);
1795 if (!torrent)
return false;
1797 qDebug(
"Deleting torrent with ID: %s", qUtf8Printable(torrent->
id().
toString()));
1805 const lt::torrent_handle nativeHandle {torrent->
nativeHandle()};
1809 return job.torrentHandle == nativeHandle;
1815 nativeHandle.unset_flags(lt::torrent_flags::auto_managed);
1816 nativeHandle.pause();
1820 m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile);
1834 return job.torrentHandle == torrent->nativeHandle();
1864 using ElementType = std::pair<int, const TorrentImpl *>;
1865 std::priority_queue<ElementType
1866 , std::vector<ElementType>
1867 , std::greater<ElementType>> torrentQueue;
1873 if (!torrent)
continue;
1874 if (
const int position = torrent->
queuePosition(); position >= 0)
1875 torrentQueue.emplace(position, torrent);
1879 while (!torrentQueue.empty())
1881 const TorrentImpl *torrent = torrentQueue.top().second;
1891 using ElementType = std::pair<int, const TorrentImpl *>;
1892 std::priority_queue<ElementType> torrentQueue;
1898 if (!torrent)
continue;
1899 if (
const int position = torrent->
queuePosition(); position >= 0)
1900 torrentQueue.emplace(position, torrent);
1904 while (!torrentQueue.empty())
1906 const TorrentImpl *torrent = torrentQueue.top().second;
1919 using ElementType = std::pair<int, const TorrentImpl *>;
1920 std::priority_queue<ElementType> torrentQueue;
1926 if (!torrent)
continue;
1927 if (
const int position = torrent->
queuePosition(); position >= 0)
1928 torrentQueue.emplace(position, torrent);
1932 while (!torrentQueue.empty())
1934 const TorrentImpl *torrent = torrentQueue.top().second;
1944 using ElementType = std::pair<int, const TorrentImpl *>;
1945 std::priority_queue<ElementType
1946 , std::vector<ElementType>
1947 , std::greater<ElementType>> torrentQueue;
1953 if (!torrent)
continue;
1954 if (
const int position = torrent->
queuePosition(); position >= 0)
1955 torrentQueue.emplace(position, torrent);
1959 while (!torrentQueue.empty())
1961 const TorrentImpl *torrent = torrentQueue.top().second;
1976 QMetaObject::invokeMethod(
this, [
this]()
1985 }, Qt::QueuedConnection);
1993 qDebug(
"Saving resume data is requested for torrent '%s'...", qUtf8Printable(torrent->
name()));
1999 QVector<Torrent *> result;
2013 LogMsg(tr(
"Downloading '%1', please wait...",
"e.g: Downloading 'xxx.torrent', please wait...").arg(
source));
2022 if (magnetUri.isValid())
2033 guard.markAsAddedToSession();
2034 return addTorrent(loadResult.value(), params);
2039 if (!magnetUri.
isValid())
return false;
2053 loadTorrentParams.
name = addTorrentParams.
name;
2058 loadTorrentParams.
operatingMode = (addTorrentParams.
addForced ? TorrentOperatingMode::Forced : TorrentOperatingMode::AutoManaged);
2065 loadTorrentParams.
savePath = (QDir::isAbsolutePath(addTorrentParams.
savePath)
2070 if (useDownloadPath)
2078 const QString category = addTorrentParams.
category;
2082 loadTorrentParams.
category = category;
2084 for (
const QString &tag : addTorrentParams.
tags)
2087 loadTorrentParams.
tags.insert(tag);
2090 return loadTorrentParams;
2096 const bool hasMetadata = std::holds_alternative<TorrentInfo>(
source);
2142 bool isFindingIncompleteFiles =
false;
2144 const bool useAutoTMM = loadTorrentParams.
useAutoTMM;
2153 if (loadTorrentParams.
name.isEmpty())
2155 QString contentName = torrentInfo.
rootFolder();
2156 if (contentName.isEmpty() && (torrentInfo.
filesCount() == 1))
2159 if (!contentName.isEmpty() && (contentName != torrentInfo.
name()))
2160 loadTorrentParams.
name = contentName;
2172 const QString actualDownloadPath = useAutoTMM
2175 isFindingIncompleteFiles =
true;
2179 if (!filePaths.isEmpty())
2181 for (
int index = 0; index < addTorrentParams.
filePaths.size(); ++index)
2185 Q_ASSERT(p.file_priorities.empty());
2186 const int internalFilesCount = torrentInfo.
nativeInfo()->files().num_files();
2200 if (loadTorrentParams.
name.isEmpty() && !p.name.empty())
2201 loadTorrentParams.
name = QString::fromStdString(p.name);
2213 p.flags |= lt::torrent_flags::sequential_download;
2215 p.flags &= ~lt::torrent_flags::sequential_download;
2220 p.flags |= lt::torrent_flags::seed_mode;
2222 p.flags &= ~lt::torrent_flags::seed_mode;
2224 if (loadTorrentParams.
stopped || (loadTorrentParams.
operatingMode == TorrentOperatingMode::AutoManaged))
2225 p.flags |= lt::torrent_flags::paused;
2227 p.flags &= ~lt::torrent_flags::paused;
2228 if (loadTorrentParams.
stopped || (loadTorrentParams.
operatingMode == TorrentOperatingMode::Forced))
2229 p.flags &= ~lt::torrent_flags::auto_managed;
2231 p.flags |= lt::torrent_flags::auto_managed;
2233 p.added_time = std::time(
nullptr);
2235 if (!isFindingIncompleteFiles)
2247 #ifndef QBT_USES_LIBTORRENT2
2254 const bool hasMetadata = (p.ti && p.ti->is_valid());
2255 #ifdef QBT_USES_LIBTORRENT2
2269 ,
const QString &downloadPath,
const QStringList &filePaths)
const
2271 Q_ASSERT(filePaths.isEmpty() || (filePaths.size() == torrentInfo.
filesCount()));
2274 const QStringList originalFileNames = (filePaths.isEmpty() ? torrentInfo.
filePaths() : filePaths);
2285 if (!magnetUri.
isValid())
return false;
2288 const QString name = magnetUri.
name();
2296 qDebug(
"Adding torrent to preload metadata...");
2297 qDebug(
" -> Torrent ID: %s", qUtf8Printable(
id.
toString()));
2298 qDebug(
" -> Name: %s", qUtf8Printable(name));
2305 p.storage_mode = lt::storage_mode_allocate;
2307 p.storage_mode = lt::storage_mode_sparse;
2317 p.flags &= ~lt::torrent_flags::paused;
2318 p.flags &= ~lt::torrent_flags::auto_managed;
2321 p.flags |= lt::torrent_flags::upload_mode;
2323 #ifndef QBT_USES_LIBTORRENT2
2330 if (ec)
return false;
2343 QString torrentExportFilename = QString::fromLatin1(
"%1.torrent").arg(validName);
2344 const QDir exportDir {folderPath};
2345 if (exportDir.exists() || exportDir.mkpath(exportDir.absolutePath()))
2347 QString newTorrentPath = exportDir.absoluteFilePath(torrentExportFilename);
2349 while (QFile::exists(newTorrentPath))
2352 torrentExportFilename = QString::fromLatin1(
"%1 %2.torrent").arg(validName).arg(++counter);
2353 newTorrentPath = exportDir.absoluteFilePath(torrentExportFilename);
2356 const nonstd::expected<void, QString> result = torrentInfo.
saveToFile(newTorrentPath);
2359 LogMsg(tr(
"Couldn't export torrent metadata file '%1'. Reason: %2.")
2369 if (!torrent->isValid())
continue;
2371 if (torrent->needSaveResumeData())
2373 torrent->saveResumeData();
2391 const std::vector<lt::alert *> alerts =
getPendingAlerts(lt::seconds {30});
2394 LogMsg(tr(
"Error: Aborted saving resume data for %1 outstanding torrents.").arg(QString::number(
m_numResumeData))
2399 for (
const lt::alert *a : alerts)
2403 case lt::save_resume_data_failed_alert::alert_type:
2404 case lt::save_resume_data_alert::alert_type:
2414 QVector<TorrentID> queue;
2421 if (queuePos >= queue.size())
2422 queue.resize(queuePos + 1);
2423 queue[queuePos] = torrent->id();
2438 const QString resolvedPath = (QDir::isAbsolutePath(path) ? path :
Utils::Fs::resolvePath(path, baseSavePath));
2446 torrent->setAutoTMMEnabled(
false);
2451 torrent->handleCategoryOptionsChanged();
2458 const QString resolvedPath = (QDir::isAbsolutePath(path) ? path :
Utils::Fs::resolvePath(path, baseDownloadPath));
2464 torrent->handleDownloadPathChanged();
2468 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
2469 void Session::networkOnlineStateChanged(
const bool online)
2471 LogMsg(tr(
"System network status changed to %1",
"e.g: System network status changed to ONLINE").arg(online ? tr(
"ONLINE") : tr(
"OFFLINE")),
Log::INFO);
2474 void Session::networkConfigurationChange(
const QNetworkConfiguration &cfg)
2479 if (configuredInterfaceName.isEmpty())
return;
2481 const QString changedInterface = cfg.name();
2483 if (configuredInterfaceName == changedInterface)
2485 LogMsg(tr(
"Network configuration of %1 has changed, refreshing session binding",
"e.g: Network configuration of tun0 has changed, refreshing session binding").arg(changedInterface),
Log::INFO);
2497 const QHostAddress configuredAddr(ifaceAddr);
2498 const bool allIPv4 = (ifaceAddr == QLatin1String(
"0.0.0.0"));
2499 const bool allIPv6 = (ifaceAddr == QLatin1String(
"::"));
2501 if (!ifaceAddr.isEmpty() && !allIPv4 && !allIPv6 && configuredAddr.isNull())
2503 LogMsg(tr(
"Configured network interface address %1 isn't valid.",
"Configured network interface address 124.5.158.1 isn't valid.").arg(ifaceAddr),
Log::CRITICAL);
2508 IPs.append(ifaceAddr);
2512 if (ifaceName.isEmpty())
2514 if (ifaceAddr.isEmpty())
2515 return {QLatin1String(
"0.0.0.0"), QLatin1String(
"::")};
2518 return {QLatin1String(
"0.0.0.0")};
2521 return {QLatin1String(
"::")};
2524 const auto checkAndAddIP = [allIPv4, allIPv6, &IPs](
const QHostAddress &addr,
const QHostAddress &match)
2526 if ((allIPv4 && (addr.protocol() != QAbstractSocket::IPv4Protocol))
2527 || (allIPv6 && (addr.protocol() != QAbstractSocket::IPv6Protocol)))
2530 if ((match == addr) || allIPv4 || allIPv6)
2531 IPs.append(addr.toString());
2534 if (ifaceName.isEmpty())
2536 const QList<QHostAddress> addresses = QNetworkInterface::allAddresses();
2537 for (
const auto &addr : addresses)
2538 checkAndAddIP(addr, configuredAddr);
2544 LogMsg(tr(
"Can't find the configured address '%1' to listen on"
2545 ,
"Can't find the configured address '192.168.1.3' to listen on")
2547 IPs.append(ifaceAddr);
2554 const QNetworkInterface networkIFace = QNetworkInterface::interfaceFromName(ifaceName);
2555 if (!networkIFace.isValid())
2557 qDebug(
"Invalid network interface: %s", qUtf8Printable(ifaceName));
2559 IPs.append(ifaceName);
2563 if (ifaceAddr.isEmpty())
2565 IPs.append(ifaceName);
2569 const QList<QNetworkAddressEntry> addresses = networkIFace.addressEntries();
2570 qDebug() <<
"This network interface has " << addresses.size() <<
" IP addresses";
2571 for (
const QNetworkAddressEntry &entry : addresses)
2572 checkAndAddIP(entry.ip(), configuredAddr);
2579 LogMsg(tr(
"Can't find the configured address '%1' to listen on"
2580 ,
"Can't find the configured address '192.168.1.3' to listen on")
2582 IPs.append(ifaceAddr);
2612 else if (limit <= 1024)
2637 else if (limit <= 1024)
2662 else if (limit <= 1024)
2687 else if (limit <= 1024)
2848 LogMsg(tr(
"Encryption support [%1]").arg(
2849 state == 0 ? tr(
"ON") : ((state == 1) ? tr(
"FORCED") : tr(
"OFF")))
2954 QStringList filteredList;
2955 for (
const QString &ip : newList)
2962 filteredList << QHostAddress(ip).toString();
2966 LogMsg(tr(
"%1 is not a valid IP address and was rejected while applying the list of banned IP addresses.")
2972 filteredList.sort();
2973 filteredList.removeDuplicates();
3000 #if defined(Q_OS_WIN)
3001 OSMemoryPriority Session::getOSMemoryPriority()
const
3003 return m_OSMemoryPriority;
3006 void Session::setOSMemoryPriority(
const OSMemoryPriority priority)
3008 if (m_OSMemoryPriority == priority)
3011 m_OSMemoryPriority = priority;
3015 void Session::applyOSMemoryPriority()
const
3017 using SETPROCESSINFORMATION = BOOL (WINAPI *)(HANDLE, PROCESS_INFORMATION_CLASS, LPVOID, DWORD);
3018 const auto setProcessInformation = Utils::Misc::loadWinAPI<SETPROCESSINFORMATION>(
"Kernel32.dll",
"SetProcessInformation");
3019 if (!setProcessInformation)
3022 #if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
3024 struct MEMORY_PRIORITY_INFORMATION
3026 ULONG MemoryPriority;
3029 #define MEMORY_PRIORITY_LOWEST 0
3030 #define MEMORY_PRIORITY_VERY_LOW 1
3031 #define MEMORY_PRIORITY_LOW 2
3032 #define MEMORY_PRIORITY_MEDIUM 3
3033 #define MEMORY_PRIORITY_BELOW_NORMAL 4
3034 #define MEMORY_PRIORITY_NORMAL 5
3037 MEMORY_PRIORITY_INFORMATION prioInfo {};
3038 switch (getOSMemoryPriority())
3040 case OSMemoryPriority::Normal:
3042 prioInfo.MemoryPriority = MEMORY_PRIORITY_NORMAL;
3044 case OSMemoryPriority::BelowNormal:
3045 prioInfo.MemoryPriority = MEMORY_PRIORITY_BELOW_NORMAL;
3047 case OSMemoryPriority::Medium:
3048 prioInfo.MemoryPriority = MEMORY_PRIORITY_MEDIUM;
3050 case OSMemoryPriority::Low:
3051 prioInfo.MemoryPriority = MEMORY_PRIORITY_LOW;
3053 case OSMemoryPriority::VeryLow:
3054 prioInfo.MemoryPriority = MEMORY_PRIORITY_VERY_LOW;
3057 setProcessInformation(::GetCurrentProcess(), ProcessMemoryPriority, &prioInfo,
sizeof(prioInfo));
3068 max = (max > 0) ? max : -1;
3074 for (
const lt::torrent_handle &handle :
m_nativeSession->get_torrents())
3078 handle.set_max_connections(max);
3080 catch (
const std::exception &) {}
3092 max = (max > 0) ? max : -1;
3098 for (
const lt::torrent_handle &handle :
m_nativeSession->get_torrents())
3102 handle.set_max_uploads(max);
3104 catch (
const std::exception &) {}
3228 size = std::max(size, 1);
3239 #ifdef QBT_APP_64BIT
3250 #ifdef QBT_APP_64BIT
3251 size = std::min(size, 33554431);
3254 size = std::min(size, 1536);
3437 max = std::max(max, -1);
3452 max = std::max(max, -1);
3467 max = std::max(max, -1);
3658 for (
const lt::torrent_handle &torrent :
m_nativeSession->get_torrents())
3659 torrent.force_reannounce(0, -1, lt::torrent_handle::ignore_min_interval);
3683 max = (max > 0) ? max : -1;
3698 max = (max > 0) ? max : -1;
3713 if ((protocol < BTProtocol::Both) || (BTProtocol::UTP < protocol))
3903 LogMsg(tr(
"Tracker '%1' was added to torrent '%2'").arg(newTracker.url, torrent->
name()));
3905 if (torrent->
trackers().size() == newTrackers.size())
3912 for (
const TrackerEntry &deletedTracker : deletedTrackers)
3913 LogMsg(tr(
"Tracker '%1' was deleted from torrent '%2'").arg(deletedTracker.url, torrent->
name()));
3927 for (
const QUrl &newUrlSeed : newUrlSeeds)
3928 LogMsg(tr(
"URL seed '%1' was added to torrent '%2'").arg(newUrlSeed.toString(), torrent->
name()));
3933 for (
const QUrl &urlSeed : urlSeeds)
3934 LogMsg(tr(
"URL seed '%1' was removed from torrent '%2'").arg(urlSeed.toString(), torrent->
name()));
3942 #ifdef QBT_USES_LIBTORRENT2
3972 qDebug(
"Checking if the torrent contains torrent files to download");
3976 if (torrentRelpath.endsWith(
".torrent", Qt::CaseInsensitive))
3978 qDebug(
"Found possible recursive torrent download.");
3980 qDebug(
"Full subtorrent path is %s", qUtf8Printable(torrentFullpath));
3983 qDebug(
"emitting recursiveTorrentDownloadPossible()");
3989 qDebug(
"Caught error loading torrent");
3998 #ifdef QBT_USES_LIBTORRENT2
4031 const lt::torrent_handle torrentHandle = torrent->
nativeHandle();
4039 return job.torrentHandle == torrentHandle;
4046 LogMsg(tr(
"Cancelled moving \"%1\" from \"%2\" to \"%3\".").arg(torrent->
name(), currentLocation, iter->path));
4056 LogMsg(tr(
"Couldn't enqueue move of \"%1\" to \"%2\". Torrent is currently moving to the same destination location.")
4057 .arg(torrent->
name(), newPath));
4063 if (QDir {currentLocation} == QDir {newPath})
4065 LogMsg(tr(
"Couldn't enqueue move of \"%1\" from \"%2\" to \"%3\". Both paths point to the same location.")
4066 .arg(torrent->
name(), currentLocation, newPath));
4071 const MoveStorageJob moveStorageJob {torrentHandle, newPath, mode};
4073 LogMsg(tr(
"Enqueued to move \"%1\" from \"%2\" to \"%3\".").arg(torrent->
name(), currentLocation, newPath));
4083 #ifdef QBT_USES_LIBTORRENT2
4089 const QString torrentName = (torrent ? torrent->
name() :
id.toString());
4090 LogMsg(tr(
"Moving \"%1\" to \"%2\"...").arg(torrentName, job.
path));
4094 ? lt::move_flags_t::always_replace_files : lt::move_flags_t::dont_replace));
4106 return job.torrentHandle == finishedJob.torrentHandle;
4116 else if (!torrentHasOutstandingJob)
4119 const lt::torrent_handle nativeHandle {finishedJob.
torrentHandle};
4122 m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile);
4128 QJsonObject jsonObj;
4131 const QString &categoryName = it.key();
4137 const QByteArray data = QJsonDocument(jsonObj).toJson();
4141 LogMsg(tr(
"Couldn't store Categories configuration to %1. Error: %2")
4149 for (
auto it = legacyCategories.cbegin(); it != legacyCategories.cend(); ++it)
4151 const QString categoryName = it.key();
4165 if (!confFile.exists())
4176 if (!confFile.open(QFile::ReadOnly))
4178 LogMsg(tr(
"Couldn't load Categories from %1. Error: %2")
4179 .arg(confFile.fileName(), confFile.errorString()),
Log::CRITICAL);
4183 QJsonParseError jsonError;
4184 const QJsonDocument jsonDoc = QJsonDocument::fromJson(confFile.readAll(), &jsonError);
4185 if (jsonError.error != QJsonParseError::NoError)
4187 LogMsg(tr(
"Couldn't parse Categories configuration from %1. Error: %2")
4188 .arg(confFile.fileName(), jsonError.errorString()),
Log::WARNING);
4192 if (!jsonDoc.isObject())
4194 LogMsg(tr(
"Couldn't load Categories configuration from %1. Invalid data format.")
4200 const QJsonObject jsonObj = jsonDoc.object();
4201 for (
auto it = jsonObj.constBegin(); it != jsonObj.constEnd(); ++it)
4203 const QString &categoryName = it.key();
4218 return (torrent->ratioLimit() >= 0);
4226 return (torrent->seedingTimeLimit() >= 0);
4236 QMetaObject::invokeMethod(
this, qOverload<>(&
Session::configure), Qt::QueuedConnection);
4243 qDebug(
"Enabling IPFilter");
4260 qDebug(
"Disabling IPFilter");
4270 lt::ip_filter filter;
4278 if (!torrent)
return;
4282 if (torrentRelpath.endsWith(QLatin1String(
".torrent")))
4284 LogMsg(tr(
"Recursive download of file '%1' embedded in torrent '%2'"
4285 ,
"Recursive download of 'test.torrent' embedded in torrent 'test2'")
4287 const QString torrentFullpath = torrent->
savePath() +
'/' + torrentRelpath;
4313 qDebug(
"Initializing torrents resume data storage...");
4317 const bool dbStorageExists = QFile::exists(dbPath);
4324 if (!dbStorageExists)
4337 if (dbStorageExists)
4341 if (!startupStorage)
4344 qDebug(
"Starting up torrents...");
4347 int resumedTorrentsCount = 0;
4348 QVector<TorrentID> queue;
4351 const std::optional<LoadTorrentParams> loadResumeDataResult = startupStorage->
load(torrentID);
4352 if (loadResumeDataResult)
4355 bool needStore =
false;
4361 queue.append(torrentID);
4379 qDebug() <<
"Starting up torrent" << torrentID.toString() <<
"...";
4382 LogMsg(tr(
"Unable to resume torrent '%1'.",
"e.g: Unable to resume torrent 'hash'.")
4387 if ((resumedTorrentsCount % 100) == 0)
readAlerts();
4389 ++resumedTorrentsCount;
4393 LogMsg(tr(
"Unable to resume torrent '%1'.",
"e.g: Unable to resume torrent 'hash'.")
4400 delete startupStorage;
4440 LogMsg(tr(
"Successfully parsed the provided IP filter: %1 rules were applied.",
"%1 is a number").arg(ruleCount));
4446 lt::ip_filter filter;
4456 if (time > lt::time_duration::zero())
4459 std::vector<lt::alert *> alerts;
4478 for (
const lt::alert *a : alerts)
4488 #ifdef QBT_USES_LIBTORRENT2
4489 case lt::file_prio_alert::alert_type:
4491 case lt::file_renamed_alert::alert_type:
4492 case lt::file_completed_alert::alert_type:
4493 case lt::torrent_finished_alert::alert_type:
4494 case lt::save_resume_data_alert::alert_type:
4495 case lt::save_resume_data_failed_alert::alert_type:
4496 case lt::torrent_paused_alert::alert_type:
4497 case lt::torrent_resumed_alert::alert_type:
4498 case lt::tracker_error_alert::alert_type:
4499 case lt::tracker_reply_alert::alert_type:
4500 case lt::tracker_warning_alert::alert_type:
4501 case lt::fastresume_rejected_alert::alert_type:
4502 case lt::torrent_checked_alert::alert_type:
4503 case lt::metadata_received_alert::alert_type:
4506 case lt::state_update_alert::alert_type:
4509 case lt::session_stats_alert::alert_type:
4512 case lt::file_error_alert::alert_type:
4515 case lt::add_torrent_alert::alert_type:
4518 case lt::torrent_removed_alert::alert_type:
4521 case lt::torrent_deleted_alert::alert_type:
4524 case lt::torrent_delete_failed_alert::alert_type:
4527 case lt::portmap_error_alert::alert_type:
4530 case lt::portmap_alert::alert_type:
4533 case lt::peer_blocked_alert::alert_type:
4536 case lt::peer_ban_alert::alert_type:
4539 case lt::url_seed_alert::alert_type:
4542 case lt::listen_succeeded_alert::alert_type:
4545 case lt::listen_failed_alert::alert_type:
4548 case lt::external_ip_alert::alert_type:
4551 case lt::alerts_dropped_alert::alert_type:
4554 case lt::storage_moved_alert::alert_type:
4557 case lt::storage_moved_failed_alert::alert_type:
4560 case lt::socks5_alert::alert_type:
4565 catch (
const std::exception &exc)
4567 qWarning() <<
"Caught exception in " << Q_FUNC_INFO <<
": " << QString::fromStdString(exc.what());
4573 TorrentImpl *
const torrent =
m_torrents.value(
static_cast<const lt::torrent_alert*
>(a)->handle.info_hash());
4582 case lt::metadata_received_alert::alert_type:
4590 #ifdef QBT_USES_LIBTORRENT2
4603 const bool hasMetadata = torrent->hasMetadata();
4607 LogMsg(tr(
"'%1' restored.",
"'torrent name' restored.").arg(torrent->name()));
4627 LogMsg(tr(
"'%1' added to download list.",
"'torrent name' was added to download list.")
4628 .arg(torrent->name()));
4631 if (((torrent->ratioLimit() >= 0) || (torrent->seedingTimeLimit() >= 0))
4642 if (torrent->hasError())
4643 LogMsg(tr(
"Torrent errored. Torrent: \"%1\". Error: %2.").arg(torrent->name(), torrent->error()),
Log::WARNING);
4650 const QString msg = QString::fromStdString(p->message());
4654 const lt::add_torrent_params ¶ms = p->params;
4655 const bool hasMetadata = (params.ti && params.ti->is_valid());
4656 #ifdef QBT_USES_LIBTORRENT2
4671 #ifdef QBT_USES_LIBTORRENT2
4682 LogMsg(tr(
"'%1' was removed from the transfer list.",
"'xxx.avi' was removed...").arg(removingTorrentDataIter->name));
4690 #ifdef QBT_USES_LIBTORRENT2
4702 LogMsg(tr(
"'%1' was removed from the transfer list and hard disk.",
"'xxx.avi' was removed...").arg(removingTorrentDataIter->name));
4708 #ifdef QBT_USES_LIBTORRENT2
4725 LogMsg(tr(
"'%1' was removed from the transfer list but the files couldn't be deleted. Error: %2",
"'xxx.avi' was removed...")
4726 .arg(removingTorrentDataIter->name, QString::fromLocal8Bit(p->error.message().c_str()))
4731 LogMsg(tr(
"'%1' was removed from the transfer list.",
"'xxx.avi' was removed...").arg(removingTorrentDataIter->name));
4738 #ifdef QBT_USES_LIBTORRENT2
4748 const TorrentInfo metadata {*p->handle.torrent_file()};
4753 m_nativeSession->remove_torrent(p->handle, lt::session::delete_files);
4772 const QString msg = QString::fromStdString(p->message());
4773 LogMsg(tr(
"File error alert. Torrent: \"%1\". File: \"%2\". Reason: %3")
4774 .arg(torrent->
name(), p->filename(), msg)
4784 LogMsg(tr(
"UPnP/NAT-PMP: Port mapping failure, message: %1").arg(QString::fromStdString(p->message())),
Log::CRITICAL);
4789 qDebug(
"UPnP Success, msg: %s", p->message().c_str());
4790 LogMsg(tr(
"UPnP/NAT-PMP: Port mapping successful, message: %1").arg(QString::fromStdString(p->message())),
Log::INFO);
4798 case lt::peer_blocked_alert::ip_filter:
4799 reason = tr(
"IP filter",
"this peer was blocked. Reason: IP filter.");
4801 case lt::peer_blocked_alert::port_filter:
4802 reason = tr(
"port filter",
"this peer was blocked. Reason: port filter.");
4804 case lt::peer_blocked_alert::i2p_mixed:
4805 reason = tr(
"%1 mixed mode restrictions",
"this peer was blocked. Reason: I2P mixed mode restrictions.").arg(
"I2P");
4807 case lt::peer_blocked_alert::privileged_ports:
4808 reason = tr(
"use of privileged port",
"this peer was blocked. Reason: use of privileged port.");
4810 case lt::peer_blocked_alert::utp_disabled:
4811 reason = tr(
"%1 is disabled",
"this peer was blocked. Reason: uTP is disabled.").arg(QString::fromUtf8(
C_UTP));
4813 case lt::peer_blocked_alert::tcp_disabled:
4814 reason = tr(
"%1 is disabled",
"this peer was blocked. Reason: TCP is disabled.").arg(
"TCP");
4818 const QString ip {
toString(p->endpoint.address())};
4825 const QString ip {
toString(p->endpoint.address())};
4838 LogMsg(tr(
"URL seed name lookup failed. Torrent: \"%1\". URL: \"%2\". Error: \"%3\"")
4839 .arg(torrent->
name(), p->server_url(), QString::fromStdString(p->message()))
4844 LogMsg(tr(
"Received error message from a URL seed. Torrent: \"%1\". URL: \"%2\". Message: \"%3\"")
4845 .arg(torrent->
name(), p->server_url(), p->error_message())
4852 const QString proto {
toString(p->socket_type)};
4853 LogMsg(tr(
"Successfully listening on IP: %1, port: %2/%3"
4854 ,
"e.g: Successfully listening on IP: 192.168.0.1, port: TCP/6881")
4863 const QString proto {
toString(p->socket_type)};
4864 LogMsg(tr(
"Failed to listen on IP: %1, port: %2/%3. Reason: %4"
4865 ,
"e.g: Failed to listen on IP: 192.168.0.1, port: TCP/6881. Reason: already in use")
4866 .arg(
toString(p->address), proto, QString::number(p->port)
4867 , QString::fromLocal8Bit(p->error.message().c_str())),
Log::CRITICAL);
4872 const QString externalIP {
toString(p->external_address)};
4873 LogMsg(tr(
"Detected external IP: %1",
"e.g. Detected external IP: 1.1.1.1")
4889 const auto stats = p->counters();
4904 auto calcRate = [interval](
const quint64 previous,
const quint64 current)
4906 Q_ASSERT(current >= previous);
4907 return static_cast<quint64
>((current - previous) / interval);
4941 #ifndef QBT_USES_LIBTORRENT2
4944 m_cacheStatus.
readRatio =
static_cast<qreal
>(numBlocksCacheHits) / std::max<int64_t>((numBlocksCacheHits + numBlocksRead), 1);
4962 LogMsg(tr(
"Error: Internal alert queue full and alerts were dropped, you might see degraded performance. Dropped alert types: %1. Message: %2")
4963 .arg(QString::fromStdString(p->dropped_alerts.to_string()), QString::fromStdString(p->message())),
Log::CRITICAL);
4973 const QString newPath {p->storage_path()};
4974 Q_ASSERT(newPath == currentJob.
path);
4976 #ifdef QBT_USES_LIBTORRENT2
4983 const QString torrentName = (torrent ? torrent->
name() :
id.toString());
4984 LogMsg(tr(
"\"%1\" is successfully moved to \"%2\".").arg(torrentName, newPath));
4996 #ifdef QBT_USES_LIBTORRENT2
5003 const QString torrentName = (torrent ? torrent->
name() :
id.toString());
5004 const QString currentLocation = QString::fromStdString(p->handle.status(lt::torrent_handle::query_save_path).save_path);
5005 const QString errorMessage = QString::fromStdString(p->message());
5006 LogMsg(tr(
"Failed to move \"%1\" from \"%2\" to \"%3\". Reason: %4.")
5007 .arg(torrentName, currentLocation, currentJob.
path, errorMessage),
Log::CRITICAL);
5014 QVector<Torrent *> updatedTorrents;
5015 updatedTorrents.reserve(
static_cast<decltype(updatedTorrents)::size_type
>(p->status.size()));
5017 for (
const lt::torrent_status &
status : p->status)
5019 #ifdef QBT_USES_LIBTORRENT2
5029 updatedTorrents.push_back(torrent);
5032 if (!updatedTorrents.isEmpty())
5045 LogMsg(tr(
"SOCKS5 proxy error. Message: %1").arg(QString::fromStdString(p->message()))
void bandwidthLimitRequested(bool alternative)
QVector< TrackerEntry > trackers() const
lt::add_torrent_params addTorrentParams() const
InfoHash infoHash() const
QVector< QUrl > urlSeeds() const
virtual void remove(const TorrentID &id) const =0
virtual void storeQueue(const QVector< TorrentID > &queue) const =0
virtual void store(const TorrentID &id, const LoadTorrentParams &resumeData) const =0
virtual QVector< TorrentID > registeredTorrents() const =0
virtual std::optional< LoadTorrentParams > load(const TorrentID &id) const =0
void reannounceToAllTrackers() const
int refreshInterval() const
void populateAdditionalTrackers()
CachedSettingValue< int > m_globalMaxSeedingMinutes
void handleAddTorrentAlert(const lt::add_torrent_alert *p)
QString networkInterfaceName() const
void handleTorrentUrlSeedsAdded(TorrentImpl *const torrent, const QVector< QUrl > &newUrlSeeds)
CachedSettingValue< int > m_stopTrackerTimeout
bool removeTag(const QString &tag)
void loadLTSettings(lt::settings_pack &settingsPack)
void setAddTrackersEnabled(bool enabled)
bool blockPeersOnPrivilegedPorts() const
QString additionalTrackers() const
CachedSettingValue< int > m_socketBacklogSize
void setDiskCacheTTL(int ttl)
void setOutgoingPortsMax(int max)
bool m_IPFilteringConfigured
void setGlobalMaxSeedingMinutes(int minutes)
void setPeerTurnoverInterval(int num)
CachedSettingValue< SeedChokingAlgorithm > m_seedChokingAlgorithm
std::vector< lt::alert * > getPendingAlerts(lt::time_duration time=lt::time_duration::zero()) const
void subcategoriesSupportChanged()
QSet< TorrentID > m_needSaveResumeDataTorrents
void setBannedIPs(const QStringList &newList)
void setDownloadRateForSlowTorrents(int rateInKibiBytes)
void handleSessionStatsAlert(const lt::session_stats_alert *p)
void handlePeerBanAlert(const lt::peer_ban_alert *p)
void setIPFilterFile(QString path)
void handleTorrentChecked(TorrentImpl *const torrent)
CachedSettingValue< QStringList > m_bannedIPs
QString torrentExportDirectory() const
QStringList getListeningIPs() const
void torrentTagAdded(Torrent *torrent, const QString &tag)
void setTorrentExportDirectory(QString path)
void handleTorrentTagAdded(TorrentImpl *const torrent, const QString &tag)
void handleTorrentCategoryChanged(TorrentImpl *const torrent, const QString &oldCategory)
int maxActiveDownloads() const
CachedSettingValue< bool > m_isTrackerFilteringEnabled
void removeTorrentsQueue() const
qreal globalMaxRatio() const
void handleTorrentTrackersRemoved(TorrentImpl *const torrent, const QVector< TrackerEntry > &deletedTrackers)
void torrentSavingModeChanged(Torrent *torrent)
CachedSettingValue< int > m_saveResumeDataInterval
int maxActiveUploads() const
QVector< Torrent * > torrents() const
lt::time_point m_statsLastTimestamp
void handleAlertsDroppedAlert(const lt::alerts_dropped_alert *p) const
int uploadSpeedLimit() const
CachedSettingValue< bool > m_isLSDEnabled
void torrentPaused(Torrent *torrent)
bool cancelDownloadMetadata(const TorrentID &id)
void setResumeDataStorageType(ResumeDataStorageType type)