2015-04-19 18:17:47 +03:00
/*
* Bittorrent Client using Qt and libtorrent .
* Copyright ( C ) 2015 Vladimir Golovnev < glassez @ yandex . ru >
* Copyright ( C ) 2006 Christophe Dumez < chris @ qbittorrent . org >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
* In addition , as a special exception , the copyright holders give permission to
* link this program with the OpenSSL project ' s " OpenSSL " library ( or with
* modified versions of it that use the same license as the " OpenSSL " library ) ,
* and distribute the linked executables . You must obey the GNU General Public
* License in all respects for all of the code used other than " OpenSSL " . If you
* modify file ( s ) , you may extend this exception to your version of the file ( s ) ,
* but you are not obligated to do so . If you do not wish to do so , delete this
* exception statement from your version .
*/
2016-04-19 09:54:48 +03:00
# include "session.h"
2017-09-07 03:00:04 +03:00
# include <cstdlib>
# include <queue>
2017-10-08 09:59:52 +03:00
# include <string>
2017-09-07 03:00:04 +03:00
# include <vector>
2016-04-19 09:54:48 +03:00
# include <QCoreApplication>
# include <QDateTime>
2015-04-19 18:17:47 +03:00
# include <QDebug>
# include <QDir>
# include <QHostAddress>
# include <QNetworkAddressEntry>
2016-04-19 09:54:48 +03:00
# include <QNetworkInterface>
2015-04-19 18:17:47 +03:00
# include <QProcess>
2016-02-09 11:56:48 +03:00
# include <QRegExp>
2016-04-19 09:54:48 +03:00
# include <QString>
# include <QThread>
# include <QTimer>
2017-08-13 00:58:22 +03:00
# include <QUuid>
2015-04-19 18:17:47 +03:00
2016-04-19 09:54:48 +03:00
# include <libtorrent/alert_types.hpp>
2016-06-03 17:03:17 +03:00
# if LIBTORRENT_VERSION_NUM >= 10100
# include <libtorrent/bdecode.hpp>
# endif
2015-04-19 18:17:47 +03:00
# include <libtorrent/bencode.hpp>
2017-04-29 14:45:30 +03:00
# include <libtorrent/disk_io_thread.hpp>
2015-04-19 18:17:47 +03:00
# include <libtorrent/error_code.hpp>
# include <libtorrent/extensions/ut_metadata.hpp>
# include <libtorrent/extensions/ut_pex.hpp>
# include <libtorrent/extensions/smart_ban.hpp>
2016-04-19 09:54:48 +03:00
# include <libtorrent/identify_client.hpp>
# include <libtorrent/ip_filter.hpp>
2016-06-03 17:03:17 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2016-04-19 09:54:48 +03:00
# include <libtorrent/lazy_entry.hpp>
2016-06-03 17:03:17 +03:00
# endif
2016-04-19 09:54:48 +03:00
# include <libtorrent/magnet_uri.hpp>
# include <libtorrent/session.hpp>
2017-04-29 14:52:28 +03:00
# if LIBTORRENT_VERSION_NUM >= 10100
# include <libtorrent/session_stats.hpp>
# endif
2017-04-29 14:45:30 +03:00
# include <libtorrent/session_status.hpp>
2016-04-19 09:54:48 +03:00
# include <libtorrent/torrent_info.hpp>
2015-04-19 18:17:47 +03:00
2015-09-25 11:10:05 +03:00
# include "base/logger.h"
# include "base/net/downloadhandler.h"
2016-04-19 09:54:48 +03:00
# include "base/net/downloadmanager.h"
2015-09-25 11:10:05 +03:00
# include "base/net/portforwarder.h"
2016-05-01 11:05:52 +03:00
# include "base/net/proxyconfigurationmanager.h"
2017-09-07 03:00:04 +03:00
# include "base/profile.h"
2016-04-07 17:58:30 +03:00
# include "base/torrentfileguard.h"
2016-04-19 09:54:48 +03:00
# include "base/torrentfilter.h"
# include "base/unicodestrings.h"
# include "base/utils/fs.h"
2017-09-07 03:00:04 +03:00
# include "base/utils/misc.h"
# include "base/utils/net.h"
2017-02-10 15:33:21 +03:00
# include "base/utils/random.h"
2015-09-25 11:10:05 +03:00
# include "base/utils/string.h"
2016-04-19 09:54:48 +03:00
# include "magneturi.h"
2015-04-19 18:17:47 +03:00
# include "private/bandwidthscheduler.h"
2017-09-07 03:00:04 +03:00
# include "private/filterparserthread.h"
2015-12-13 15:38:19 +03:00
# include "private/resumedatasavingmanager.h"
2017-09-07 03:00:04 +03:00
# include "private/statistics.h"
2015-04-19 18:17:47 +03:00
# include "torrenthandle.h"
2016-04-19 09:54:48 +03:00
# include "tracker.h"
# include "trackerentry.h"
2015-04-19 18:17:47 +03:00
2017-08-13 00:58:22 +03:00
# ifdef Q_OS_WIN
# include <iphlpapi.h>
# endif
2017-08-15 21:57:34 +03:00
# if defined(Q_OS_WIN) && (_WIN32_WINNT < 0x0600)
2017-08-13 00:58:22 +03:00
using NETIO_STATUS = LONG ;
# endif
2016-10-30 00:11:52 +03:00
static const char PEER_ID [ ] = " qB " ;
static const char RESUME_FOLDER [ ] = " BT_backup " ;
2017-03-08 00:41:29 +03:00
static const char USER_AGENT [ ] = " qBittorrent/ " QBT_VERSION_2 ;
2015-04-19 18:17:47 +03:00
namespace libt = libtorrent ;
using namespace BitTorrent ;
2016-02-09 11:56:48 +03:00
namespace
{
bool readFile ( const QString & path , QByteArray & buf ) ;
bool loadTorrentResumeData ( const QByteArray & data , AddTorrentData & torrentData , int & prio , MagnetUri & magnetUri ) ;
void torrentQueuePositionUp ( const libt : : torrent_handle & handle ) ;
void torrentQueuePositionDown ( const libt : : torrent_handle & handle ) ;
void torrentQueuePositionTop ( const libt : : torrent_handle & handle ) ;
void torrentQueuePositionBottom ( const libt : : torrent_handle & handle ) ;
2017-08-13 00:58:22 +03:00
# ifdef Q_OS_WIN
QString convertIfaceNameToGuid ( const QString & name ) ;
# endif
2016-05-01 11:05:52 +03:00
inline SettingsStorage * settings ( ) { return SettingsStorage : : instance ( ) ; }
2016-02-09 11:56:48 +03:00
QStringMap map_cast ( const QVariantMap & map )
{
QStringMap result ;
foreach ( const QString & key , map . keys ( ) )
result [ key ] = map . value ( key ) . toString ( ) ;
return result ;
}
QVariantMap map_cast ( const QStringMap & map )
{
QVariantMap result ;
foreach ( const QString & key , map . keys ( ) )
result [ key ] = map . value ( key ) ;
return result ;
}
2017-06-05 03:22:17 +03:00
template < typename Entry >
QSet < QString > entryListToSetImpl ( const Entry & entry )
{
Q_ASSERT ( entry . type ( ) = = Entry : : list_t ) ;
QSet < QString > output ;
for ( int i = 0 ; i < entry . list_size ( ) ; + + i ) {
const QString tag = QString : : fromStdString ( entry . list_string_value_at ( i ) ) ;
if ( Session : : isValidTag ( tag ) )
output . insert ( tag ) ;
else
qWarning ( ) < < QString ( " Dropping invalid stored tag: %1 " ) . arg ( tag ) ;
}
return output ;
}
# if LIBTORRENT_VERSION_NUM < 10100
bool isList ( const libt : : lazy_entry * entry )
{
return entry & & ( entry - > type ( ) = = libt : : lazy_entry : : list_t ) ;
}
QSet < QString > entryListToSet ( const libt : : lazy_entry * entry )
{
return entry ? entryListToSetImpl ( * entry ) : QSet < QString > ( ) ;
}
# else
bool isList ( const libt : : bdecode_node & entry )
{
return entry . type ( ) = = libt : : bdecode_node : : list_t ;
}
QSet < QString > entryListToSet ( const libt : : bdecode_node & entry )
{
return entryListToSetImpl ( entry ) ;
}
# endif
2016-05-01 11:05:52 +03:00
QString normalizePath ( const QString & path )
{
QString tmp = Utils : : Fs : : fromNativePath ( path . trimmed ( ) ) ;
if ( ! tmp . isEmpty ( ) & & ! tmp . endsWith ( ' / ' ) )
return tmp + ' / ' ;
return tmp ;
}
2016-05-11 14:25:29 +03:00
QString normalizeSavePath ( QString path , const QString & defaultPath = specialFolderLocation ( SpecialFolder : : Downloads ) )
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
path = path . trimmed ( ) ;
2016-03-06 09:25:55 +03:00
if ( path . isEmpty ( ) )
path = Utils : : Fs : : fromNativePath ( defaultPath . trimmed ( ) ) ;
2016-05-01 11:05:52 +03:00
return normalizePath ( path ) ;
2016-02-09 11:56:48 +03:00
}
QStringMap expandCategories ( const QStringMap & categories )
{
QStringMap expanded = categories ;
2015-04-19 18:17:47 +03:00
2016-02-09 11:56:48 +03:00
foreach ( const QString & category , categories . keys ( ) ) {
foreach ( const QString & subcat , Session : : expandCategory ( category ) ) {
if ( ! expanded . contains ( subcat ) )
expanded [ subcat ] = " " ;
}
}
return expanded ;
}
2016-04-19 09:54:48 +03:00
2016-05-01 11:05:52 +03:00
template < typename T >
struct LowerLimited
{
LowerLimited ( T limit , T ret )
: m_limit ( limit )
, m_ret ( ret )
{
}
explicit LowerLimited ( T limit )
: LowerLimited ( limit , limit )
{
}
2017-05-09 09:21:55 +03:00
T operator ( ) ( T val ) const
2016-05-01 11:05:52 +03:00
{
return val < = m_limit ? m_ret : val ;
}
private :
const T m_limit ;
const T m_ret ;
} ;
template < typename T >
LowerLimited < T > lowerLimited ( T limit ) { return LowerLimited < T > ( limit ) ; }
template < typename T >
LowerLimited < T > lowerLimited ( T limit , T ret ) { return LowerLimited < T > ( limit , ret ) ; }
2017-08-15 15:26:28 +03:00
template < typename T >
std : : function < T ( const T & ) > clampValue ( const T lower , const T upper )
{
// TODO: change return type to `auto` when using C++14
return [ lower , upper ] ( const T value ) - > T
{
if ( value < lower )
return lower ;
if ( value > upper )
return upper ;
return value ;
} ;
}
2016-02-09 11:56:48 +03:00
}
2015-04-19 18:17:47 +03:00
// Session
2016-02-09 11:56:48 +03:00
Session * Session : : m_instance = nullptr ;
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
# define BITTORRENT_KEY(name) "BitTorrent / " name
# define BITTORRENT_SESSION_KEY(name) BITTORRENT_KEY("Session / ") name
2015-04-19 18:17:47 +03:00
Session : : Session ( QObject * parent )
: QObject ( parent )
2016-05-01 11:05:52 +03:00
, m_deferredConfigureScheduled ( false )
2016-06-03 17:03:17 +03:00
, m_IPFilteringChanged ( false )
# if LIBTORRENT_VERSION_NUM >= 10100
, m_listenInterfaceChanged ( true )
# endif
2016-05-01 11:05:52 +03:00
, m_isDHTEnabled ( BITTORRENT_SESSION_KEY ( " DHTEnabled " ) , true )
, m_isLSDEnabled ( BITTORRENT_SESSION_KEY ( " LSDEnabled " ) , true )
, m_isPeXEnabled ( BITTORRENT_SESSION_KEY ( " PeXEnabled " ) , true )
2016-10-29 19:14:27 +03:00
, m_isIPFilteringEnabled ( BITTORRENT_SESSION_KEY ( " IPFilteringEnabled " ) , false )
2016-05-01 11:05:52 +03:00
, m_isTrackerFilteringEnabled ( BITTORRENT_SESSION_KEY ( " TrackerFilteringEnabled " ) , false )
, m_IPFilterFile ( BITTORRENT_SESSION_KEY ( " IPFilter " ) )
2017-10-31 00:04:14 +03:00
, m_announceToAllTrackers ( BITTORRENT_SESSION_KEY ( " AnnounceToAllTrackers " ) , false )
2017-10-30 21:04:14 +03:00
, m_announceToAllTiers ( BITTORRENT_SESSION_KEY ( " AnnounceToAllTiers " ) , true )
2017-09-10 16:04:40 +03:00
, m_diskCacheSize ( BITTORRENT_SESSION_KEY ( " DiskCacheSize " ) , 64 )
2016-05-01 11:05:52 +03:00
, m_diskCacheTTL ( BITTORRENT_SESSION_KEY ( " DiskCacheTTL " ) , 60 )
, m_useOSCache ( BITTORRENT_SESSION_KEY ( " UseOSCache " ) , true )
2017-08-11 10:50:56 +03:00
, m_guidedReadCacheEnabled ( BITTORRENT_SESSION_KEY ( " GuidedReadCache " ) , true )
2017-08-11 14:15:18 +03:00
, m_isSuggestMode ( BITTORRENT_SESSION_KEY ( " SuggestMode " ) , false )
2017-08-11 14:48:58 +03:00
, m_sendBufferWatermark ( BITTORRENT_SESSION_KEY ( " SendBufferWatermark " ) , 500 )
, m_sendBufferLowWatermark ( BITTORRENT_SESSION_KEY ( " SendBufferLowWatermark " ) , 10 )
, m_sendBufferWatermarkFactor ( BITTORRENT_SESSION_KEY ( " SendBufferWatermarkFactor " ) , 50 )
2016-05-01 11:05:52 +03:00
, m_isAnonymousModeEnabled ( BITTORRENT_SESSION_KEY ( " AnonymousModeEnabled " ) , false )
, m_isQueueingEnabled ( BITTORRENT_SESSION_KEY ( " QueueingSystemEnabled " ) , true )
2016-10-30 00:10:42 +03:00
, m_maxActiveDownloads ( BITTORRENT_SESSION_KEY ( " MaxActiveDownloads " ) , 3 , lowerLimited ( - 1 ) )
, m_maxActiveUploads ( BITTORRENT_SESSION_KEY ( " MaxActiveUploads " ) , 3 , lowerLimited ( - 1 ) )
, m_maxActiveTorrents ( BITTORRENT_SESSION_KEY ( " MaxActiveTorrents " ) , 5 , lowerLimited ( - 1 ) )
2016-05-01 11:05:52 +03:00
, m_ignoreSlowTorrentsForQueueing ( BITTORRENT_SESSION_KEY ( " IgnoreSlowTorrentsForQueueing " ) , false )
, m_outgoingPortsMin ( BITTORRENT_SESSION_KEY ( " OutgoingPortsMin " ) , 0 )
, m_outgoingPortsMax ( BITTORRENT_SESSION_KEY ( " OutgoingPortsMax " ) , 0 )
, m_ignoreLimitsOnLAN ( BITTORRENT_SESSION_KEY ( " IgnoreLimitsOnLAN " ) , true )
, m_includeOverheadInLimits ( BITTORRENT_SESSION_KEY ( " IncludeOverheadInLimits " ) , false )
2016-10-31 02:22:11 +03:00
, m_announceIP ( BITTORRENT_SESSION_KEY ( " AnnounceIP " ) )
2016-05-01 11:05:52 +03:00
, m_isSuperSeedingEnabled ( BITTORRENT_SESSION_KEY ( " SuperSeedingEnabled " ) , false )
, m_maxConnections ( BITTORRENT_SESSION_KEY ( " MaxConnections " ) , 500 , lowerLimited ( 0 , - 1 ) )
, m_maxHalfOpenConnections ( BITTORRENT_SESSION_KEY ( " MaxHalfOpenConnections " ) , 20 , lowerLimited ( 0 , - 1 ) )
, m_maxUploads ( BITTORRENT_SESSION_KEY ( " MaxUploads " ) , - 1 , lowerLimited ( 0 , - 1 ) )
, m_maxConnectionsPerTorrent ( BITTORRENT_SESSION_KEY ( " MaxConnectionsPerTorrent " ) , 100 , lowerLimited ( 0 , - 1 ) )
, m_maxUploadsPerTorrent ( BITTORRENT_SESSION_KEY ( " MaxUploadsPerTorrent " ) , - 1 , lowerLimited ( 0 , - 1 ) )
2017-09-13 23:29:54 +03:00
, m_btProtocol ( BITTORRENT_SESSION_KEY ( " BTProtocol " ) , BTProtocol : : Both
, clampValue ( BTProtocol : : Both , BTProtocol : : UTP ) )
2016-05-01 11:05:52 +03:00
, m_isUTPRateLimited ( BITTORRENT_SESSION_KEY ( " uTPRateLimited " ) , true )
2017-08-15 21:23:07 +03:00
, m_utpMixedMode ( BITTORRENT_SESSION_KEY ( " uTPMixedMode " ) , MixedModeAlgorithm : : Proportional
, clampValue ( MixedModeAlgorithm : : TCP , MixedModeAlgorithm : : Proportional ) )
2017-08-11 11:37:32 +03:00
, m_multiConnectionsPerIpEnabled ( BITTORRENT_SESSION_KEY ( " MultiConnectionsPerIp " ) , false )
2016-05-01 11:05:52 +03:00
, m_isAddTrackersEnabled ( BITTORRENT_SESSION_KEY ( " AddTrackersEnabled " ) , false )
, m_additionalTrackers ( BITTORRENT_SESSION_KEY ( " AdditionalTrackers " ) )
, m_globalMaxRatio ( BITTORRENT_SESSION_KEY ( " GlobalMaxRatio " ) , - 1 , [ ] ( qreal r ) { return r < 0 ? - 1. : r ; } )
2016-02-07 20:31:50 +03:00
, m_globalMaxSeedingMinutes ( BITTORRENT_SESSION_KEY ( " GlobalMaxSeedingMinutes " ) , - 1 , lowerLimited ( - 1 ) )
2016-05-01 11:05:52 +03:00
, m_isAddTorrentPaused ( BITTORRENT_SESSION_KEY ( " AddTorrentPaused " ) , false )
2017-04-15 17:21:24 +03:00
, m_isCreateTorrentSubfolder ( BITTORRENT_SESSION_KEY ( " CreateTorrentSubfolder " ) , true )
2016-05-01 11:05:52 +03:00
, m_isAppendExtensionEnabled ( BITTORRENT_SESSION_KEY ( " AddExtensionToIncompleteFiles " ) , false )
, m_refreshInterval ( BITTORRENT_SESSION_KEY ( " RefreshInterval " ) , 1500 )
, m_isPreallocationEnabled ( BITTORRENT_SESSION_KEY ( " Preallocation " ) , false )
, m_torrentExportDirectory ( BITTORRENT_SESSION_KEY ( " TorrentExportDirectory " ) )
, m_finishedTorrentExportDirectory ( BITTORRENT_SESSION_KEY ( " FinishedTorrentExportDirectory " ) )
, m_globalDownloadSpeedLimit ( BITTORRENT_SESSION_KEY ( " GlobalDLSpeedLimit " ) , 0 , lowerLimited ( 0 ) )
, m_globalUploadSpeedLimit ( BITTORRENT_SESSION_KEY ( " GlobalUPSpeedLimit " ) , 0 , lowerLimited ( 0 ) )
, m_altGlobalDownloadSpeedLimit ( BITTORRENT_SESSION_KEY ( " AlternativeGlobalDLSpeedLimit " ) , 10 , lowerLimited ( 0 ) )
, m_altGlobalUploadSpeedLimit ( BITTORRENT_SESSION_KEY ( " AlternativeGlobalUPSpeedLimit " ) , 10 , lowerLimited ( 0 ) )
, m_isAltGlobalSpeedLimitEnabled ( BITTORRENT_SESSION_KEY ( " UseAlternativeGlobalSpeedLimit " ) , false )
, m_isBandwidthSchedulerEnabled ( BITTORRENT_SESSION_KEY ( " BandwidthSchedulerEnabled " ) , false )
, m_saveResumeDataInterval ( BITTORRENT_SESSION_KEY ( " SaveResumeDataInterval " ) , 3 )
, m_port ( BITTORRENT_SESSION_KEY ( " Port " ) , 8999 )
, m_useRandomPort ( BITTORRENT_SESSION_KEY ( " UseRandomPort " ) , false )
, m_networkInterface ( BITTORRENT_SESSION_KEY ( " Interface " ) )
2016-10-31 02:40:26 +03:00
, m_networkInterfaceName ( BITTORRENT_SESSION_KEY ( " InterfaceName " ) )
2016-05-01 11:05:52 +03:00
, m_networkInterfaceAddress ( BITTORRENT_SESSION_KEY ( " InterfaceAddress " ) )
, m_isIPv6Enabled ( BITTORRENT_SESSION_KEY ( " IPv6Enabled " ) , false )
, m_encryption ( BITTORRENT_SESSION_KEY ( " Encryption " ) , 0 )
, m_isForceProxyEnabled ( BITTORRENT_SESSION_KEY ( " ForceProxy " ) , true )
, m_isProxyPeerConnectionsEnabled ( BITTORRENT_SESSION_KEY ( " ProxyPeerConnections " ) , false )
2017-08-15 21:23:07 +03:00
, m_chokingAlgorithm ( BITTORRENT_SESSION_KEY ( " ChokingAlgorithm " ) , ChokingAlgorithm : : FixedSlots
, clampValue ( ChokingAlgorithm : : FixedSlots , ChokingAlgorithm : : RateBased ) )
, m_seedChokingAlgorithm ( BITTORRENT_SESSION_KEY ( " SeedChokingAlgorithm " ) , SeedChokingAlgorithm : : FastestUpload
, clampValue ( SeedChokingAlgorithm : : RoundRobin , SeedChokingAlgorithm : : AntiLeech ) )
2016-05-01 11:05:52 +03:00
, m_storedCategories ( BITTORRENT_SESSION_KEY ( " Categories " ) )
2017-06-05 03:22:17 +03:00
, m_storedTags ( BITTORRENT_SESSION_KEY ( " Tags " ) )
2016-05-01 11:05:52 +03:00
, m_maxRatioAction ( BITTORRENT_SESSION_KEY ( " MaxRatioAction " ) , Pause )
2016-05-11 14:25:29 +03:00
, m_defaultSavePath ( BITTORRENT_SESSION_KEY ( " DefaultSavePath " ) , specialFolderLocation ( SpecialFolder : : Downloads ) , normalizePath )
2016-05-01 11:05:52 +03:00
, m_tempPath ( BITTORRENT_SESSION_KEY ( " TempPath " ) , defaultSavePath ( ) + " temp/ " , normalizePath )
, m_isSubcategoriesEnabled ( BITTORRENT_SESSION_KEY ( " SubcategoriesEnabled " ) , false )
, m_isTempPathEnabled ( BITTORRENT_SESSION_KEY ( " TempPathEnabled " ) , false )
, m_isAutoTMMDisabledByDefault ( BITTORRENT_SESSION_KEY ( " DisableAutoTMMByDefault " ) , true )
, m_isDisableAutoTMMWhenCategoryChanged ( BITTORRENT_SESSION_KEY ( " DisableAutoTMMTriggers/CategoryChanged " ) , false )
, m_isDisableAutoTMMWhenDefaultSavePathChanged ( BITTORRENT_SESSION_KEY ( " DisableAutoTMMTriggers/DefaultSavePathChanged " ) , true )
, m_isDisableAutoTMMWhenCategorySavePathChanged ( BITTORRENT_SESSION_KEY ( " DisableAutoTMMTriggers/CategorySavePathChanged " ) , true )
, m_isTrackerEnabled ( BITTORRENT_KEY ( " TrackerEnabled " ) , false )
2017-03-06 15:40:34 +03:00
, m_bannedIPs ( " State/BannedIPs "
, QStringList ( )
, [ ] ( const QStringList & value )
{
QStringList tmp = value ;
tmp . sort ( ) ;
return tmp ;
}
)
2016-10-31 03:06:29 +03:00
, m_wasPexEnabled ( m_isPeXEnabled )
2015-04-19 18:17:47 +03:00
, m_numResumeData ( 0 )
, m_extraLimit ( 0 )
2016-05-01 11:05:52 +03:00
, m_useProxy ( false )
2015-04-19 18:17:47 +03:00
{
2015-11-07 03:06:07 +03:00
Logger * const logger = Logger : : instance ( ) ;
2015-04-19 18:17:47 +03:00
initResumeFolder ( ) ;
2016-02-07 20:31:50 +03:00
m_seedingLimitTimer = new QTimer ( this ) ;
m_seedingLimitTimer - > setInterval ( 10000 ) ;
2017-10-30 18:59:13 +03:00
connect ( m_seedingLimitTimer , & QTimer : : timeout , this , & Session : : processShareLimits ) ;
2015-04-19 18:17:47 +03:00
2015-11-10 01:22:18 +03:00
// Set severity level of libtorrent session
2017-10-30 18:59:13 +03:00
const int alertMask = libt : : alert : : error_notification
2015-11-10 01:22:18 +03:00
| libt : : alert : : peer_notification
| libt : : alert : : port_mapping_notification
| libt : : alert : : storage_notification
| libt : : alert : : tracker_notification
| libt : : alert : : status_notification
| libt : : alert : : ip_block_notification
| libt : : alert : : progress_notification
2017-10-30 18:59:13 +03:00
| libt : : alert : : stats_notification ;
2015-11-07 03:06:07 +03:00
2016-04-28 10:56:58 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2017-03-03 11:42:13 +03:00
libt : : fingerprint fingerprint ( PEER_ID , QBT_VERSION_MAJOR , QBT_VERSION_MINOR , QBT_VERSION_BUGFIX , QBT_VERSION_BUILD ) ;
2016-06-03 17:03:17 +03:00
std : : string peerId = fingerprint . to_string ( ) ;
const ushort port = this - > port ( ) ;
std : : pair < int , int > ports ( port , port ) ;
const QString ip = getListeningIPs ( ) . first ( ) ;
m_nativeSession = new libt : : session ( fingerprint , ports , ip . isEmpty ( ) ? 0 : ip . toLatin1 ( ) . constData ( ) , 0 , alertMask ) ;
libt : : session_settings sessionSettings = m_nativeSession - > settings ( ) ;
sessionSettings . user_agent = USER_AGENT ;
sessionSettings . upnp_ignore_nonrouters = true ;
sessionSettings . use_dht_as_fallback = false ;
// Disable support for SSL torrents for now
sessionSettings . ssl_listen = 0 ;
// To prevent ISPs from blocking seeding
sessionSettings . lazy_bitfields = true ;
// Speed up exit
sessionSettings . stop_tracker_timeout = 1 ;
sessionSettings . auto_scrape_interval = 1200 ; // 20 minutes
sessionSettings . auto_scrape_min_interval = 900 ; // 15 minutes
sessionSettings . connection_speed = 20 ; // default is 10
sessionSettings . no_connect_privileged_ports = false ;
2017-08-18 03:05:36 +03:00
// Disk cache pool is rarely tested in libtorrent and doesn't free buffers
// Soon to be deprecated there
// More info: https://github.com/arvidn/libtorrent/issues/2251
sessionSettings . use_disk_cache_pool = false ;
2016-06-03 17:03:17 +03:00
configure ( sessionSettings ) ;
m_nativeSession - > set_settings ( sessionSettings ) ;
configureListeningInterface ( ) ;
2016-04-28 10:56:58 +03:00
m_nativeSession - > set_alert_dispatch ( [ this ] ( std : : auto_ptr < libt : : alert > alertPtr )
{
2016-12-08 15:13:14 +03:00
dispatchAlerts ( alertPtr . release ( ) ) ;
2016-04-28 10:56:58 +03:00
} ) ;
# else
2017-10-30 18:59:13 +03:00
const std : : string peerId = libt : : generate_fingerprint ( PEER_ID , QBT_VERSION_MAJOR , QBT_VERSION_MINOR , QBT_VERSION_BUGFIX , QBT_VERSION_BUILD ) ;
2016-06-03 17:03:17 +03:00
libt : : settings_pack pack ;
pack . set_int ( libt : : settings_pack : : alert_mask , alertMask ) ;
pack . set_str ( libt : : settings_pack : : peer_fingerprint , peerId ) ;
pack . set_bool ( libt : : settings_pack : : listen_system_port_fallback , false ) ;
pack . set_str ( libt : : settings_pack : : user_agent , USER_AGENT ) ;
pack . set_bool ( libt : : settings_pack : : use_dht_as_fallback , false ) ;
// Disable support for SSL torrents for now
pack . set_int ( libt : : settings_pack : : ssl_listen , 0 ) ;
// To prevent ISPs from blocking seeding
pack . set_bool ( libt : : settings_pack : : lazy_bitfields , true ) ;
// Speed up exit
pack . set_int ( libt : : settings_pack : : stop_tracker_timeout , 1 ) ;
pack . set_int ( libt : : settings_pack : : auto_scrape_interval , 1200 ) ; // 20 minutes
pack . set_int ( libt : : settings_pack : : auto_scrape_min_interval , 900 ) ; // 15 minutes
pack . set_int ( libt : : settings_pack : : connection_speed , 20 ) ; // default is 10
pack . set_bool ( libt : : settings_pack : : no_connect_privileged_ports , false ) ;
2017-08-18 03:05:36 +03:00
// Disk cache pool is rarely tested in libtorrent and doesn't free buffers
// Soon to be deprecated there
// More info: https://github.com/arvidn/libtorrent/issues/2251
pack . set_bool ( libt : : settings_pack : : use_disk_cache_pool , false ) ;
2017-10-30 15:38:41 +03:00
// libtorrent 1.1 enables UPnP & NAT-PMP by default
// turn them off before `libt::session` ctor to avoid split second effects
pack . set_bool ( libt : : settings_pack : : enable_upnp , false ) ;
pack . set_bool ( libt : : settings_pack : : enable_natpmp , false ) ;
pack . set_bool ( libt : : settings_pack : : upnp_ignore_nonrouters , true ) ;
2016-06-03 17:03:17 +03:00
configure ( pack ) ;
m_nativeSession = new libt : : session ( pack , 0 ) ;
2016-04-28 10:56:58 +03:00
m_nativeSession - > set_alert_notify ( [ this ] ( )
{
QMetaObject : : invokeMethod ( this , " readAlerts " , Qt : : QueuedConnection ) ;
} ) ;
2017-05-01 19:19:34 +03:00
configurePeerClasses ( ) ;
2016-04-28 10:56:58 +03:00
# endif
2015-04-19 18:17:47 +03:00
// Enabling plugins
//m_nativeSession->add_extension(&libt::create_metadata_plugin);
m_nativeSession - > add_extension ( & libt : : create_ut_metadata_plugin ) ;
2016-06-03 17:03:17 +03:00
if ( isPeXEnabled ( ) )
2015-04-19 18:17:47 +03:00
m_nativeSession - > add_extension ( & libt : : create_ut_pex_plugin ) ;
m_nativeSession - > add_extension ( & libt : : create_smart_ban_plugin ) ;
2017-03-07 14:41:38 +03:00
logger - > addMessage ( tr ( " Peer ID: " ) + QString : : fromStdString ( peerId ) ) ;
2016-06-03 17:03:17 +03:00
logger - > addMessage ( tr ( " HTTP User-Agent is '%1' " ) . arg ( USER_AGENT ) ) ;
logger - > addMessage ( tr ( " DHT support [%1] " ) . arg ( isDHTEnabled ( ) ? tr ( " ON " ) : tr ( " OFF " ) ) , Log : : INFO ) ;
logger - > addMessage ( tr ( " Local Peer Discovery support [%1] " ) . arg ( isLSDEnabled ( ) ? tr ( " ON " ) : tr ( " OFF " ) ) , Log : : INFO ) ;
logger - > addMessage ( tr ( " PeX support [%1] " ) . arg ( isPeXEnabled ( ) ? tr ( " ON " ) : tr ( " OFF " ) ) , Log : : INFO ) ;
logger - > addMessage ( tr ( " Anonymous mode [%1] " ) . arg ( isAnonymousModeEnabled ( ) ? tr ( " ON " ) : tr ( " OFF " ) ) , Log : : INFO ) ;
logger - > addMessage ( tr ( " Encryption support [%1] " )
. arg ( encryption ( ) = = 0 ? tr ( " ON " ) : encryption ( ) = = 1 ? tr ( " FORCED " ) : tr ( " OFF " ) )
, Log : : INFO ) ;
2017-08-20 18:00:23 +03:00
if ( isBandwidthSchedulerEnabled ( ) )
enableBandwidthScheduler ( ) ;
2017-03-07 02:34:55 +03:00
if ( isIPFilteringEnabled ( ) ) {
// Manually banned IPs are handled in that function too(in the slots)
2016-06-03 17:03:17 +03:00
enableIPFilter ( ) ;
2017-03-07 02:34:55 +03:00
}
else {
// Add the banned IPs
libt : : ip_filter filter ;
processBannedIPs ( filter ) ;
m_nativeSession - > set_ip_filter ( filter ) ;
}
2016-06-03 17:03:17 +03:00
2016-05-01 11:05:52 +03:00
m_categories = map_cast ( m_storedCategories ) ;
2016-02-09 11:56:48 +03:00
if ( isSubcategoriesEnabled ( ) ) {
// if subcategories support changed manually
m_categories = expandCategories ( m_categories ) ;
2016-05-01 11:05:52 +03:00
m_storedCategories = map_cast ( m_categories ) ;
2016-02-09 11:56:48 +03:00
}
2017-06-05 03:22:17 +03:00
m_tags = QSet < QString > : : fromList ( m_storedTags . value ( ) ) ;
2015-04-19 18:17:47 +03:00
m_refreshTimer = new QTimer ( this ) ;
2016-05-01 11:05:52 +03:00
m_refreshTimer - > setInterval ( refreshInterval ( ) ) ;
2017-10-30 18:59:13 +03:00
connect ( m_refreshTimer , & QTimer : : timeout , this , & Session : : refresh ) ;
2015-04-19 18:17:47 +03:00
m_refreshTimer - > start ( ) ;
// Regular saving of fastresume data
m_resumeDataTimer = new QTimer ( this ) ;
2016-05-01 11:05:52 +03:00
m_resumeDataTimer - > setInterval ( saveResumeDataInterval ( ) * 60 * 1000 ) ;
2017-10-30 18:59:13 +03:00
connect ( m_resumeDataTimer , & QTimer : : timeout , this , [ this ] ( ) { generateResumeData ( ) ; } ) ;
2015-04-19 18:17:47 +03:00
m_statistics = new Statistics ( this ) ;
2016-02-07 20:31:50 +03:00
updateSeedingLimitTimer ( ) ;
2016-05-01 11:05:52 +03:00
populateAdditionalTrackers ( ) ;
enableTracker ( isTrackerEnabled ( ) ) ;
connect ( Net : : ProxyConfigurationManager : : instance ( ) , SIGNAL ( proxyConfigurationChanged ( ) ) , SLOT ( configureDeferred ( ) ) ) ;
2016-02-09 11:56:48 +03:00
2015-06-15 01:06:56 +03:00
// Network configuration monitor
connect ( & m_networkManager , SIGNAL ( onlineStateChanged ( bool ) ) , SLOT ( networkOnlineStateChanged ( bool ) ) ) ;
connect ( & m_networkManager , SIGNAL ( configurationAdded ( const QNetworkConfiguration & ) ) , SLOT ( networkConfigurationChange ( const QNetworkConfiguration & ) ) ) ;
connect ( & m_networkManager , SIGNAL ( configurationRemoved ( const QNetworkConfiguration & ) ) , SLOT ( networkConfigurationChange ( const QNetworkConfiguration & ) ) ) ;
connect ( & m_networkManager , SIGNAL ( configurationChanged ( const QNetworkConfiguration & ) ) , SLOT ( networkConfigurationChange ( const QNetworkConfiguration & ) ) ) ;
2015-12-13 15:38:19 +03:00
m_ioThread = new QThread ( this ) ;
m_resumeDataSavingManager = new ResumeDataSavingManager ( m_resumeFolderPath ) ;
m_resumeDataSavingManager - > moveToThread ( m_ioThread ) ;
2017-10-30 18:59:13 +03:00
connect ( m_ioThread , & QThread : : finished , m_resumeDataSavingManager , & QObject : : deleteLater ) ;
2015-12-13 15:38:19 +03:00
m_ioThread - > start ( ) ;
2015-04-19 18:17:47 +03:00
m_resumeDataTimer - > start ( ) ;
// initialize PortForwarder instance
Net : : PortForwarder : : initInstance ( m_nativeSession ) ;
2017-04-29 14:52:28 +03:00
# if LIBTORRENT_VERSION_NUM >= 10100
initMetrics ( ) ;
m_statsUpdateTimer . start ( ) ;
# endif
2015-04-19 18:17:47 +03:00
qDebug ( " * BitTorrent Session constructed " ) ;
}
bool Session : : isDHTEnabled ( ) const
{
2016-05-01 11:05:52 +03:00
return m_isDHTEnabled ;
}
void Session : : setDHTEnabled ( bool enabled )
{
if ( enabled ! = m_isDHTEnabled ) {
m_isDHTEnabled = enabled ;
configureDeferred ( ) ;
2016-06-03 17:03:17 +03:00
Logger : : instance ( ) - > addMessage (
tr ( " DHT support [%1] " ) . arg ( enabled ? tr ( " ON " ) : tr ( " OFF " ) ) , Log : : INFO ) ;
2016-05-01 11:05:52 +03:00
}
2015-04-19 18:17:47 +03:00
}
bool Session : : isLSDEnabled ( ) const
{
2016-05-01 11:05:52 +03:00
return m_isLSDEnabled ;
}
void Session : : setLSDEnabled ( bool enabled )
{
if ( enabled ! = m_isLSDEnabled ) {
m_isLSDEnabled = enabled ;
configureDeferred ( ) ;
2016-06-03 17:03:17 +03:00
Logger : : instance ( ) - > addMessage (
tr ( " Local Peer Discovery support [%1] " ) . arg ( enabled ? tr ( " ON " ) : tr ( " OFF " ) )
, Log : : INFO ) ;
2016-05-01 11:05:52 +03:00
}
}
bool Session : : isPeXEnabled ( ) const
{
return m_isPeXEnabled ;
}
void Session : : setPeXEnabled ( bool enabled )
{
2016-10-31 03:06:29 +03:00
m_isPeXEnabled = enabled ;
if ( m_wasPexEnabled ! = enabled )
2016-05-01 11:05:52 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " Restart is required to toggle PeX support " ) , Log : : WARNING ) ;
2015-04-19 18:17:47 +03:00
}
bool Session : : isTempPathEnabled ( ) const
{
2016-05-01 11:05:52 +03:00
return m_isTempPathEnabled ;
2015-04-19 18:17:47 +03:00
}
2016-02-09 11:56:48 +03:00
void Session : : setTempPathEnabled ( bool enabled )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( enabled ! = isTempPathEnabled ( ) ) {
m_isTempPathEnabled = enabled ;
foreach ( TorrentHandle * const torrent , m_torrents )
torrent - > handleTempPathChanged ( ) ;
}
2015-04-19 18:17:47 +03:00
}
2016-02-09 11:56:48 +03:00
bool Session : : isAppendExtensionEnabled ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isAppendExtensionEnabled ;
}
void Session : : setAppendExtensionEnabled ( bool enabled )
{
if ( isAppendExtensionEnabled ( ) ! = enabled ) {
// append or remove .!qB extension for incomplete files
foreach ( TorrentHandle * const torrent , m_torrents )
torrent - > handleAppendExtensionToggled ( ) ;
m_isAppendExtensionEnabled = enabled ;
}
}
uint Session : : refreshInterval ( ) const
{
return m_refreshInterval ;
}
void Session : : setRefreshInterval ( uint value )
{
if ( value ! = refreshInterval ( ) ) {
m_refreshTimer - > setInterval ( value ) ;
m_refreshInterval = value ;
}
}
bool Session : : isPreallocationEnabled ( ) const
{
return m_isPreallocationEnabled ;
}
void Session : : setPreallocationEnabled ( bool enabled )
{
m_isPreallocationEnabled = enabled ;
}
QString Session : : torrentExportDirectory ( ) const
{
2016-10-31 03:22:51 +03:00
return Utils : : Fs : : fromNativePath ( m_torrentExportDirectory ) ;
2016-05-01 11:05:52 +03:00
}
2016-10-31 03:22:51 +03:00
void Session : : setTorrentExportDirectory ( QString path )
2016-05-01 11:05:52 +03:00
{
2016-10-31 03:22:51 +03:00
path = Utils : : Fs : : fromNativePath ( path ) ;
if ( path ! = torrentExportDirectory ( ) )
m_torrentExportDirectory = path ;
2016-05-01 11:05:52 +03:00
}
QString Session : : finishedTorrentExportDirectory ( ) const
{
2016-10-31 03:22:51 +03:00
return Utils : : Fs : : fromNativePath ( m_finishedTorrentExportDirectory ) ;
2016-05-01 11:05:52 +03:00
}
2016-10-31 03:22:51 +03:00
void Session : : setFinishedTorrentExportDirectory ( QString path )
2016-05-01 11:05:52 +03:00
{
2016-10-31 03:22:51 +03:00
path = Utils : : Fs : : fromNativePath ( path ) ;
if ( path ! = finishedTorrentExportDirectory ( ) )
m_finishedTorrentExportDirectory = path ;
2015-04-19 18:17:47 +03:00
}
QString Session : : defaultSavePath ( ) const
{
2016-10-31 03:22:51 +03:00
return Utils : : Fs : : fromNativePath ( m_defaultSavePath ) ;
2015-04-19 18:17:47 +03:00
}
QString Session : : tempPath ( ) const
{
2016-10-31 03:22:51 +03:00
return Utils : : Fs : : fromNativePath ( m_tempPath ) ;
2015-04-19 18:17:47 +03:00
}
2017-07-28 12:13:57 +03:00
QString Session : : torrentTempPath ( const TorrentInfo & torrentInfo ) const
2016-04-23 19:34:01 +03:00
{
2017-07-28 12:13:57 +03:00
if ( ( torrentInfo . filesCount ( ) > 1 ) & & ! torrentInfo . hasRootFolder ( ) )
return tempPath ( )
+ QString : : fromStdString ( torrentInfo . nativeInfo ( ) - > orig_files ( ) . name ( ) )
2016-04-23 21:01:56 +03:00
+ " / " ;
2017-07-28 12:13:57 +03:00
return tempPath ( ) ;
2016-04-23 19:34:01 +03:00
}
2016-02-09 11:56:48 +03:00
bool Session : : isValidCategoryName ( const QString & name )
{
2016-03-06 09:25:55 +03:00
QRegExp re ( R " (^([^ \\ \ /]|[^ \\ \ /]([^ \\ \ /]| \ /(?=[^ \ /]) ) * [ ^ \ \ \ / ] ) $ ) " ) ;
2016-02-09 11:56:48 +03:00
if ( ! name . isEmpty ( ) & & ( re . indexIn ( name ) ! = 0 ) ) {
qDebug ( ) < < " Incorrect category name: " < < name ;
return false ;
}
return true ;
}
QStringList Session : : expandCategory ( const QString & category )
{
QStringList result ;
if ( ! isValidCategoryName ( category ) )
return result ;
int index = 0 ;
while ( ( index = category . indexOf ( ' / ' , index ) ) > = 0 ) {
result < < category . left ( index ) ;
+ + index ;
}
result < < category ;
return result ;
}
2017-09-24 14:54:42 +03:00
const QStringMap & Session : : categories ( ) const
2016-02-09 11:56:48 +03:00
{
2017-09-24 14:54:42 +03:00
return m_categories ;
2016-02-09 11:56:48 +03:00
}
QString Session : : categorySavePath ( const QString & categoryName ) const
{
QString basePath = m_defaultSavePath ;
if ( categoryName . isEmpty ( ) ) return basePath ;
2016-03-06 09:25:55 +03:00
QString path = m_categories . value ( categoryName ) ;
2016-02-09 11:56:48 +03:00
if ( path . isEmpty ( ) ) // use implicit save path
path = Utils : : Fs : : toValidFileSystemName ( categoryName , true ) ;
if ( ! QDir : : isAbsolutePath ( path ) )
2016-03-06 09:25:55 +03:00
path . prepend ( basePath ) ;
2016-02-09 11:56:48 +03:00
2016-03-06 09:25:55 +03:00
return normalizeSavePath ( path ) ;
2016-02-09 11:56:48 +03:00
}
bool Session : : addCategory ( const QString & name , const QString & savePath )
{
if ( name . isEmpty ( ) ) return false ;
if ( ! isValidCategoryName ( name ) | | m_categories . contains ( name ) )
return false ;
if ( isSubcategoriesEnabled ( ) ) {
foreach ( const QString & parent , expandCategory ( name ) ) {
if ( ( parent ! = name ) & & ! m_categories . contains ( parent ) ) {
m_categories [ parent ] = " " ;
emit categoryAdded ( parent ) ;
}
}
}
m_categories [ name ] = savePath ;
2016-05-01 11:05:52 +03:00
m_storedCategories = map_cast ( m_categories ) ;
2016-02-09 11:56:48 +03:00
emit categoryAdded ( name ) ;
return true ;
}
bool Session : : editCategory ( const QString & name , const QString & savePath )
{
if ( ! m_categories . contains ( name ) ) return false ;
if ( categorySavePath ( name ) = = savePath ) return false ;
m_categories [ name ] = savePath ;
2017-09-24 14:54:42 +03:00
m_storedCategories = map_cast ( m_categories ) ;
2016-05-08 22:47:50 +03:00
if ( isDisableAutoTMMWhenCategorySavePathChanged ( ) ) {
2016-02-09 11:56:48 +03:00
foreach ( TorrentHandle * const torrent , torrents ( ) )
if ( torrent - > category ( ) = = name )
2016-05-08 22:47:50 +03:00
torrent - > setAutoTMMEnabled ( false ) ;
2016-02-09 11:56:48 +03:00
}
else {
foreach ( TorrentHandle * const torrent , torrents ( ) )
if ( torrent - > category ( ) = = name )
torrent - > handleCategorySavePathChanged ( ) ;
}
return true ;
}
bool Session : : removeCategory ( const QString & name )
{
foreach ( TorrentHandle * const torrent , torrents ( ) )
if ( torrent - > belongsToCategory ( name ) )
torrent - > setCategory ( " " ) ;
// remove stored category and its subcategories if exist
bool result = false ;
if ( isSubcategoriesEnabled ( ) ) {
// remove subcategories
QString test = name + " / " ;
foreach ( const QString & category , m_categories . keys ( ) ) {
if ( category . startsWith ( test ) ) {
m_categories . remove ( category ) ;
result = true ;
emit categoryRemoved ( category ) ;
}
}
}
result = ( m_categories . remove ( name ) > 0 ) | | result ;
if ( result ) {
// update stored categories
2016-05-01 11:05:52 +03:00
m_storedCategories = map_cast ( m_categories ) ;
2016-02-09 11:56:48 +03:00
emit categoryRemoved ( name ) ;
}
return result ;
}
bool Session : : isSubcategoriesEnabled ( ) const
{
2016-05-01 11:05:52 +03:00
return m_isSubcategoriesEnabled ;
2016-02-09 11:56:48 +03:00
}
void Session : : setSubcategoriesEnabled ( bool value )
{
if ( isSubcategoriesEnabled ( ) = = value ) return ;
if ( value ) {
// expand categories to include all parent categories
m_categories = expandCategories ( m_categories ) ;
// update stored categories
2016-05-01 11:05:52 +03:00
m_storedCategories = map_cast ( m_categories ) ;
2016-02-09 11:56:48 +03:00
}
else {
// reload categories
2016-05-01 11:05:52 +03:00
m_categories = map_cast ( m_storedCategories ) ;
2016-02-09 11:56:48 +03:00
}
2016-05-01 11:05:52 +03:00
m_isSubcategoriesEnabled = value ;
2016-02-09 11:56:48 +03:00
emit subcategoriesSupportChanged ( ) ;
}
2017-06-05 03:22:17 +03:00
QSet < QString > Session : : tags ( ) const
{
return m_tags ;
}
bool Session : : isValidTag ( const QString & tag )
{
return ( ! tag . trimmed ( ) . isEmpty ( ) & & ! tag . contains ( ' , ' ) ) ;
}
bool Session : : hasTag ( const QString & tag ) const
{
return m_tags . contains ( tag ) ;
}
bool Session : : addTag ( const QString & tag )
{
if ( ! isValidTag ( tag ) )
return false ;
if ( ! hasTag ( tag ) ) {
m_tags . insert ( tag ) ;
m_storedTags = m_tags . toList ( ) ;
emit tagAdded ( tag ) ;
return true ;
}
return false ;
}
bool Session : : removeTag ( const QString & tag )
{
if ( m_tags . remove ( tag ) ) {
foreach ( TorrentHandle * const torrent , torrents ( ) )
torrent - > removeTag ( tag ) ;
m_storedTags = m_tags . toList ( ) ;
emit tagRemoved ( tag ) ;
return true ;
}
return false ;
}
2016-05-08 22:47:50 +03:00
bool Session : : isAutoTMMDisabledByDefault ( ) const
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isAutoTMMDisabledByDefault ;
2016-02-09 11:56:48 +03:00
}
2016-05-08 22:47:50 +03:00
void Session : : setAutoTMMDisabledByDefault ( bool value )
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
m_isAutoTMMDisabledByDefault = value ;
2016-02-09 11:56:48 +03:00
}
2016-05-08 22:47:50 +03:00
bool Session : : isDisableAutoTMMWhenCategoryChanged ( ) const
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isDisableAutoTMMWhenCategoryChanged ;
2016-02-09 11:56:48 +03:00
}
2016-05-08 22:47:50 +03:00
void Session : : setDisableAutoTMMWhenCategoryChanged ( bool value )
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
m_isDisableAutoTMMWhenCategoryChanged = value ;
2016-02-09 11:56:48 +03:00
}
2016-05-08 22:47:50 +03:00
bool Session : : isDisableAutoTMMWhenDefaultSavePathChanged ( ) const
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isDisableAutoTMMWhenDefaultSavePathChanged ;
2016-02-09 11:56:48 +03:00
}
2016-05-08 22:47:50 +03:00
void Session : : setDisableAutoTMMWhenDefaultSavePathChanged ( bool value )
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
m_isDisableAutoTMMWhenDefaultSavePathChanged = value ;
2016-02-09 11:56:48 +03:00
}
2016-05-08 22:47:50 +03:00
bool Session : : isDisableAutoTMMWhenCategorySavePathChanged ( ) const
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isDisableAutoTMMWhenCategorySavePathChanged ;
2016-02-09 11:56:48 +03:00
}
2016-05-08 22:47:50 +03:00
void Session : : setDisableAutoTMMWhenCategorySavePathChanged ( bool value )
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
m_isDisableAutoTMMWhenCategorySavePathChanged = value ;
2016-02-09 11:56:48 +03:00
}
bool Session : : isAddTorrentPaused ( ) const
{
2016-05-01 11:05:52 +03:00
return m_isAddTorrentPaused ;
2016-02-09 11:56:48 +03:00
}
void Session : : setAddTorrentPaused ( bool value )
{
2016-05-01 11:05:52 +03:00
m_isAddTorrentPaused = value ;
}
bool Session : : isTrackerEnabled ( ) const
{
return m_isTrackerEnabled ;
}
void Session : : setTrackerEnabled ( bool enabled )
{
if ( isTrackerEnabled ( ) ! = enabled ) {
enableTracker ( enabled ) ;
m_isTrackerEnabled = enabled ;
}
2016-02-09 11:56:48 +03:00
}
2015-04-19 18:17:47 +03:00
qreal Session : : globalMaxRatio ( ) const
{
return m_globalMaxRatio ;
}
2016-05-01 11:05:52 +03:00
// Torrents will a ratio superior to the given value will
// be automatically deleted
void Session : : setGlobalMaxRatio ( qreal ratio )
{
if ( ratio < 0 )
ratio = - 1. ;
if ( ratio ! = globalMaxRatio ( ) ) {
m_globalMaxRatio = ratio ;
2016-02-07 20:31:50 +03:00
updateSeedingLimitTimer ( ) ;
}
}
int Session : : globalMaxSeedingMinutes ( ) const
{
return m_globalMaxSeedingMinutes ;
}
void Session : : setGlobalMaxSeedingMinutes ( int minutes )
{
if ( minutes < 0 )
minutes = - 1 ;
if ( minutes ! = globalMaxSeedingMinutes ( ) ) {
m_globalMaxSeedingMinutes = minutes ;
updateSeedingLimitTimer ( ) ;
2016-05-01 11:05:52 +03:00
}
}
2015-04-19 18:17:47 +03:00
// Main destructor
Session : : ~ Session ( )
{
// Do some BT related saving
saveResumeData ( ) ;
// We must delete FilterParserThread
// before we delete libtorrent::session
if ( m_filterParser )
delete m_filterParser ;
// We must delete PortForwarderImpl before
// we delete libtorrent::session
Net : : PortForwarder : : freeInstance ( ) ;
qDebug ( " Deleting the session " ) ;
delete m_nativeSession ;
2015-12-13 15:38:19 +03:00
m_ioThread - > quit ( ) ;
m_ioThread - > wait ( ) ;
2015-04-19 18:17:47 +03:00
m_resumeFolderLock . close ( ) ;
m_resumeFolderLock . remove ( ) ;
}
void Session : : initInstance ( )
{
2017-08-20 18:00:23 +03:00
if ( ! m_instance )
2015-04-19 18:17:47 +03:00
m_instance = new Session ;
}
void Session : : freeInstance ( )
{
if ( m_instance ) {
delete m_instance ;
m_instance = 0 ;
}
}
Session * Session : : instance ( )
{
return m_instance ;
}
2016-05-01 11:05:52 +03:00
void Session : : adjustLimits ( )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( isQueueingSystemEnabled ( ) ) {
2016-06-03 17:03:17 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2016-05-01 11:05:52 +03:00
libt : : session_settings sessionSettings ( m_nativeSession - > settings ( ) ) ;
2015-04-19 18:17:47 +03:00
adjustLimits ( sessionSettings ) ;
2016-05-01 11:05:52 +03:00
m_nativeSession - > set_settings ( sessionSettings ) ;
2016-06-03 17:03:17 +03:00
# else
2016-10-30 00:11:52 +03:00
libt : : settings_pack settingsPack = m_nativeSession - > get_settings ( ) ;
2016-06-03 17:03:17 +03:00
adjustLimits ( settingsPack ) ;
m_nativeSession - > apply_settings ( settingsPack ) ;
# endif
2015-04-19 18:17:47 +03:00
}
2016-06-03 17:03:17 +03:00
}
2015-04-19 18:17:47 +03:00
2017-08-20 18:00:23 +03:00
void Session : : applyBandwidthLimits ( )
{
# if LIBTORRENT_VERSION_NUM < 10100
libt : : session_settings sessionSettings ( m_nativeSession - > settings ( ) ) ;
applyBandwidthLimits ( sessionSettings ) ;
m_nativeSession - > set_settings ( sessionSettings ) ;
# else
libt : : settings_pack settingsPack = m_nativeSession - > get_settings ( ) ;
applyBandwidthLimits ( settingsPack ) ;
m_nativeSession - > apply_settings ( settingsPack ) ;
# endif
}
2016-06-03 17:03:17 +03:00
// Set BitTorrent session configuration
void Session : : configure ( )
{
qDebug ( " Configuring session " ) ;
2016-01-20 10:15:10 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2016-06-03 17:03:17 +03:00
libt : : session_settings sessionSettings = m_nativeSession - > settings ( ) ;
configure ( sessionSettings ) ;
m_nativeSession - > set_settings ( sessionSettings ) ;
2016-01-20 10:15:10 +03:00
# else
2016-10-30 00:11:52 +03:00
libt : : settings_pack settingsPack = m_nativeSession - > get_settings ( ) ;
2016-06-03 17:03:17 +03:00
configure ( settingsPack ) ;
m_nativeSession - > apply_settings ( settingsPack ) ;
2017-05-01 19:19:34 +03:00
configurePeerClasses ( ) ;
2016-01-20 10:15:10 +03:00
# endif
2016-05-08 15:45:53 +03:00
2016-06-03 17:03:17 +03:00
if ( m_IPFilteringChanged ) {
2016-10-29 19:14:27 +03:00
if ( isIPFilteringEnabled ( ) )
2016-06-03 17:03:17 +03:00
enableIPFilter ( ) ;
else
disableIPFilter ( ) ;
m_IPFilteringChanged = false ;
}
m_deferredConfigureScheduled = false ;
qDebug ( " Session configured " ) ;
2015-04-19 18:17:47 +03:00
}
2017-03-07 02:34:55 +03:00
void Session : : processBannedIPs ( libt : : ip_filter & filter )
2015-04-19 18:17:47 +03:00
{
2016-06-03 17:03:17 +03:00
// First, import current filter
foreach ( const QString & ip , m_bannedIPs . value ( ) ) {
boost : : system : : error_code ec ;
libt : : address addr = libt : : address : : from_string ( ip . toLatin1 ( ) . constData ( ) , ec ) ;
Q_ASSERT ( ! ec ) ;
2016-10-30 00:11:52 +03:00
if ( ! ec )
filter . add_rule ( addr , addr , libt : : ip_filter : : blocked ) ;
2015-04-19 18:17:47 +03:00
}
}
2016-06-03 17:03:17 +03:00
# if LIBTORRENT_VERSION_NUM >= 10100
void Session : : adjustLimits ( libt : : settings_pack & settingsPack )
2015-04-19 18:17:47 +03:00
{
//Internally increase the queue limits to ensure that the magnet is started
2016-06-03 17:03:17 +03:00
int maxDownloads = maxActiveDownloads ( ) ;
int maxActive = maxActiveTorrents ( ) ;
2015-09-16 21:57:50 +03:00
2016-06-03 17:03:17 +03:00
settingsPack . set_int ( libt : : settings_pack : : active_downloads
, maxDownloads > - 1 ? maxDownloads + m_extraLimit : maxDownloads ) ;
settingsPack . set_int ( libt : : settings_pack : : active_limit
, maxActive > - 1 ? maxActive + m_extraLimit : maxActive ) ;
2015-04-19 18:17:47 +03:00
}
2017-08-20 18:00:23 +03:00
void Session : : applyBandwidthLimits ( libtorrent : : settings_pack & settingsPack )
{
const bool altSpeedLimitEnabled = isAltGlobalSpeedLimitEnabled ( ) ;
settingsPack . set_int ( libt : : settings_pack : : download_rate_limit , altSpeedLimitEnabled ? altGlobalDownloadSpeedLimit ( ) : globalDownloadSpeedLimit ( ) ) ;
settingsPack . set_int ( libt : : settings_pack : : upload_rate_limit , altSpeedLimitEnabled ? altGlobalUploadSpeedLimit ( ) : globalUploadSpeedLimit ( ) ) ;
}
2017-04-29 14:52:28 +03:00
void Session : : initMetrics ( )
{
m_metricIndices . net . hasIncomingConnections = libt : : find_metric_idx ( " net.has_incoming_connections " ) ;
Q_ASSERT ( m_metricIndices . net . hasIncomingConnections > = 0 ) ;
m_metricIndices . net . sentPayloadBytes = libt : : find_metric_idx ( " net.sent_payload_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . sentPayloadBytes > = 0 ) ;
m_metricIndices . net . recvPayloadBytes = libt : : find_metric_idx ( " net.recv_payload_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . recvPayloadBytes > = 0 ) ;
m_metricIndices . net . sentBytes = libt : : find_metric_idx ( " net.sent_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . sentBytes > = 0 ) ;
m_metricIndices . net . recvBytes = libt : : find_metric_idx ( " net.recv_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . recvBytes > = 0 ) ;
m_metricIndices . net . sentIPOverheadBytes = libt : : find_metric_idx ( " net.sent_ip_overhead_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . sentIPOverheadBytes > = 0 ) ;
m_metricIndices . net . recvIPOverheadBytes = libt : : find_metric_idx ( " net.recv_ip_overhead_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . recvIPOverheadBytes > = 0 ) ;
m_metricIndices . net . sentTrackerBytes = libt : : find_metric_idx ( " net.sent_tracker_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . sentTrackerBytes > = 0 ) ;
m_metricIndices . net . recvTrackerBytes = libt : : find_metric_idx ( " net.recv_tracker_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . recvTrackerBytes > = 0 ) ;
m_metricIndices . net . recvRedundantBytes = libt : : find_metric_idx ( " net.recv_redundant_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . recvRedundantBytes > = 0 ) ;
m_metricIndices . net . recvFailedBytes = libt : : find_metric_idx ( " net.recv_failed_bytes " ) ;
Q_ASSERT ( m_metricIndices . net . recvFailedBytes > = 0 ) ;
m_metricIndices . peer . numPeersConnected = libt : : find_metric_idx ( " peer.num_peers_connected " ) ;
Q_ASSERT ( m_metricIndices . peer . numPeersConnected > = 0 ) ;
m_metricIndices . peer . numPeersDownDisk = libt : : find_metric_idx ( " peer.num_peers_down_disk " ) ;
Q_ASSERT ( m_metricIndices . peer . numPeersDownDisk > = 0 ) ;
m_metricIndices . peer . numPeersUpDisk = libt : : find_metric_idx ( " peer.num_peers_up_disk " ) ;
Q_ASSERT ( m_metricIndices . peer . numPeersUpDisk > = 0 ) ;
m_metricIndices . dht . dhtBytesIn = libt : : find_metric_idx ( " dht.dht_bytes_in " ) ;
Q_ASSERT ( m_metricIndices . dht . dhtBytesIn > = 0 ) ;
m_metricIndices . dht . dhtBytesOut = libt : : find_metric_idx ( " dht.dht_bytes_out " ) ;
Q_ASSERT ( m_metricIndices . dht . dhtBytesOut > = 0 ) ;
m_metricIndices . dht . dhtNodes = libt : : find_metric_idx ( " dht.dht_nodes " ) ;
Q_ASSERT ( m_metricIndices . dht . dhtNodes > = 0 ) ;
m_metricIndices . disk . diskBlocksInUse = libt : : find_metric_idx ( " disk.disk_blocks_in_use " ) ;
Q_ASSERT ( m_metricIndices . disk . diskBlocksInUse > = 0 ) ;
m_metricIndices . disk . numBlocksRead = libt : : find_metric_idx ( " disk.num_blocks_read " ) ;
Q_ASSERT ( m_metricIndices . disk . numBlocksRead > = 0 ) ;
m_metricIndices . disk . numBlocksCacheHits = libt : : find_metric_idx ( " disk.num_blocks_cache_hits " ) ;
Q_ASSERT ( m_metricIndices . disk . numBlocksCacheHits > = 0 ) ;
2017-08-14 17:27:31 +03:00
m_metricIndices . disk . writeJobs = libt : : find_metric_idx ( " disk.num_write_ops " ) ;
Q_ASSERT ( m_metricIndices . disk . writeJobs > = 0 ) ;
m_metricIndices . disk . readJobs = libt : : find_metric_idx ( " disk.num_read_ops " ) ;
Q_ASSERT ( m_metricIndices . disk . readJobs > = 0 ) ;
m_metricIndices . disk . hashJobs = libt : : find_metric_idx ( " disk.num_blocks_hashed " ) ;
Q_ASSERT ( m_metricIndices . disk . hashJobs > = 0 ) ;
2017-04-29 14:52:28 +03:00
m_metricIndices . disk . queuedDiskJobs = libt : : find_metric_idx ( " disk.queued_disk_jobs " ) ;
Q_ASSERT ( m_metricIndices . disk . queuedDiskJobs > = 0 ) ;
m_metricIndices . disk . diskJobTime = libt : : find_metric_idx ( " disk.disk_job_time " ) ;
Q_ASSERT ( m_metricIndices . disk . diskJobTime > = 0 ) ;
}
2016-06-03 17:03:17 +03:00
void Session : : configure ( libtorrent : : settings_pack & settingsPack )
2015-04-19 18:17:47 +03:00
{
2016-06-03 17:03:17 +03:00
Logger * const logger = Logger : : instance ( ) ;
2015-04-19 18:17:47 +03:00
2017-08-13 00:58:22 +03:00
# ifdef Q_OS_WIN
QString chosenIP ;
# endif
2016-06-03 17:03:17 +03:00
if ( m_listenInterfaceChanged ) {
const ushort port = this - > port ( ) ;
std : : pair < int , int > ports ( port , port ) ;
settingsPack . set_int ( libt : : settings_pack : : max_retry_port_bind , ports . second - ports . first ) ;
foreach ( QString ip , getListeningIPs ( ) ) {
libt : : error_code ec ;
std : : string interfacesStr ;
if ( ip . isEmpty ( ) ) {
ip = QLatin1String ( " 0.0.0.0 " ) ;
interfacesStr = std : : string ( ( QString ( " %1:%2 " ) . arg ( ip ) . arg ( port ) ) . toLatin1 ( ) . constData ( ) ) ;
logger - > addMessage ( tr ( " qBittorrent is trying to listen on any interface port: %1 "
, " e.g: qBittorrent is trying to listen on any interface port: TCP/6881 " )
. arg ( QString : : number ( port ) )
, Log : : INFO ) ;
settingsPack . set_str ( libt : : settings_pack : : listen_interfaces , interfacesStr ) ;
break ;
}
libt : : address addr = libt : : address : : from_string ( ip . toLatin1 ( ) . constData ( ) , ec ) ;
if ( ! ec ) {
interfacesStr = std : : string ( ( addr . is_v6 ( ) ? QString ( " [%1]:%2 " ) : QString ( " %1:%2 " ) )
. arg ( ip ) . arg ( port ) . toLatin1 ( ) . constData ( ) ) ;
logger - > addMessage ( tr ( " qBittorrent is trying to listen on interface %1 port: %2 "
, " e.g: qBittorrent is trying to listen on interface 192.168.0.1 port: TCP/6881 " )
. arg ( ip ) . arg ( port )
, Log : : INFO ) ;
settingsPack . set_str ( libt : : settings_pack : : listen_interfaces , interfacesStr ) ;
2017-08-13 00:58:22 +03:00
# ifdef Q_OS_WIN
chosenIP = ip ;
# endif
2016-06-03 17:03:17 +03:00
break ;
}
}
2015-04-19 18:17:47 +03:00
2017-08-13 00:58:22 +03:00
# ifdef Q_OS_WIN
// On Vista+ versions and after Qt 5.5 QNetworkInterface::name() returns
// the interface's Luid and not the GUID.
// Libtorrent expects GUIDs for the 'outgoing_interfaces' setting.
if ( ! networkInterface ( ) . isEmpty ( ) ) {
QString guid = convertIfaceNameToGuid ( networkInterface ( ) ) ;
if ( ! guid . isEmpty ( ) ) {
settingsPack . set_str ( libt : : settings_pack : : outgoing_interfaces , guid . toStdString ( ) ) ;
}
else {
settingsPack . set_str ( libt : : settings_pack : : outgoing_interfaces , chosenIP . toStdString ( ) ) ;
LogMsg ( tr ( " Could not get GUID of configured network interface. Binding to IP %1 " ) . arg ( chosenIP )
, Log : : WARNING ) ;
}
}
# else
2017-07-12 22:28:00 +03:00
settingsPack . set_str ( libt : : settings_pack : : outgoing_interfaces , networkInterface ( ) . toStdString ( ) ) ;
2017-08-13 00:58:22 +03:00
# endif
2016-06-03 17:03:17 +03:00
m_listenInterfaceChanged = false ;
2015-04-19 18:17:47 +03:00
}
2017-08-20 18:00:23 +03:00
applyBandwidthLimits ( settingsPack ) ;
2015-04-19 18:17:47 +03:00
2016-06-03 17:03:17 +03:00
// The most secure, rc4 only so that all streams are encrypted
settingsPack . set_int ( libt : : settings_pack : : allowed_enc_level , libt : : settings_pack : : pe_rc4 ) ;
settingsPack . set_bool ( libt : : settings_pack : : prefer_rc4 , true ) ;
switch ( encryption ( ) ) {
case 0 : //Enabled
settingsPack . set_int ( libt : : settings_pack : : out_enc_policy , libt : : settings_pack : : pe_enabled ) ;
settingsPack . set_int ( libt : : settings_pack : : in_enc_policy , libt : : settings_pack : : pe_enabled ) ;
break ;
case 1 : // Forced
settingsPack . set_int ( libt : : settings_pack : : out_enc_policy , libt : : settings_pack : : pe_forced ) ;
settingsPack . set_int ( libt : : settings_pack : : in_enc_policy , libt : : settings_pack : : pe_forced ) ;
break ;
default : // Disabled
settingsPack . set_int ( libt : : settings_pack : : out_enc_policy , libt : : settings_pack : : pe_disabled ) ;
settingsPack . set_int ( libt : : settings_pack : : in_enc_policy , libt : : settings_pack : : pe_disabled ) ;
}
auto proxyManager = Net : : ProxyConfigurationManager : : instance ( ) ;
Net : : ProxyConfiguration proxyConfig = proxyManager - > proxyConfiguration ( ) ;
if ( m_useProxy | | ( proxyConfig . type ! = Net : : ProxyType : : None ) ) {
if ( proxyConfig . type ! = Net : : ProxyType : : None ) {
2017-03-06 18:51:35 +03:00
settingsPack . set_str ( libt : : settings_pack : : proxy_hostname , proxyConfig . ip . toStdString ( ) ) ;
2016-06-03 17:03:17 +03:00
settingsPack . set_int ( libt : : settings_pack : : proxy_port , proxyConfig . port ) ;
if ( proxyManager - > isAuthenticationRequired ( ) ) {
2017-03-06 18:51:35 +03:00
settingsPack . set_str ( libt : : settings_pack : : proxy_username , proxyConfig . username . toStdString ( ) ) ;
settingsPack . set_str ( libt : : settings_pack : : proxy_password , proxyConfig . password . toStdString ( ) ) ;
2016-06-03 17:03:17 +03:00
}
settingsPack . set_bool ( libt : : settings_pack : : proxy_peer_connections , isProxyPeerConnectionsEnabled ( ) ) ;
2015-04-19 18:17:47 +03:00
}
2016-06-03 17:03:17 +03:00
switch ( proxyConfig . type ) {
case Net : : ProxyType : : HTTP :
settingsPack . set_int ( libt : : settings_pack : : proxy_type , libt : : settings_pack : : http ) ;
break ;
case Net : : ProxyType : : HTTP_PW :
settingsPack . set_int ( libt : : settings_pack : : proxy_type , libt : : settings_pack : : http_pw ) ;
break ;
case Net : : ProxyType : : SOCKS4 :
settingsPack . set_int ( libt : : settings_pack : : proxy_type , libt : : settings_pack : : socks4 ) ;
break ;
case Net : : ProxyType : : SOCKS5 :
settingsPack . set_int ( libt : : settings_pack : : proxy_type , libt : : settings_pack : : socks5 ) ;
break ;
case Net : : ProxyType : : SOCKS5_PW :
settingsPack . set_int ( libt : : settings_pack : : proxy_type , libt : : settings_pack : : socks5_pw ) ;
break ;
default :
settingsPack . set_int ( libt : : settings_pack : : proxy_type , libt : : settings_pack : : none ) ;
}
2015-04-19 18:17:47 +03:00
2016-06-03 17:03:17 +03:00
m_useProxy = ( proxyConfig . type ! = Net : : ProxyType : : None ) ;
2015-04-19 18:17:47 +03:00
}
2016-06-03 17:03:17 +03:00
settingsPack . set_bool ( libt : : settings_pack : : force_proxy , m_useProxy ? isForceProxyEnabled ( ) : false ) ;
2015-04-19 18:17:47 +03:00
2017-10-30 21:04:14 +03:00
settingsPack . set_bool ( libt : : settings_pack : : announce_to_all_trackers , announceToAllTrackers ( ) ) ;
settingsPack . set_bool ( libt : : settings_pack : : announce_to_all_tiers , announceToAllTiers ( ) ) ;
2015-04-19 18:17:47 +03:00
2017-08-18 03:05:36 +03:00
const int cacheSize = ( diskCacheSize ( ) > - 1 ) ? diskCacheSize ( ) * 64 : - 1 ;
settingsPack . set_int ( libt : : settings_pack : : cache_size , cacheSize ) ;
2016-06-03 17:03:17 +03:00
settingsPack . set_int ( libt : : settings_pack : : cache_expiry , diskCacheTTL ( ) ) ;
qDebug ( ) < < " Using a disk cache size of " < < cacheSize < < " MiB " ;
2015-04-19 18:17:47 +03:00
2016-06-03 17:03:17 +03:00
libt : : settings_pack : : io_buffer_mode_t mode = useOSCache ( ) ? libt : : settings_pack : : enable_os_cache
: libt : : settings_pack : : disable_os_cache ;
settingsPack . set_int ( libt : : settings_pack : : disk_io_read_mode , mode ) ;
settingsPack . set_int ( libt : : settings_pack : : disk_io_write_mode , mode ) ;
2017-08-11 10:50:56 +03:00
settingsPack . set_bool ( libt : : settings_pack : : guided_read_cache , isGuidedReadCacheEnabled ( ) ) ;
2017-08-31 21:17:09 +03:00
settingsPack . set_int ( libt : : settings_pack : : suggest_mode , isSuggestModeEnabled ( )
? libt : : settings_pack : : suggest_read_cache : libt : : settings_pack : : no_piece_suggestions ) ;
2015-04-19 18:17:47 +03:00
2017-08-11 14:48:58 +03:00
settingsPack . set_int ( libt : : settings_pack : : send_buffer_watermark , sendBufferWatermark ( ) * 1024 ) ;
settingsPack . set_int ( libt : : settings_pack : : send_buffer_low_watermark , sendBufferLowWatermark ( ) * 1024 ) ;
settingsPack . set_int ( libt : : settings_pack : : send_buffer_watermark_factor , sendBufferWatermarkFactor ( ) ) ;
2015-04-19 18:17:47 +03:00
2016-06-03 17:03:17 +03:00
settingsPack . set_bool ( libt : : settings_pack : : anonymous_mode , isAnonymousModeEnabled ( ) ) ;
2015-04-19 18:17:47 +03:00
2016-06-03 17:03:17 +03:00
// Queueing System
if ( isQueueingSystemEnabled ( ) ) {
adjustLimits ( settingsPack ) ;
2015-04-19 18:17:47 +03:00
2016-06-03 17:03:17 +03:00
settingsPack . set_int ( libt : : settings_pack : : active_seeds , maxActiveUploads ( ) ) ;
settingsPack . set_bool ( libt : : settings_pack : : dont_count_slow_torrents , ignoreSlowTorrentsForQueueing ( ) ) ;
2015-04-19 18:17:47 +03:00
}
else {
2016-06-03 17:03:17 +03:00
settingsPack . set_int ( libt : : settings_pack : : active_downloads , - 1 ) ;
settingsPack . set_int ( libt : : settings_pack : : active_seeds , - 1 ) ;
settingsPack . set_int ( libt : : settings_pack : : active_limit , - 1 ) ;
2015-04-19 18:17:47 +03:00
}
2016-06-03 17:03:17 +03:00
settingsPack . set_int ( libt : : settings_pack : : active_tracker_limit , - 1 ) ;
settingsPack . set_int ( libt : : settings_pack : : active_dht_limit , - 1 ) ;
settingsPack . set_int ( libt : : settings_pack : : active_lsd_limit , - 1 ) ;
2017-01-23 18:45:37 +03:00
// 1 active torrent force 2 connections. If you have more active torrents * 2 than connection limit,
// connection limit will get extended. Multiply max connections or active torrents by 10 for queue.
// Ignore -1 values because we don't want to set a max int message queue
settingsPack . set_int ( libt : : settings_pack : : alert_queue_size , std : : max ( 1000 ,
10 * std : : max ( maxActiveTorrents ( ) * 2 , maxConnections ( ) ) ) ) ;
2015-04-19 18:17:47 +03:00
2016-06-03 17:03:17 +03:00
// Outgoing ports
settingsPack . set_int ( libt : : settings_pack : : outgoing_port , outgoingPortsMin ( ) ) ;
settingsPack . set_int ( libt : : settings_pack : : num_outgoing_ports , outgoingPortsMax ( ) - outgoingPortsMin ( ) + 1 ) ;
// Include overhead in transfer limits
settingsPack . set_bool ( libt : : settings_pack : : rate_limit_ip_overhead , includeOverheadInLimits ( ) ) ;
// IP address to announce to trackers
2017-03-06 18:51:35 +03:00
settingsPack . set_str ( libt : : settings_pack : : announce_ip , announceIP ( ) . toStdString ( ) ) ;
2016-06-03 17:03:17 +03:00
// Super seeding
settingsPack . set_bool ( libt : : settings_pack : : strict_super_seeding , isSuperSeedingEnabled ( ) ) ;
// * Max connections limit
settingsPack . set_int ( libt : : settings_pack : : connections_limit , maxConnections ( ) ) ;
// * Global max upload slots
settingsPack . set_int ( libt : : settings_pack : : unchoke_slots_limit , maxUploads ( ) ) ;
// uTP
2017-09-13 23:29:54 +03:00
switch ( btProtocol ( ) ) {
case BTProtocol : : Both :
default :
settingsPack . set_bool ( libt : : settings_pack : : enable_incoming_tcp , true ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_outgoing_tcp , true ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_incoming_utp , true ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_outgoing_utp , true ) ;
break ;
case BTProtocol : : TCP :
settingsPack . set_bool ( libt : : settings_pack : : enable_incoming_tcp , true ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_outgoing_tcp , true ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_incoming_utp , false ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_outgoing_utp , false ) ;
break ;
case BTProtocol : : UTP :
settingsPack . set_bool ( libt : : settings_pack : : enable_incoming_tcp , false ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_outgoing_tcp , false ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_incoming_utp , true ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_outgoing_utp , true ) ;
break ;
}
2017-08-15 21:23:07 +03:00
switch ( utpMixedMode ( ) ) {
case MixedModeAlgorithm : : TCP :
default :
settingsPack . set_int ( libt : : settings_pack : : mixed_mode_algorithm , libt : : settings_pack : : prefer_tcp ) ;
break ;
case MixedModeAlgorithm : : Proportional :
settingsPack . set_int ( libt : : settings_pack : : mixed_mode_algorithm , libt : : settings_pack : : peer_proportional ) ;
break ;
}
2016-06-03 17:03:17 +03:00
2017-08-11 11:37:32 +03:00
settingsPack . set_bool ( libt : : settings_pack : : allow_multiple_connections_per_ip , multiConnectionsPerIpEnabled ( ) ) ;
2016-06-03 17:03:17 +03:00
settingsPack . set_bool ( libt : : settings_pack : : apply_ip_filter_to_trackers , isTrackerFilteringEnabled ( ) ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_dht , isDHTEnabled ( ) ) ;
2016-10-31 03:52:29 +03:00
if ( isDHTEnabled ( ) )
2016-10-31 03:55:17 +03:00
settingsPack . set_str ( libt : : 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 " ) ;
2016-06-03 17:03:17 +03:00
settingsPack . set_bool ( libt : : settings_pack : : enable_lsd , isLSDEnabled ( ) ) ;
2017-08-11 12:06:31 +03:00
switch ( chokingAlgorithm ( ) ) {
2017-08-15 21:23:07 +03:00
case ChokingAlgorithm : : FixedSlots :
2017-08-11 12:06:31 +03:00
default :
settingsPack . set_int ( libt : : settings_pack : : choking_algorithm , libt : : settings_pack : : fixed_slots_choker ) ;
break ;
2017-08-15 21:23:07 +03:00
case ChokingAlgorithm : : RateBased :
2017-08-11 12:06:31 +03:00
settingsPack . set_int ( libt : : settings_pack : : choking_algorithm , libt : : settings_pack : : rate_based_choker ) ;
break ;
}
2017-08-15 21:23:07 +03:00
switch ( seedChokingAlgorithm ( ) ) {
case SeedChokingAlgorithm : : RoundRobin :
settingsPack . set_int ( libt : : settings_pack : : seed_choking_algorithm , libt : : settings_pack : : round_robin ) ;
break ;
case SeedChokingAlgorithm : : FastestUpload :
default :
settingsPack . set_int ( libt : : settings_pack : : seed_choking_algorithm , libt : : settings_pack : : fastest_upload ) ;
break ;
case SeedChokingAlgorithm : : AntiLeech :
settingsPack . set_int ( libt : : settings_pack : : seed_choking_algorithm , libt : : settings_pack : : anti_leech ) ;
break ;
}
2016-05-01 11:05:52 +03:00
}
2017-05-01 19:19:34 +03:00
void Session : : configurePeerClasses ( )
{
libt : : ip_filter f ;
f . add_rule ( libt : : address_v4 : : from_string ( " 0.0.0.0 " )
, libt : : address_v4 : : from_string ( " 255.255.255.255 " )
, 1 < < libt : : session : : global_peer_class_id ) ;
# if TORRENT_USE_IPV6
2017-08-11 23:12:56 +03:00
// IPv6 may not be available on OS and the parsing
// would result in an exception -> abnormal program termination
// Affects Windows XP
try {
f . add_rule ( libt : : address_v6 : : from_string ( " ::0 " )
, libt : : address_v6 : : from_string ( " ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff " )
, 1 < < libt : : session : : global_peer_class_id ) ;
}
2017-08-12 16:21:01 +03:00
catch ( std : : exception & ) { }
2017-05-01 19:19:34 +03:00
# endif
if ( ignoreLimitsOnLAN ( ) ) {
2017-05-02 18:11:23 +03:00
// local networks
2017-05-01 19:19:34 +03:00
f . add_rule ( libt : : address_v4 : : from_string ( " 10.0.0.0 " )
, libt : : address_v4 : : from_string ( " 10.255.255.255 " )
, 1 < < libt : : session : : local_peer_class_id ) ;
f . add_rule ( libt : : address_v4 : : from_string ( " 172.16.0.0 " )
2017-05-02 18:11:23 +03:00
, libt : : address_v4 : : from_string ( " 172.31.255.255 " )
2017-05-01 19:19:34 +03:00
, 1 < < libt : : session : : local_peer_class_id ) ;
f . add_rule ( libt : : address_v4 : : from_string ( " 192.168.0.0 " )
, libt : : address_v4 : : from_string ( " 192.168.255.255 " )
, 1 < < libt : : session : : local_peer_class_id ) ;
2017-05-02 18:11:23 +03:00
// link local
2017-05-01 19:19:34 +03:00
f . add_rule ( libt : : address_v4 : : from_string ( " 169.254.0.0 " )
, libt : : address_v4 : : from_string ( " 169.254.255.255 " )
, 1 < < libt : : session : : local_peer_class_id ) ;
2017-05-02 18:11:23 +03:00
// loopback
2017-05-01 19:19:34 +03:00
f . add_rule ( libt : : address_v4 : : from_string ( " 127.0.0.0 " )
, libt : : address_v4 : : from_string ( " 127.255.255.255 " )
, 1 < < libt : : session : : local_peer_class_id ) ;
# if TORRENT_USE_IPV6
2017-08-11 23:12:56 +03:00
// IPv6 may not be available on OS and the parsing
// would result in an exception -> abnormal program termination
// Affects Windows XP
try {
// link local
f . add_rule ( libt : : address_v6 : : from_string ( " fe80:: " )
, libt : : address_v6 : : from_string ( " febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff " )
, 1 < < libt : : session : : local_peer_class_id ) ;
// unique local addresses
f . add_rule ( libt : : address_v6 : : from_string ( " fc00:: " )
, libt : : address_v6 : : from_string ( " fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff " )
, 1 < < libt : : session : : local_peer_class_id ) ;
// loopback
f . add_rule ( libt : : address_v6 : : from_string ( " ::1 " )
, libt : : address_v6 : : from_string ( " ::1 " )
, 1 < < libt : : session : : local_peer_class_id ) ;
}
2017-08-12 16:21:01 +03:00
catch ( std : : exception & ) { }
2017-05-01 19:19:34 +03:00
# endif
}
m_nativeSession - > set_peer_class_filter ( f ) ;
libt : : peer_class_type_filter peerClassTypeFilter ;
peerClassTypeFilter . add ( libt : : peer_class_type_filter : : tcp_socket , libt : : session : : tcp_peer_class_id ) ;
peerClassTypeFilter . add ( libt : : peer_class_type_filter : : ssl_tcp_socket , libt : : session : : tcp_peer_class_id ) ;
peerClassTypeFilter . add ( libt : : peer_class_type_filter : : i2p_socket , libt : : session : : tcp_peer_class_id ) ;
if ( isUTPRateLimited ( ) ) {
peerClassTypeFilter . add ( libt : : peer_class_type_filter : : utp_socket
, libt : : session : : local_peer_class_id ) ;
peerClassTypeFilter . add ( libt : : peer_class_type_filter : : utp_socket
, libt : : session : : global_peer_class_id ) ;
peerClassTypeFilter . add ( libt : : peer_class_type_filter : : ssl_utp_socket
, libt : : session : : local_peer_class_id ) ;
peerClassTypeFilter . add ( libt : : peer_class_type_filter : : ssl_utp_socket
, libt : : session : : global_peer_class_id ) ;
}
m_nativeSession - > set_peer_class_type_filter ( peerClassTypeFilter ) ;
}
2016-06-03 17:03:17 +03:00
# else
2016-05-01 11:05:52 +03:00
void Session : : adjustLimits ( libt : : session_settings & sessionSettings )
{
//Internally increase the queue limits to ensure that the magnet is started
2016-10-30 00:10:42 +03:00
int maxDownloads = maxActiveDownloads ( ) ;
2016-05-01 11:05:52 +03:00
int maxActive = maxActiveTorrents ( ) ;
2016-10-30 00:10:42 +03:00
sessionSettings . active_downloads = maxDownloads > - 1 ? maxDownloads + m_extraLimit : maxDownloads ;
sessionSettings . active_limit = maxActive > - 1 ? maxActive + m_extraLimit : maxActive ;
2016-05-01 11:05:52 +03:00
}
2017-08-20 18:00:23 +03:00
void Session : : applyBandwidthLimits ( libt : : session_settings & sessionSettings )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
const bool altSpeedLimitEnabled = isAltGlobalSpeedLimitEnabled ( ) ;
sessionSettings . download_rate_limit = altSpeedLimitEnabled ? altGlobalDownloadSpeedLimit ( ) : globalDownloadSpeedLimit ( ) ;
sessionSettings . upload_rate_limit = altSpeedLimitEnabled ? altGlobalUploadSpeedLimit ( ) : globalUploadSpeedLimit ( ) ;
2017-08-20 18:00:23 +03:00
}
void Session : : configure ( libtorrent : : session_settings & sessionSettings )
{
applyBandwidthLimits ( sessionSettings ) ;
2016-05-01 11:05:52 +03:00
2016-06-03 17:03:17 +03:00
// The most secure, rc4 only so that all streams are encrypted
libt : : pe_settings encryptionSettings ;
2015-04-19 18:17:47 +03:00
encryptionSettings . allowed_enc_level = libt : : pe_settings : : rc4 ;
encryptionSettings . prefer_rc4 = true ;
2016-06-03 17:03:17 +03:00
switch ( encryption ( ) ) {
2015-04-19 18:17:47 +03:00
case 0 : //Enabled
encryptionSettings . out_enc_policy = libt : : pe_settings : : enabled ;
encryptionSettings . in_enc_policy = libt : : pe_settings : : enabled ;
break ;
case 1 : // Forced
encryptionSettings . out_enc_policy = libt : : pe_settings : : forced ;
encryptionSettings . in_enc_policy = libt : : pe_settings : : forced ;
break ;
default : // Disabled
encryptionSettings . out_enc_policy = libt : : pe_settings : : disabled ;
encryptionSettings . in_enc_policy = libt : : pe_settings : : disabled ;
}
m_nativeSession - > set_pe_settings ( encryptionSettings ) ;
2016-06-03 17:03:17 +03:00
auto proxyManager = Net : : ProxyConfigurationManager : : instance ( ) ;
Net : : ProxyConfiguration proxyConfig = proxyManager - > proxyConfiguration ( ) ;
if ( m_useProxy | | ( proxyConfig . type ! = Net : : ProxyType : : None ) ) {
libt : : proxy_settings proxySettings ;
if ( proxyConfig . type ! = Net : : ProxyType : : None ) {
2017-03-06 18:51:35 +03:00
proxySettings . hostname = proxyConfig . ip . toStdString ( ) ;
2016-06-03 17:03:17 +03:00
proxySettings . port = proxyConfig . port ;
if ( proxyManager - > isAuthenticationRequired ( ) ) {
2017-03-06 18:51:35 +03:00
proxySettings . username = proxyConfig . username . toStdString ( ) ;
proxySettings . password = proxyConfig . password . toStdString ( ) ;
2016-06-03 17:03:17 +03:00
}
proxySettings . proxy_peer_connections = isProxyPeerConnectionsEnabled ( ) ;
2015-06-30 21:03:17 +03:00
}
2016-06-03 17:03:17 +03:00
switch ( proxyConfig . type ) {
case Net : : ProxyType : : HTTP :
proxySettings . type = libt : : proxy_settings : : http ;
break ;
case Net : : ProxyType : : HTTP_PW :
proxySettings . type = libt : : proxy_settings : : http_pw ;
break ;
case Net : : ProxyType : : SOCKS4 :
proxySettings . type = libt : : proxy_settings : : socks4 ;
break ;
case Net : : ProxyType : : SOCKS5 :
proxySettings . type = libt : : proxy_settings : : socks5 ;
break ;
case Net : : ProxyType : : SOCKS5_PW :
proxySettings . type = libt : : proxy_settings : : socks5_pw ;
break ;
default :
proxySettings . type = libt : : proxy_settings : : none ;
2015-04-19 18:17:47 +03:00
}
2016-06-03 17:03:17 +03:00
m_nativeSession - > set_proxy ( proxySettings ) ;
m_useProxy = ( proxyConfig . type ! = Net : : ProxyType : : None ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
sessionSettings . force_proxy = m_useProxy ? isForceProxyEnabled ( ) : false ;
2015-04-19 18:17:47 +03:00
2017-10-30 21:04:14 +03:00
sessionSettings . announce_to_all_trackers = announceToAllTrackers ( ) ;
sessionSettings . announce_to_all_tiers = announceToAllTiers ( ) ;
2017-08-18 03:05:36 +03:00
const int cacheSize = ( diskCacheSize ( ) > - 1 ) ? diskCacheSize ( ) * 64 : - 1 ;
sessionSettings . cache_size = cacheSize ;
2016-05-01 11:05:52 +03:00
sessionSettings . cache_expiry = diskCacheTTL ( ) ;
qDebug ( ) < < " Using a disk cache size of " < < cacheSize < < " MiB " ;
libt : : session_settings : : io_buffer_mode_t mode = useOSCache ( ) ? libt : : session_settings : : enable_os_cache
: libt : : session_settings : : disable_os_cache ;
2015-04-19 18:17:47 +03:00
sessionSettings . disk_io_read_mode = mode ;
sessionSettings . disk_io_write_mode = mode ;
2017-08-11 10:50:56 +03:00
sessionSettings . guided_read_cache = isGuidedReadCacheEnabled ( ) ;
2017-08-31 21:17:09 +03:00
sessionSettings . suggest_mode = isSuggestModeEnabled ( )
? libt : : session_settings : : suggest_read_cache : libt : : session_settings : : no_piece_suggestions ;
2015-04-19 18:17:47 +03:00
2017-08-11 14:48:58 +03:00
sessionSettings . send_buffer_watermark = sendBufferWatermark ( ) * 1024 ;
sessionSettings . send_buffer_low_watermark = sendBufferLowWatermark ( ) * 1024 ;
sessionSettings . send_buffer_watermark_factor = sendBufferWatermarkFactor ( ) ;
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
sessionSettings . anonymous_mode = isAnonymousModeEnabled ( ) ;
2015-04-19 18:17:47 +03:00
// Queueing System
2016-05-01 11:05:52 +03:00
if ( isQueueingSystemEnabled ( ) ) {
2015-04-19 18:17:47 +03:00
adjustLimits ( sessionSettings ) ;
2016-05-01 11:05:52 +03:00
sessionSettings . active_seeds = maxActiveUploads ( ) ;
sessionSettings . dont_count_slow_torrents = ignoreSlowTorrentsForQueueing ( ) ;
2015-04-19 18:17:47 +03:00
}
else {
sessionSettings . active_downloads = - 1 ;
sessionSettings . active_seeds = - 1 ;
sessionSettings . active_limit = - 1 ;
}
2015-09-16 21:57:50 +03:00
sessionSettings . active_tracker_limit = - 1 ;
sessionSettings . active_dht_limit = - 1 ;
sessionSettings . active_lsd_limit = - 1 ;
2017-01-23 18:45:37 +03:00
// 1 active torrent force 2 connections. If you have more active torrents * 2 than connection limit,
// connection limit will get extended. Multiply max connections or active torrents by 10 for queue.
// Ignore -1 values because we don't want to set a max int message queue
sessionSettings . alert_queue_size = std : : max ( 1000 ,
10 * std : : max ( maxActiveTorrents ( ) * 2 , maxConnections ( ) ) ) ;
2015-04-19 18:17:47 +03:00
// Outgoing ports
2016-05-01 11:05:52 +03:00
sessionSettings . outgoing_ports = std : : make_pair ( outgoingPortsMin ( ) , outgoingPortsMax ( ) ) ;
2015-04-19 18:17:47 +03:00
// Ignore limits on LAN
2016-05-01 11:05:52 +03:00
sessionSettings . ignore_limits_on_local_network = ignoreLimitsOnLAN ( ) ;
2015-04-19 18:17:47 +03:00
// Include overhead in transfer limits
2016-05-01 11:05:52 +03:00
sessionSettings . rate_limit_ip_overhead = includeOverheadInLimits ( ) ;
2015-04-19 18:17:47 +03:00
// IP address to announce to trackers
2017-03-06 18:51:35 +03:00
sessionSettings . announce_ip = announceIP ( ) . toStdString ( ) ;
2015-04-19 18:17:47 +03:00
// Super seeding
2016-05-01 11:05:52 +03:00
sessionSettings . strict_super_seeding = isSuperSeedingEnabled ( ) ;
2015-04-19 18:17:47 +03:00
// * Max Half-open connections
2016-05-01 11:05:52 +03:00
sessionSettings . half_open_limit = maxHalfOpenConnections ( ) ;
2015-04-19 18:17:47 +03:00
// * Max connections limit
2016-05-01 11:05:52 +03:00
sessionSettings . connections_limit = maxConnections ( ) ;
2015-04-19 18:17:47 +03:00
// * Global max upload slots
2016-05-01 11:05:52 +03:00
sessionSettings . unchoke_slots_limit = maxUploads ( ) ;
2015-04-19 18:17:47 +03:00
// uTP
2017-09-13 23:29:54 +03:00
switch ( btProtocol ( ) ) {
case BTProtocol : : Both :
default :
sessionSettings . enable_incoming_tcp = true ;
sessionSettings . enable_outgoing_tcp = true ;
sessionSettings . enable_incoming_utp = true ;
sessionSettings . enable_outgoing_utp = true ;
break ;
case BTProtocol : : TCP :
sessionSettings . enable_incoming_tcp = true ;
sessionSettings . enable_outgoing_tcp = true ;
sessionSettings . enable_incoming_utp = false ;
sessionSettings . enable_outgoing_utp = false ;
break ;
case BTProtocol : : UTP :
sessionSettings . enable_incoming_tcp = false ;
sessionSettings . enable_outgoing_tcp = false ;
sessionSettings . enable_incoming_utp = true ;
sessionSettings . enable_outgoing_utp = true ;
break ;
}
2015-04-19 18:17:47 +03:00
// uTP rate limiting
2016-05-01 11:05:52 +03:00
sessionSettings . rate_limit_utp = isUTPRateLimited ( ) ;
2017-08-15 21:23:07 +03:00
switch ( utpMixedMode ( ) ) {
case MixedModeAlgorithm : : TCP :
default :
sessionSettings . mixed_mode_algorithm = libt : : session_settings : : prefer_tcp ;
break ;
case MixedModeAlgorithm : : Proportional :
sessionSettings . mixed_mode_algorithm = libt : : session_settings : : peer_proportional ;
break ;
}
2015-04-19 18:17:47 +03:00
2017-08-11 11:37:32 +03:00
sessionSettings . allow_multiple_connections_per_ip = multiConnectionsPerIpEnabled ( ) ;
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
sessionSettings . apply_ip_filter_to_trackers = isTrackerFilteringEnabled ( ) ;
2015-04-19 18:17:47 +03:00
2016-10-31 03:52:29 +03:00
if ( isDHTEnabled ( ) ) {
// Add first the routers and then start DHT.
2016-10-31 03:55:17 +03:00
m_nativeSession - > add_dht_router ( std : : make_pair ( std : : string ( " dht.libtorrent.org " ) , 25401 ) ) ;
2016-10-31 03:52:29 +03:00
m_nativeSession - > add_dht_router ( std : : make_pair ( std : : string ( " router.bittorrent.com " ) , 6881 ) ) ;
m_nativeSession - > add_dht_router ( std : : make_pair ( std : : string ( " router.utorrent.com " ) , 6881 ) ) ;
m_nativeSession - > add_dht_router ( std : : make_pair ( std : : string ( " dht.transmissionbt.com " ) , 6881 ) ) ;
m_nativeSession - > add_dht_router ( std : : make_pair ( std : : string ( " dht.aelitis.com " ) , 6881 ) ) ; // Vuze
2016-06-03 17:03:17 +03:00
m_nativeSession - > start_dht ( ) ;
2016-10-31 03:52:29 +03:00
}
else {
2016-06-03 17:03:17 +03:00
m_nativeSession - > stop_dht ( ) ;
2016-10-31 03:52:29 +03:00
}
2016-05-01 11:05:52 +03:00
2016-06-03 17:03:17 +03:00
if ( isLSDEnabled ( ) )
m_nativeSession - > start_lsd ( ) ;
else
m_nativeSession - > stop_lsd ( ) ;
2017-08-11 12:06:31 +03:00
switch ( chokingAlgorithm ( ) ) {
2017-08-15 21:23:07 +03:00
case ChokingAlgorithm : : FixedSlots :
2017-08-11 12:06:31 +03:00
default :
sessionSettings . choking_algorithm = libt : : session_settings : : fixed_slots_choker ;
break ;
2017-08-15 21:23:07 +03:00
case ChokingAlgorithm : : RateBased :
2017-08-11 12:06:31 +03:00
sessionSettings . choking_algorithm = libt : : session_settings : : rate_based_choker ;
break ;
}
2017-08-15 21:23:07 +03:00
switch ( seedChokingAlgorithm ( ) ) {
case SeedChokingAlgorithm : : RoundRobin :
sessionSettings . seed_choking_algorithm = libt : : session_settings : : round_robin ;
break ;
case SeedChokingAlgorithm : : FastestUpload :
default :
sessionSettings . seed_choking_algorithm = libt : : session_settings : : fastest_upload ;
break ;
case SeedChokingAlgorithm : : AntiLeech :
sessionSettings . seed_choking_algorithm = libt : : session_settings : : anti_leech ;
break ;
}
2015-04-19 18:17:47 +03:00
}
2016-06-03 17:03:17 +03:00
# endif
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
void Session : : enableTracker ( bool enable )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
Logger * const logger = Logger : : instance ( ) ;
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
if ( enable ) {
2015-04-19 18:17:47 +03:00
if ( ! m_tracker )
m_tracker = new Tracker ( this ) ;
if ( m_tracker - > start ( ) )
logger - > addMessage ( tr ( " Embedded Tracker [ON] " ) , Log : : INFO ) ;
else
logger - > addMessage ( tr ( " Failed to start the embedded tracker! " ) , Log : : CRITICAL ) ;
}
else {
2016-11-06 12:55:31 +03:00
logger - > addMessage ( tr ( " Embedded Tracker [OFF] " ) , Log : : INFO ) ;
2015-04-19 18:17:47 +03:00
if ( m_tracker )
delete m_tracker ;
}
2016-05-01 11:05:52 +03:00
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
void Session : : enableBandwidthScheduler ( )
{
if ( ! m_bwScheduler ) {
m_bwScheduler = new BandwidthScheduler ( this ) ;
2017-08-20 18:00:23 +03:00
connect ( m_bwScheduler . data ( ) , & BandwidthScheduler : : bandwidthLimitRequested
, this , & Session : : setAltGlobalSpeedLimitEnabled ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
m_bwScheduler - > start ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : populateAdditionalTrackers ( )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
m_additionalTrackerList . clear ( ) ;
foreach ( QString tracker , additionalTrackers ( ) . split ( " \n " ) ) {
tracker = tracker . trimmed ( ) ;
if ( ! tracker . isEmpty ( ) )
m_additionalTrackerList < < tracker ;
2015-04-19 18:17:47 +03:00
}
}
2016-02-07 20:31:50 +03:00
void Session : : processShareLimits ( )
2015-04-19 18:17:47 +03:00
{
2016-02-07 20:31:50 +03:00
qDebug ( " Processing share limits... " ) ;
2015-04-19 18:17:47 +03:00
foreach ( TorrentHandle * const torrent , m_torrents ) {
2016-02-07 20:31:50 +03:00
if ( torrent - > isSeed ( ) & & ! torrent - > isForced ( ) ) {
if ( torrent - > ratioLimit ( ) ! = TorrentHandle : : NO_RATIO_LIMIT ) {
const qreal ratio = torrent - > realRatio ( ) ;
qreal ratioLimit = torrent - > ratioLimit ( ) ;
if ( ratioLimit = = TorrentHandle : : USE_GLOBAL_RATIO )
// If Global Max Ratio is really set...
ratioLimit = globalMaxRatio ( ) ;
if ( ratioLimit > = 0 ) {
qDebug ( " Ratio: %f (limit: %f) " , ratio , ratioLimit ) ;
if ( ( ratio < = TorrentHandle : : MAX_RATIO ) & & ( ratio > = ratioLimit ) ) {
Logger * const logger = Logger : : instance ( ) ;
if ( m_maxRatioAction = = Remove ) {
logger - > addMessage ( tr ( " '%1' reached the maximum ratio you set. Removed. " ) . arg ( torrent - > name ( ) ) ) ;
2017-09-11 08:11:09 +03:00
deleteTorrent ( torrent - > hash ( ) ) ;
2016-02-07 20:31:50 +03:00
}
else if ( ! torrent - > isPaused ( ) ) {
torrent - > pause ( ) ;
logger - > addMessage ( tr ( " '%1' reached the maximum ratio you set. Paused. " ) . arg ( torrent - > name ( ) ) ) ;
}
}
2015-04-19 18:17:47 +03:00
}
2016-02-07 20:31:50 +03:00
}
if ( torrent - > seedingTimeLimit ( ) ! = TorrentHandle : : NO_SEEDING_TIME_LIMIT ) {
const int seedingTimeInMinutes = torrent - > seedingTime ( ) / 60 ;
int seedingTimeLimit = torrent - > seedingTimeLimit ( ) ;
if ( seedingTimeLimit = = TorrentHandle : : USE_GLOBAL_SEEDING_TIME )
// If Global Seeding Time Limit is really set...
seedingTimeLimit = globalMaxSeedingMinutes ( ) ;
if ( seedingTimeLimit > = 0 ) {
qDebug ( " Seeding Time: %d (limit: %d) " , seedingTimeInMinutes , seedingTimeLimit ) ;
if ( ( seedingTimeInMinutes < = TorrentHandle : : MAX_SEEDING_TIME ) & & ( seedingTimeInMinutes > = seedingTimeLimit ) ) {
Logger * const logger = Logger : : instance ( ) ;
if ( m_maxRatioAction = = Remove ) {
logger - > addMessage ( tr ( " '%1' reached the maximum seeding time you set. Removed. " ) . arg ( torrent - > name ( ) ) ) ;
2017-09-11 08:11:09 +03:00
deleteTorrent ( torrent - > hash ( ) ) ;
2016-02-07 20:31:50 +03:00
}
else if ( ! torrent - > isPaused ( ) ) {
torrent - > pause ( ) ;
logger - > addMessage ( tr ( " '%1' reached the maximum seeding time you set. Paused. " ) . arg ( torrent - > name ( ) ) ) ;
}
2015-04-19 18:17:47 +03:00
}
}
}
}
}
}
void Session : : handleDownloadFailed ( const QString & url , const QString & reason )
{
emit downloadFromUrlFailed ( url , reason ) ;
}
void Session : : handleRedirectedToMagnet ( const QString & url , const QString & magnetUri )
{
2016-01-01 16:28:40 +03:00
addTorrent_impl ( m_downloadedTorrents . take ( url ) , MagnetUri ( magnetUri ) ) ;
2015-04-19 18:17:47 +03:00
}
// Add to BitTorrent session the downloaded torrent file
void Session : : handleDownloadFinished ( const QString & url , const QString & filePath )
{
emit downloadFromUrlFinished ( url ) ;
2016-01-01 16:28:40 +03:00
addTorrent_impl ( m_downloadedTorrents . take ( url ) , MagnetUri ( ) , TorrentInfo : : loadFromFile ( filePath ) ) ;
2015-05-06 14:53:27 +03:00
Utils : : Fs : : forceRemove ( filePath ) ; // remove temporary file
2015-04-19 18:17:47 +03:00
}
// Return the torrent handle, given its hash
TorrentHandle * Session : : findTorrent ( const InfoHash & hash ) const
{
return m_torrents . value ( hash ) ;
}
bool Session : : hasActiveTorrents ( ) const
{
foreach ( TorrentHandle * const torrent , m_torrents )
if ( TorrentFilter : : ActiveTorrent . match ( torrent ) )
return true ;
return false ;
}
bool Session : : hasUnfinishedTorrents ( ) const
{
foreach ( TorrentHandle * const torrent , m_torrents )
if ( ! torrent - > isSeed ( ) & & ! torrent - > isPaused ( ) )
return true ;
return false ;
}
void Session : : banIP ( const QString & ip )
{
2016-05-01 11:05:52 +03:00
QStringList bannedIPs = m_bannedIPs ;
if ( ! bannedIPs . contains ( ip ) ) {
2016-06-03 17:03:17 +03:00
libt : : ip_filter filter = m_nativeSession - > get_ip_filter ( ) ;
boost : : system : : error_code ec ;
libt : : address addr = libt : : address : : from_string ( ip . toLatin1 ( ) . constData ( ) , ec ) ;
Q_ASSERT ( ! ec ) ;
2016-10-30 00:11:52 +03:00
if ( ec ) return ;
2016-06-03 17:03:17 +03:00
filter . add_rule ( addr , addr , libt : : ip_filter : : blocked ) ;
m_nativeSession - > set_ip_filter ( filter ) ;
2016-05-01 11:05:52 +03:00
bannedIPs < < ip ;
2017-03-06 15:40:34 +03:00
bannedIPs . sort ( ) ;
2016-05-01 11:05:52 +03:00
m_bannedIPs = bannedIPs ;
}
2015-04-19 18:17:47 +03:00
}
// Delete a torrent from the session, given its hash
// deleteLocalFiles = true means that the torrent will be removed from the hard-drive too
bool Session : : deleteTorrent ( const QString & hash , bool deleteLocalFiles )
{
TorrentHandle * const torrent = m_torrents . take ( hash ) ;
if ( ! torrent ) return false ;
2017-08-13 13:56:03 +03:00
qDebug ( " Deleting torrent with hash: %s " , qUtf8Printable ( torrent - > hash ( ) ) ) ;
2015-04-19 18:17:47 +03:00
emit torrentAboutToBeRemoved ( torrent ) ;
// Remove it from session
if ( deleteLocalFiles ) {
2017-08-04 22:29:17 +03:00
QString rootPath = torrent - > rootPath ( true ) ;
if ( ! rootPath . isEmpty ( ) )
// torrent with root folder
2017-09-14 19:55:14 +03:00
m_removingTorrents [ torrent - > hash ( ) ] = { torrent - > name ( ) , rootPath , deleteLocalFiles } ;
2017-08-04 22:29:17 +03:00
else if ( torrent - > useTempPath ( ) )
// torrent without root folder still has it in its temporary save path
2017-09-14 19:55:14 +03:00
m_removingTorrents [ torrent - > hash ( ) ] = { torrent - > name ( ) , torrent - > savePath ( true ) , deleteLocalFiles } ;
else
m_removingTorrents [ torrent - > hash ( ) ] = { torrent - > name ( ) , " " , deleteLocalFiles } ;
2015-04-19 18:17:47 +03:00
m_nativeSession - > remove_torrent ( torrent - > nativeHandle ( ) , libt : : session : : delete_files ) ;
}
else {
2017-09-14 19:55:14 +03:00
m_removingTorrents [ torrent - > hash ( ) ] = { torrent - > name ( ) , " " , deleteLocalFiles } ;
2015-04-19 18:17:47 +03:00
QStringList unwantedFiles ;
if ( torrent - > hasMetadata ( ) )
unwantedFiles = torrent - > absoluteFilePathsUnwanted ( ) ;
2016-03-14 15:53:14 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2015-04-19 18:17:47 +03:00
m_nativeSession - > remove_torrent ( torrent - > nativeHandle ( ) ) ;
2016-03-14 15:53:14 +03:00
# else
m_nativeSession - > remove_torrent ( torrent - > nativeHandle ( ) , libt : : session : : delete_partfile ) ;
# endif
2015-04-19 18:17:47 +03:00
// Remove unwanted and incomplete files
foreach ( const QString & unwantedFile , unwantedFiles ) {
2017-08-13 13:56:03 +03:00
qDebug ( " Removing unwanted file: %s " , qUtf8Printable ( unwantedFile ) ) ;
2015-05-06 14:53:27 +03:00
Utils : : Fs : : forceRemove ( unwantedFile ) ;
const QString parentFolder = Utils : : Fs : : branchPath ( unwantedFile ) ;
2017-08-13 13:56:03 +03:00
qDebug ( " Attempt to remove parent folder (if empty): %s " , qUtf8Printable ( parentFolder ) ) ;
2015-04-19 18:17:47 +03:00
QDir ( ) . rmpath ( parentFolder ) ;
}
}
// Remove it from torrent resume directory
QDir resumeDataDir ( m_resumeFolderPath ) ;
QStringList filters ;
filters < < QString ( " %1.* " ) . arg ( torrent - > hash ( ) ) ;
const QStringList files = resumeDataDir . entryList ( filters , QDir : : Files , QDir : : Unsorted ) ;
foreach ( const QString & file , files )
2015-05-06 14:53:27 +03:00
Utils : : Fs : : forceRemove ( resumeDataDir . absoluteFilePath ( file ) ) ;
2015-04-19 18:17:47 +03:00
delete torrent ;
qDebug ( " Torrent deleted. " ) ;
return true ;
}
bool Session : : cancelLoadMetadata ( const InfoHash & hash )
{
if ( ! m_loadedMetadata . contains ( hash ) ) return false ;
m_loadedMetadata . remove ( hash ) ;
libt : : torrent_handle torrent = m_nativeSession - > find_torrent ( hash ) ;
if ( ! torrent . is_valid ( ) ) return false ;
if ( ! torrent . status ( 0 ) . has_metadata ) {
// if hidden torrent is still loading metadata...
- - m_extraLimit ;
adjustLimits ( ) ;
}
// Remove it from session
m_nativeSession - > remove_torrent ( torrent , libt : : session : : delete_files ) ;
qDebug ( " Preloaded torrent deleted. " ) ;
return true ;
}
void Session : : increaseTorrentsPriority ( const QStringList & hashes )
{
std : : priority_queue < QPair < int , TorrentHandle * > ,
std : : vector < QPair < int , TorrentHandle * > > ,
std : : greater < QPair < int , TorrentHandle * > > > torrentQueue ;
// Sort torrents by priority
foreach ( const InfoHash & hash , hashes ) {
TorrentHandle * const torrent = m_torrents . value ( hash ) ;
if ( torrent & & ! torrent - > isSeed ( ) )
torrentQueue . push ( qMakePair ( torrent - > queuePosition ( ) , torrent ) ) ;
}
// Increase torrents priority (starting with the ones with highest priority)
while ( ! torrentQueue . empty ( ) ) {
TorrentHandle * const torrent = torrentQueue . top ( ) . second ;
torrentQueuePositionUp ( torrent - > nativeHandle ( ) ) ;
torrentQueue . pop ( ) ;
}
}
void Session : : decreaseTorrentsPriority ( const QStringList & hashes )
{
std : : priority_queue < QPair < int , TorrentHandle * > ,
std : : vector < QPair < int , TorrentHandle * > > ,
std : : less < QPair < int , TorrentHandle * > > > torrentQueue ;
// Sort torrents by priority
foreach ( const InfoHash & hash , hashes ) {
TorrentHandle * const torrent = m_torrents . value ( hash ) ;
if ( torrent & & ! torrent - > isSeed ( ) )
torrentQueue . push ( qMakePair ( torrent - > queuePosition ( ) , torrent ) ) ;
}
// Decrease torrents priority (starting with the ones with lowest priority)
while ( ! torrentQueue . empty ( ) ) {
TorrentHandle * const torrent = torrentQueue . top ( ) . second ;
torrentQueuePositionDown ( torrent - > nativeHandle ( ) ) ;
torrentQueue . pop ( ) ;
}
foreach ( const InfoHash & hash , m_loadedMetadata . keys ( ) )
torrentQueuePositionBottom ( m_nativeSession - > find_torrent ( hash ) ) ;
}
void Session : : topTorrentsPriority ( const QStringList & hashes )
{
std : : priority_queue < QPair < int , TorrentHandle * > ,
std : : vector < QPair < int , TorrentHandle * > > ,
std : : greater < QPair < int , TorrentHandle * > > > torrentQueue ;
// Sort torrents by priority
foreach ( const InfoHash & hash , hashes ) {
TorrentHandle * const torrent = m_torrents . value ( hash ) ;
if ( torrent & & ! torrent - > isSeed ( ) )
torrentQueue . push ( qMakePair ( torrent - > queuePosition ( ) , torrent ) ) ;
}
// Top torrents priority (starting with the ones with highest priority)
while ( ! torrentQueue . empty ( ) ) {
TorrentHandle * const torrent = torrentQueue . top ( ) . second ;
torrentQueuePositionTop ( torrent - > nativeHandle ( ) ) ;
torrentQueue . pop ( ) ;
}
}
void Session : : bottomTorrentsPriority ( const QStringList & hashes )
{
std : : priority_queue < QPair < int , TorrentHandle * > ,
std : : vector < QPair < int , TorrentHandle * > > ,
std : : less < QPair < int , TorrentHandle * > > > torrentQueue ;
// Sort torrents by priority
foreach ( const InfoHash & hash , hashes ) {
TorrentHandle * const torrent = m_torrents . value ( hash ) ;
if ( torrent & & ! torrent - > isSeed ( ) )
torrentQueue . push ( qMakePair ( torrent - > queuePosition ( ) , torrent ) ) ;
}
// Bottom torrents priority (starting with the ones with lowest priority)
while ( ! torrentQueue . empty ( ) ) {
TorrentHandle * const torrent = torrentQueue . top ( ) . second ;
torrentQueuePositionBottom ( torrent - > nativeHandle ( ) ) ;
torrentQueue . pop ( ) ;
}
foreach ( const InfoHash & hash , m_loadedMetadata . keys ( ) )
torrentQueuePositionBottom ( m_nativeSession - > find_torrent ( hash ) ) ;
}
QHash < InfoHash , TorrentHandle * > Session : : torrents ( ) const
{
return m_torrents ;
}
2015-11-05 19:17:10 +03:00
TorrentStatusReport Session : : torrentStatusReport ( ) const
{
return m_torrentStatusReport ;
}
2016-01-01 16:28:40 +03:00
// source - .torrent file path/url or magnet uri
2015-04-19 18:17:47 +03:00
bool Session : : addTorrent ( QString source , const AddTorrentParams & params )
{
2016-01-07 14:22:35 +03:00
MagnetUri magnetUri ( source ) ;
if ( magnetUri . isValid ( ) ) {
return addTorrent_impl ( params , magnetUri ) ;
2015-04-19 18:17:47 +03:00
}
2016-01-07 14:22:35 +03:00
else if ( Utils : : Misc : : isUrl ( source ) ) {
2015-04-19 18:17:47 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " Downloading '%1', please wait... " , " e.g: Downloading 'xxx.torrent', please wait... " ) . arg ( source ) ) ;
// Launch downloader
2015-06-03 11:49:39 +03:00
Net : : DownloadHandler * handler = Net : : DownloadManager : : instance ( ) - > downloadUrl ( source , true , 10485760 /* 10MB */ , true ) ;
2015-04-19 18:17:47 +03:00
connect ( handler , SIGNAL ( downloadFinished ( QString , QString ) ) , this , SLOT ( handleDownloadFinished ( QString , QString ) ) ) ;
connect ( handler , SIGNAL ( downloadFailed ( QString , QString ) ) , this , SLOT ( handleDownloadFailed ( QString , QString ) ) ) ;
connect ( handler , SIGNAL ( redirectedToMagnet ( QString , QString ) ) , this , SLOT ( handleRedirectedToMagnet ( QString , QString ) ) ) ;
m_downloadedTorrents [ handler - > url ( ) ] = params ;
}
else {
2016-04-07 17:58:30 +03:00
TorrentFileGuard guard ( source ) ;
2017-01-18 00:55:01 +03:00
if ( addTorrent_impl ( params , MagnetUri ( ) , TorrentInfo : : loadFromFile ( source ) ) ) {
guard . markAsAddedToSession ( ) ;
return true ;
}
2015-04-19 18:17:47 +03:00
}
return false ;
}
bool Session : : addTorrent ( const TorrentInfo & torrentInfo , const AddTorrentParams & params )
{
if ( ! torrentInfo . isValid ( ) ) return false ;
2016-01-01 16:28:40 +03:00
return addTorrent_impl ( params , MagnetUri ( ) , torrentInfo ) ;
2015-04-19 18:17:47 +03:00
}
// Add a torrent to the BitTorrent session
2015-11-01 09:22:18 +03:00
bool Session : : addTorrent_impl ( AddTorrentData addData , const MagnetUri & magnetUri ,
2016-04-19 09:54:48 +03:00
TorrentInfo torrentInfo , const QByteArray & fastresumeData )
2015-04-19 18:17:47 +03:00
{
2017-08-05 23:11:40 +03:00
addData . savePath = normalizeSavePath ( addData . savePath , " " ) ;
2016-02-09 11:56:48 +03:00
if ( ! addData . category . isEmpty ( ) ) {
if ( ! m_categories . contains ( addData . category ) & & ! addCategory ( addData . category ) ) {
qWarning ( ) < < " Couldn't create category " < < addData . category ;
addData . category = " " ;
2016-01-01 16:28:40 +03:00
}
}
2015-04-19 18:17:47 +03:00
libt : : add_torrent_params p ;
InfoHash hash ;
std : : vector < boost : : uint8_t > filePriorities ;
2016-04-19 09:54:48 +03:00
QString savePath ;
2016-05-08 22:47:50 +03:00
if ( addData . savePath . isEmpty ( ) ) // using Automatic mode
2016-04-19 09:54:48 +03:00
savePath = categorySavePath ( addData . category ) ;
2016-05-08 22:47:50 +03:00
else // using Manual mode
2016-04-19 09:54:48 +03:00
savePath = addData . savePath ;
2015-04-19 18:17:47 +03:00
bool fromMagnetUri = magnetUri . isValid ( ) ;
if ( fromMagnetUri ) {
hash = magnetUri . hash ( ) ;
2016-01-01 16:28:40 +03:00
if ( m_loadedMetadata . contains ( hash ) ) {
// Adding preloaded torrent
m_loadedMetadata . remove ( hash ) ;
libt : : torrent_handle handle = m_nativeSession - > find_torrent ( hash ) ;
- - m_extraLimit ;
try {
handle . auto_managed ( false ) ;
handle . pause ( ) ;
}
catch ( std : : exception & ) { }
adjustLimits ( ) ;
// use common 2nd step of torrent addition
m_addingTorrents . insert ( hash , addData ) ;
createTorrentHandle ( handle ) ;
return true ;
}
p = magnetUri . addTorrentParams ( ) ;
2015-04-19 18:17:47 +03:00
}
2015-06-04 11:03:19 +03:00
else if ( torrentInfo . isValid ( ) ) {
2016-01-04 16:00:50 +03:00
if ( ! addData . resumed & & ! addData . hasRootFolder )
torrentInfo . stripRootFolder ( ) ;
2015-04-19 18:17:47 +03:00
// Metadata
2016-04-19 09:54:48 +03:00
if ( ! addData . resumed & & ! addData . hasSeedStatus )
findIncompleteFiles ( torrentInfo , savePath ) ;
2015-04-19 18:17:47 +03:00
p . ti = torrentInfo . nativeInfo ( ) ;
hash = torrentInfo . hash ( ) ;
2015-06-04 11:03:19 +03:00
}
else {
2015-07-15 20:37:27 +03:00
// 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 ;
2015-06-04 11:03:19 +03:00
}
2015-04-19 18:17:47 +03:00
2015-06-04 11:03:19 +03:00
if ( addData . resumed & & ! fromMagnetUri ) {
// Set torrent fast resume data
2017-05-02 14:04:11 +03:00
p . resume_data = { fastresumeData . constData ( ) , fastresumeData . constData ( ) + fastresumeData . size ( ) } ;
2015-06-04 11:03:19 +03:00
p . flags | = libt : : add_torrent_params : : flag_use_resume_save_path ;
}
else {
foreach ( int prio , addData . filePriorities )
filePriorities . push_back ( prio ) ;
p . file_priorities = filePriorities ;
2015-04-19 18:17:47 +03:00
}
// We should not add torrent if it already
// processed or adding to session
if ( m_addingTorrents . contains ( hash ) | | m_loadedMetadata . contains ( hash ) ) return false ;
if ( m_torrents . contains ( hash ) ) {
TorrentHandle * const torrent = m_torrents . value ( hash ) ;
2016-02-15 04:24:22 +03:00
if ( torrent - > isPrivate ( ) | | ( ! fromMagnetUri & & torrentInfo . isPrivate ( ) ) )
return false ;
2015-04-19 18:17:47 +03:00
torrent - > addTrackers ( fromMagnetUri ? magnetUri . trackers ( ) : torrentInfo . trackers ( ) ) ;
torrent - > addUrlSeeds ( fromMagnetUri ? magnetUri . urlSeeds ( ) : torrentInfo . urlSeeds ( ) ) ;
return true ;
}
qDebug ( " Adding torrent... " ) ;
2017-08-13 13:56:03 +03:00
qDebug ( " -> Hash: %s " , qUtf8Printable ( hash ) ) ;
2015-04-19 18:17:47 +03:00
// Preallocation mode
2016-05-01 11:05:52 +03:00
if ( isPreallocationEnabled ( ) )
2015-04-19 18:17:47 +03:00
p . storage_mode = libt : : storage_mode_allocate ;
else
p . storage_mode = libt : : storage_mode_sparse ;
p . flags | = libt : : add_torrent_params : : flag_paused ; // Start in pause
p . flags & = ~ libt : : add_torrent_params : : flag_auto_managed ; // Because it is added in paused state
p . flags & = ~ libt : : add_torrent_params : : flag_duplicate_is_error ; // Already checked
// Seeding mode
// Skip checking and directly start seeding (new in libtorrent v0.15)
2015-10-25 01:39:40 +03:00
if ( addData . skipChecking )
2015-04-19 18:17:47 +03:00
p . flags | = libt : : add_torrent_params : : flag_seed_mode ;
else
p . flags & = ~ libt : : add_torrent_params : : flag_seed_mode ;
// Limits
2016-05-01 11:05:52 +03:00
p . max_connections = maxConnectionsPerTorrent ( ) ;
p . max_uploads = maxUploadsPerTorrent ( ) ;
2017-03-06 18:51:35 +03:00
p . save_path = Utils : : Fs : : toNativePath ( savePath ) . toStdString ( ) ;
2017-08-14 14:44:56 +03:00
p . upload_limit = addData . uploadLimit ;
p . download_limit = addData . downloadLimit ;
2015-04-19 18:17:47 +03:00
m_addingTorrents . insert ( hash , addData ) ;
// Adding torrent to BitTorrent session
m_nativeSession - > async_add_torrent ( p ) ;
return true ;
}
2016-04-19 09:54:48 +03:00
bool Session : : findIncompleteFiles ( TorrentInfo & torrentInfo , QString & savePath ) const
{
auto findInDir = [ ] ( const QString & dirPath , TorrentInfo & torrentInfo ) - > bool
{
2017-04-27 22:31:30 +03:00
const QDir dir ( dirPath ) ;
2016-04-19 09:54:48 +03:00
bool found = false ;
2017-04-27 22:31:30 +03:00
for ( int i = 0 ; i < torrentInfo . filesCount ( ) ; + + i ) {
const QString filePath = torrentInfo . filePath ( i ) ;
if ( dir . exists ( filePath ) ) {
2016-04-19 09:54:48 +03:00
found = true ;
}
2017-04-27 22:31:30 +03:00
else if ( dir . exists ( filePath + QB_EXT ) ) {
2016-04-19 09:54:48 +03:00
found = true ;
2017-04-27 22:31:30 +03:00
torrentInfo . renameFile ( i , filePath + QB_EXT ) ;
2016-04-19 09:54:48 +03:00
}
}
return found ;
} ;
bool found = findInDir ( savePath , torrentInfo ) ;
if ( ! found & & isTempPathEnabled ( ) ) {
2017-07-28 12:13:57 +03:00
savePath = torrentTempPath ( torrentInfo ) ;
2016-04-19 09:54:48 +03:00
found = findInDir ( savePath , torrentInfo ) ;
}
return found ;
}
2015-04-19 18:17:47 +03:00
// Add a torrent to the BitTorrent session in hidden mode
// and force it to load its metadata
2016-01-07 14:22:35 +03:00
bool Session : : loadMetadata ( const MagnetUri & magnetUri )
2015-04-19 18:17:47 +03:00
{
2016-01-07 14:22:35 +03:00
if ( ! magnetUri . isValid ( ) ) return false ;
2015-04-19 18:17:47 +03:00
2016-01-07 14:22:35 +03:00
InfoHash hash = magnetUri . hash ( ) ;
QString name = magnetUri . name ( ) ;
2015-04-19 18:17:47 +03:00
2015-05-04 02:09:30 +03:00
// We should not add torrent if it already
2015-04-19 18:17:47 +03:00
// processed or adding to session
if ( m_torrents . contains ( hash ) ) return false ;
if ( m_addingTorrents . contains ( hash ) ) return false ;
if ( m_loadedMetadata . contains ( hash ) ) return false ;
qDebug ( " Adding torrent to preload metadata... " ) ;
2017-08-13 13:56:03 +03:00
qDebug ( " -> Hash: %s " , qUtf8Printable ( hash ) ) ;
qDebug ( " -> Name: %s " , qUtf8Printable ( name ) ) ;
2015-04-19 18:17:47 +03:00
2016-01-07 14:22:35 +03:00
libt : : add_torrent_params p = magnetUri . addTorrentParams ( ) ;
2015-04-19 18:17:47 +03:00
// Flags
// Preallocation mode
2016-05-01 11:05:52 +03:00
if ( isPreallocationEnabled ( ) )
2015-04-19 18:17:47 +03:00
p . storage_mode = libt : : storage_mode_allocate ;
else
p . storage_mode = libt : : storage_mode_sparse ;
// Limits
2016-05-01 11:05:52 +03:00
p . max_connections = maxConnectionsPerTorrent ( ) ;
p . max_uploads = maxUploadsPerTorrent ( ) ;
2015-04-19 18:17:47 +03:00
QString savePath = QString ( " %1/%2 " ) . arg ( QDir : : tempPath ( ) ) . arg ( hash ) ;
2017-03-06 18:51:35 +03:00
p . save_path = Utils : : Fs : : toNativePath ( savePath ) . toStdString ( ) ;
2015-04-19 18:17:47 +03:00
// Forced start
p . flags & = ~ libt : : add_torrent_params : : flag_paused ;
p . flags & = ~ libt : : add_torrent_params : : flag_auto_managed ;
// Solution to avoid accidental file writes
p . flags | = libt : : add_torrent_params : : flag_upload_mode ;
// Adding torrent to BitTorrent session
libt : : error_code ec ;
libt : : torrent_handle h = m_nativeSession - > add_torrent ( p , ec ) ;
if ( ec ) return false ;
// waiting for metadata...
m_loadedMetadata . insert ( h . info_hash ( ) , TorrentInfo ( ) ) ;
+ + m_extraLimit ;
adjustLimits ( ) ;
return true ;
}
void Session : : exportTorrentFile ( TorrentHandle * const torrent , TorrentExportFolder folder )
{
2016-05-01 11:05:52 +03:00
Q_ASSERT ( ( ( folder = = TorrentExportFolder : : Regular ) & & ! torrentExportDirectory ( ) . isEmpty ( ) ) | |
( ( folder = = TorrentExportFolder : : Finished ) & & ! finishedTorrentExportDirectory ( ) . isEmpty ( ) ) ) ;
2015-04-19 18:17:47 +03:00
2015-12-01 17:41:56 +03:00
QString validName = Utils : : Fs : : toValidFileSystemName ( torrent - > name ( ) ) ;
2015-04-19 18:17:47 +03:00
QString torrentFilename = QString ( " %1.torrent " ) . arg ( torrent - > hash ( ) ) ;
2015-12-01 17:41:56 +03:00
QString torrentExportFilename = QString ( " %1.torrent " ) . arg ( validName ) ;
2015-04-19 18:17:47 +03:00
QString torrentPath = QDir ( m_resumeFolderPath ) . absoluteFilePath ( torrentFilename ) ;
2016-05-01 11:05:52 +03:00
QDir exportPath ( folder = = TorrentExportFolder : : Regular ? torrentExportDirectory ( ) : finishedTorrentExportDirectory ( ) ) ;
2015-04-19 18:17:47 +03:00
if ( exportPath . exists ( ) | | exportPath . mkpath ( exportPath . absolutePath ( ) ) ) {
2015-12-01 17:41:56 +03:00
QString newTorrentPath = exportPath . absoluteFilePath ( torrentExportFilename ) ;
int counter = 0 ;
while ( QFile : : exists ( newTorrentPath ) & & ! Utils : : Fs : : sameFiles ( torrentPath , newTorrentPath ) ) {
// Append number to torrent name to make it unique
torrentExportFilename = QString ( " %1 %2.torrent " ) . arg ( validName ) . arg ( + + counter ) ;
newTorrentPath = exportPath . absoluteFilePath ( torrentExportFilename ) ;
2015-04-19 18:17:47 +03:00
}
2015-12-01 17:41:56 +03:00
if ( ! QFile : : exists ( newTorrentPath ) )
QFile : : copy ( torrentPath , newTorrentPath ) ;
2015-04-19 18:17:47 +03:00
}
}
void Session : : generateResumeData ( bool final )
{
foreach ( TorrentHandle * const torrent , m_torrents ) {
if ( ! torrent - > isValid ( ) ) continue ;
if ( torrent - > hasMissingFiles ( ) ) continue ;
if ( torrent - > isChecking ( ) | | torrent - > hasError ( ) ) continue ;
if ( ! final & & ! torrent - > needSaveResumeData ( ) ) continue ;
2017-01-18 19:23:57 +03:00
saveTorrentResumeData ( torrent , final ) ;
2017-08-13 13:56:03 +03:00
qDebug ( " Saving fastresume data for %s " , qUtf8Printable ( torrent - > name ( ) ) ) ;
2015-04-19 18:17:47 +03:00
}
}
// Called on exit
void Session : : saveResumeData ( )
{
qDebug ( " Saving fast resume data... " ) ;
// Pause session
m_nativeSession - > pause ( ) ;
generateResumeData ( true ) ;
while ( m_numResumeData > 0 ) {
2016-04-28 10:56:58 +03:00
std : : vector < libt : : alert * > alerts ;
2015-04-19 18:17:47 +03:00
getPendingAlerts ( alerts , 30 * 1000 ) ;
if ( alerts . empty ( ) ) {
std : : cerr < < " aborting with " < < m_numResumeData
< < " outstanding torrents to save resume data for "
< < std : : endl ;
break ;
}
2016-04-28 10:56:58 +03:00
for ( const auto a : alerts ) {
2015-04-19 18:17:47 +03:00
switch ( a - > type ( ) ) {
case libt : : save_resume_data_failed_alert : : alert_type :
case libt : : save_resume_data_alert : : alert_type :
2016-11-18 19:04:04 +03:00
dispatchTorrentAlert ( a ) ;
2015-04-19 18:17:47 +03:00
break ;
}
2016-04-28 10:56:58 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2015-04-19 18:17:47 +03:00
delete a ;
2016-04-28 10:56:58 +03:00
# endif
2015-04-19 18:17:47 +03:00
}
}
}
2016-02-09 11:56:48 +03:00
void Session : : setDefaultSavePath ( QString path )
2015-04-19 18:17:47 +03:00
{
2016-03-06 09:25:55 +03:00
path = normalizeSavePath ( path ) ;
2016-05-01 11:05:52 +03:00
if ( path = = m_defaultSavePath ) return ;
2015-04-19 18:17:47 +03:00
2016-02-09 11:56:48 +03:00
m_defaultSavePath = path ;
2015-04-19 18:17:47 +03:00
2016-05-08 22:47:50 +03:00
if ( isDisableAutoTMMWhenDefaultSavePathChanged ( ) )
2016-02-09 11:56:48 +03:00
foreach ( TorrentHandle * const torrent , torrents ( ) )
2016-05-08 22:47:50 +03:00
torrent - > setAutoTMMEnabled ( false ) ;
2016-02-09 11:56:48 +03:00
else
foreach ( TorrentHandle * const torrent , torrents ( ) )
torrent - > handleCategorySavePathChanged ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-02-09 11:56:48 +03:00
void Session : : setTempPath ( QString path )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
path = normalizeSavePath ( path , defaultSavePath ( ) + " temp/ " ) ;
if ( path = = m_tempPath ) return ;
2015-08-16 20:03:32 +03:00
2016-02-09 11:56:48 +03:00
m_tempPath = path ;
2015-08-16 20:03:32 +03:00
2016-02-09 11:56:48 +03:00
foreach ( TorrentHandle * const torrent , m_torrents )
torrent - > handleTempPathChanged ( ) ;
2015-04-19 18:17:47 +03:00
}
2015-06-15 01:06:56 +03:00
void Session : : networkOnlineStateChanged ( const bool online )
{
Logger : : instance ( ) - > addMessage ( tr ( " System network status changed to %1 " , " e.g: System network status changed to ONLINE " ) . arg ( online ? tr ( " ONLINE " ) : tr ( " OFFLINE " ) ) , Log : : INFO ) ;
}
void Session : : networkConfigurationChange ( const QNetworkConfiguration & cfg )
{
2016-05-01 11:05:52 +03:00
const QString configuredInterfaceName = networkInterface ( ) ;
2015-12-05 22:22:01 +03:00
// Empty means "Any Interface". In this case libtorrent has binded to 0.0.0.0 so any change to any interface will
// be automatically picked up. Otherwise we would rebinding here to 0.0.0.0 again.
2016-05-01 11:05:52 +03:00
if ( configuredInterfaceName . isEmpty ( ) ) return ;
2015-06-15 01:06:56 +03:00
const QString changedInterface = cfg . name ( ) ;
2016-05-24 01:27:53 +03:00
// workaround for QTBUG-52633: check interface IPs, react only if the IPs have changed
// seems to be present only with NetworkManager, hence Q_OS_LINUX
2017-01-11 02:13:31 +03:00
# if defined Q_OS_LINUX && QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(5, 7, 1)
2016-05-24 01:27:53 +03:00
static QStringList boundIPs = getListeningIPs ( ) ;
const QStringList newBoundIPs = getListeningIPs ( ) ;
if ( ( configuredInterfaceName = = changedInterface ) & & ( boundIPs ! = newBoundIPs ) ) {
boundIPs = newBoundIPs ;
# else
2015-11-29 15:30:42 +03:00
if ( configuredInterfaceName = = changedInterface ) {
2016-05-24 01:27:53 +03:00
# endif
2015-06-15 01:06:56 +03:00
Logger : : instance ( ) - > addMessage ( 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 ) ;
2016-05-01 11:05:52 +03:00
configureListeningInterface ( ) ;
2015-06-15 01:06:56 +03:00
}
}
2015-11-07 03:06:07 +03:00
const QStringList Session : : getListeningIPs ( )
2015-04-19 18:17:47 +03:00
{
Logger * const logger = Logger : : instance ( ) ;
2015-11-07 03:06:07 +03:00
QStringList IPs ;
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
const QString ifaceName = networkInterface ( ) ;
const QString ifaceAddr = networkInterfaceAddress ( ) ;
const bool listenIPv6 = isIPv6Enabled ( ) ;
2015-04-19 18:17:47 +03:00
2016-05-27 01:35:58 +03:00
if ( ! ifaceAddr . isEmpty ( ) ) {
QHostAddress addr ( ifaceAddr ) ;
if ( addr . isNull ( ) ) {
logger - > addMessage ( tr ( " Configured network interface address %1 isn't valid. " , " Configured network interface address 124.5.1568.1 isn't valid. " ) . arg ( ifaceAddr ) , Log : : CRITICAL ) ;
IPs . append ( " 127.0.0.1 " ) ; // Force listening to localhost and avoid accidental connection that will expose user data.
return IPs ;
}
}
if ( ifaceName . isEmpty ( ) ) {
if ( ! ifaceAddr . isEmpty ( ) )
IPs . append ( ifaceAddr ) ;
else
IPs . append ( QString ( ) ) ;
2015-11-07 03:06:07 +03:00
return IPs ;
2015-04-19 18:17:47 +03:00
}
// Attempt to listen on provided interface
2015-11-07 03:06:07 +03:00
const QNetworkInterface networkIFace = QNetworkInterface : : interfaceFromName ( ifaceName ) ;
if ( ! networkIFace . isValid ( ) ) {
2017-08-13 13:56:03 +03:00
qDebug ( " Invalid network interface: %s " , qUtf8Printable ( ifaceName ) ) ;
2015-11-07 03:06:07 +03:00
logger - > addMessage ( tr ( " The network interface defined is invalid: %1 " ) . arg ( ifaceName ) , Log : : CRITICAL ) ;
IPs . append ( " 127.0.0.1 " ) ; // Force listening to localhost and avoid accidental connection that will expose user data.
return IPs ;
2015-04-19 18:17:47 +03:00
}
2015-11-07 03:06:07 +03:00
const QList < QNetworkAddressEntry > addresses = networkIFace . addressEntries ( ) ;
2015-06-15 01:33:48 +03:00
qDebug ( " This network interface has %d IP addresses " , addresses . size ( ) ) ;
QHostAddress ip ;
QString ipString ;
QAbstractSocket : : NetworkLayerProtocol protocol ;
foreach ( const QNetworkAddressEntry & entry , addresses ) {
ip = entry . ip ( ) ;
ipString = ip . toString ( ) ;
protocol = ip . protocol ( ) ;
Q_ASSERT ( protocol = = QAbstractSocket : : IPv4Protocol | | protocol = = QAbstractSocket : : IPv6Protocol ) ;
2015-11-07 03:06:07 +03:00
if ( ( ! listenIPv6 & & ( protocol = = QAbstractSocket : : IPv6Protocol ) )
| | ( listenIPv6 & & ( protocol = = QAbstractSocket : : IPv4Protocol ) ) )
2015-04-19 18:17:47 +03:00
continue ;
2016-04-13 11:51:29 +03:00
2016-05-01 11:05:52 +03:00
//If an iface address has been defined only allow ip's that match it to go through
2016-04-13 11:51:29 +03:00
if ( ! ifaceAddr . isEmpty ( ) ) {
2016-05-27 01:35:58 +03:00
if ( ifaceAddr = = ipString ) {
IPs . append ( ipString ) ;
break ;
2016-04-13 11:51:29 +03:00
}
}
2016-05-27 01:35:58 +03:00
else {
IPs . append ( ipString ) ;
}
2015-11-07 03:06:07 +03:00
}
// Make sure there is at least one IP
// At this point there was a valid network interface, with no suitable IP.
if ( IPs . size ( ) = = 0 ) {
logger - > addMessage ( tr ( " qBittorrent didn't find an %1 local address to listen on " , " qBittorrent didn't find an IPv4 local address to listen on " ) . arg ( listenIPv6 ? " IPv6 " : " IPv4 " ) , Log : : CRITICAL ) ;
IPs . append ( " 127.0.0.1 " ) ; // Force listening to localhost and avoid accidental connection that will expose user data.
return IPs ;
}
return IPs ;
}
// Set the ports range in which is chosen the port
// the BitTorrent session will listen to
2016-05-01 11:05:52 +03:00
void Session : : configureListeningInterface ( )
2015-11-07 03:06:07 +03:00
{
2016-06-03 17:03:17 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2016-05-01 11:05:52 +03:00
const ushort port = this - > port ( ) ;
2015-11-07 03:06:07 +03:00
qDebug ( ) < < Q_FUNC_INFO < < port ;
2016-05-01 11:05:52 +03:00
2015-11-07 03:06:07 +03:00
Logger * const logger = Logger : : instance ( ) ;
2016-05-01 11:05:52 +03:00
std : : pair < int , int > ports ( port , port ) ;
2015-11-07 03:06:07 +03:00
libt : : error_code ec ;
const QStringList IPs = getListeningIPs ( ) ;
foreach ( const QString ip , IPs ) {
if ( ip . isEmpty ( ) ) {
logger - > addMessage ( tr ( " qBittorrent is trying to listen on any interface port: %1 " , " e.g: qBittorrent is trying to listen on any interface port: TCP/6881 " ) . arg ( QString : : number ( port ) ) , Log : : INFO ) ;
m_nativeSession - > listen_on ( ports , ec , 0 , libt : : session : : listen_no_system_port ) ;
if ( ec )
2015-11-30 19:53:19 +03:00
logger - > addMessage ( tr ( " qBittorrent failed to listen on any interface port: %1. Reason: %2. " , " e.g: qBittorrent failed to listen on any interface port: TCP/6881. Reason: no such interface " ) . arg ( QString : : number ( port ) ) . arg ( QString : : fromLocal8Bit ( ec . message ( ) . c_str ( ) ) ) , Log : : CRITICAL ) ;
2015-11-07 03:06:07 +03:00
return ;
}
m_nativeSession - > listen_on ( ports , ec , ip . toLatin1 ( ) . constData ( ) , libt : : session : : listen_no_system_port ) ;
2015-04-19 18:17:47 +03:00
if ( ! ec ) {
2015-11-07 03:06:07 +03:00
logger - > addMessage ( tr ( " qBittorrent is trying to listen on interface %1 port: %2 " , " e.g: qBittorrent is trying to listen on interface 192.168.0.1 port: TCP/6881 " ) . arg ( ip ) . arg ( port ) , Log : : INFO ) ;
2015-04-19 18:17:47 +03:00
return ;
}
}
2016-06-03 17:03:17 +03:00
# else
m_listenInterfaceChanged = true ;
configureDeferred ( ) ;
# endif
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
int Session : : globalDownloadSpeedLimit ( ) const
2015-04-19 18:17:47 +03:00
{
2016-11-01 17:52:32 +03:00
// Unfortunately the value was saved as KiB instead of B.
// But it is better to pass it around internally(+ webui) as Bytes.
return m_globalDownloadSpeedLimit * 1024 ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setGlobalDownloadSpeedLimit ( int limit )
2015-04-19 18:17:47 +03:00
{
2016-11-01 17:52:32 +03:00
// Unfortunately the value was saved as KiB instead of B.
// But it is better to pass it around internally(+ webui) as Bytes.
limit / = 1024 ;
2016-05-01 11:05:52 +03:00
if ( limit < 0 ) limit = 0 ;
if ( limit = = globalDownloadSpeedLimit ( ) ) return ;
m_globalDownloadSpeedLimit = limit ;
if ( ! isAltGlobalSpeedLimitEnabled ( ) )
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
int Session : : globalUploadSpeedLimit ( ) const
2015-04-19 18:17:47 +03:00
{
2016-11-01 17:52:32 +03:00
// Unfortunately the value was saved as KiB instead of B.
// But it is better to pass it around internally(+ webui) as Bytes.
return m_globalUploadSpeedLimit * 1024 ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setGlobalUploadSpeedLimit ( int limit )
2015-04-19 18:17:47 +03:00
{
2016-11-01 17:52:32 +03:00
// Unfortunately the value was saved as KiB instead of B.
// But it is better to pass it around internally(+ webui) as Bytes.
limit / = 1024 ;
2016-05-01 11:05:52 +03:00
if ( limit < 0 ) limit = 0 ;
if ( limit = = globalUploadSpeedLimit ( ) ) return ;
m_globalUploadSpeedLimit = limit ;
if ( ! isAltGlobalSpeedLimitEnabled ( ) )
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
int Session : : altGlobalDownloadSpeedLimit ( ) const
2015-04-19 18:17:47 +03:00
{
2016-11-01 17:52:32 +03:00
// Unfortunately the value was saved as KiB instead of B.
// But it is better to pass it around internally(+ webui) as Bytes.
return m_altGlobalDownloadSpeedLimit * 1024 ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setAltGlobalDownloadSpeedLimit ( int limit )
2016-02-09 11:56:48 +03:00
{
2016-11-01 17:52:32 +03:00
// Unfortunately the value was saved as KiB instead of B.
// But it is better to pass it around internally(+ webui) as Bytes.
limit / = 1024 ;
2016-05-01 11:05:52 +03:00
if ( limit < 0 ) limit = 0 ;
if ( limit = = altGlobalDownloadSpeedLimit ( ) ) return ;
m_altGlobalDownloadSpeedLimit = limit ;
if ( isAltGlobalSpeedLimitEnabled ( ) )
configureDeferred ( ) ;
2016-02-09 11:56:48 +03:00
}
2016-05-01 11:05:52 +03:00
int Session : : altGlobalUploadSpeedLimit ( ) const
2016-02-09 11:56:48 +03:00
{
2016-11-01 17:52:32 +03:00
// Unfortunately the value was saved as KiB instead of B.
// But it is better to pass it around internally(+ webui) as Bytes.
return m_altGlobalUploadSpeedLimit * 1024 ;
2016-02-09 11:56:48 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setAltGlobalUploadSpeedLimit ( int limit )
2015-04-19 18:17:47 +03:00
{
2016-11-01 17:52:32 +03:00
// Unfortunately the value was saved as KiB instead of B.
// But it is better to pass it around internally(+ webui) as Bytes.
limit / = 1024 ;
2016-05-01 11:05:52 +03:00
if ( limit < 0 ) limit = 0 ;
if ( limit = = altGlobalUploadSpeedLimit ( ) ) return ;
m_altGlobalUploadSpeedLimit = limit ;
if ( isAltGlobalSpeedLimitEnabled ( ) )
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
int Session : : downloadSpeedLimit ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return isAltGlobalSpeedLimitEnabled ( )
? altGlobalDownloadSpeedLimit ( )
: globalDownloadSpeedLimit ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setDownloadSpeedLimit ( int limit )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( isAltGlobalSpeedLimitEnabled ( ) )
setAltGlobalDownloadSpeedLimit ( limit ) ;
else
setGlobalDownloadSpeedLimit ( limit ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
int Session : : uploadSpeedLimit ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return isAltGlobalSpeedLimitEnabled ( )
? altGlobalUploadSpeedLimit ( )
: globalUploadSpeedLimit ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setUploadSpeedLimit ( int limit )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( isAltGlobalSpeedLimitEnabled ( ) )
setAltGlobalUploadSpeedLimit ( limit ) ;
else
setGlobalUploadSpeedLimit ( limit ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
bool Session : : isAltGlobalSpeedLimitEnabled ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isAltGlobalSpeedLimitEnabled ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setAltGlobalSpeedLimitEnabled ( bool enabled )
2015-06-07 15:03:30 +03:00
{
2017-08-20 18:00:23 +03:00
if ( enabled = = isAltGlobalSpeedLimitEnabled ( ) ) return ;
2016-05-01 11:05:52 +03:00
2017-08-20 18:00:23 +03:00
// Save new state to remember it on startup
m_isAltGlobalSpeedLimitEnabled = enabled ;
applyBandwidthLimits ( ) ;
// Notify
emit speedLimitModeChanged ( m_isAltGlobalSpeedLimitEnabled ) ;
2016-02-09 11:56:48 +03:00
}
2015-08-16 20:03:32 +03:00
2016-05-01 11:05:52 +03:00
bool Session : : isBandwidthSchedulerEnabled ( ) const
2016-02-09 11:56:48 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isBandwidthSchedulerEnabled ;
2015-06-07 15:03:30 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setBandwidthSchedulerEnabled ( bool enabled )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( enabled ! = isBandwidthSchedulerEnabled ( ) ) {
m_isBandwidthSchedulerEnabled = enabled ;
if ( enabled )
enableBandwidthScheduler ( ) ;
else
delete m_bwScheduler ;
}
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
uint Session : : saveResumeDataInterval ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_saveResumeDataInterval ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setSaveResumeDataInterval ( uint value )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( value ! = saveResumeDataInterval ( ) ) {
m_saveResumeDataInterval = value ;
m_resumeDataTimer - > setInterval ( value * 60 * 1000 ) ;
}
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
int Session : : port ( ) const
2015-04-19 18:17:47 +03:00
{
2017-02-10 15:33:21 +03:00
static int randomPort = Utils : : Random : : rand ( 1024 , 65535 ) ;
2016-05-01 11:05:52 +03:00
if ( useRandomPort ( ) )
return randomPort ;
return m_port ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setPort ( int port )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( port ! = this - > port ( ) ) {
m_port = port ;
configureListeningInterface ( ) ;
}
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
bool Session : : useRandomPort ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_useRandomPort ;
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setUseRandomPort ( bool value )
{
m_useRandomPort = value ;
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
QString Session : : networkInterface ( ) const
{
return m_networkInterface ;
2015-04-19 18:17:47 +03:00
}
2017-08-13 00:58:22 +03:00
void Session : : setNetworkInterface ( const QString & iface )
2015-04-19 18:17:47 +03:00
{
2017-08-13 00:58:22 +03:00
if ( iface ! = networkInterface ( ) ) {
m_networkInterface = iface ;
2016-05-01 11:05:52 +03:00
configureListeningInterface ( ) ;
}
2015-04-19 18:17:47 +03:00
}
2016-10-31 02:40:26 +03:00
QString Session : : networkInterfaceName ( ) const
{
return m_networkInterfaceName ;
}
void Session : : setNetworkInterfaceName ( const QString & name )
{
m_networkInterfaceName = name ;
}
2016-05-01 11:05:52 +03:00
QString Session : : networkInterfaceAddress ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_networkInterfaceAddress ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setNetworkInterfaceAddress ( const QString & address )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( address ! = networkInterfaceAddress ( ) ) {
m_networkInterfaceAddress = address ;
configureListeningInterface ( ) ;
}
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
bool Session : : isIPv6Enabled ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isIPv6Enabled ;
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setIPv6Enabled ( bool enabled )
{
if ( enabled ! = isIPv6Enabled ( ) ) {
m_isIPv6Enabled = enabled ;
configureListeningInterface ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
int Session : : encryption ( ) const
{
return m_encryption ;
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setEncryption ( int state )
{
if ( state ! = encryption ( ) ) {
m_encryption = state ;
2016-06-03 17:03:17 +03:00
configureDeferred ( ) ;
Logger : : instance ( ) - > addMessage (
tr ( " Encryption support [%1] " )
. arg ( state = = 0 ? tr ( " ON " ) : state = = 1 ? tr ( " FORCED " ) : tr ( " OFF " ) )
, Log : : INFO ) ;
2016-05-01 11:05:52 +03:00
}
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
bool Session : : isForceProxyEnabled ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isForceProxyEnabled ;
}
void Session : : setForceProxyEnabled ( bool enabled )
{
if ( enabled ! = isForceProxyEnabled ( ) ) {
m_isForceProxyEnabled = enabled ;
configureDeferred ( ) ;
}
}
bool Session : : isProxyPeerConnectionsEnabled ( ) const
{
return m_isProxyPeerConnectionsEnabled ;
}
void Session : : setProxyPeerConnectionsEnabled ( bool enabled )
{
if ( enabled ! = isProxyPeerConnectionsEnabled ( ) ) {
m_isProxyPeerConnectionsEnabled = enabled ;
configureDeferred ( ) ;
}
}
2017-08-15 21:23:07 +03:00
ChokingAlgorithm Session : : chokingAlgorithm ( ) const
2017-08-11 12:06:31 +03:00
{
return m_chokingAlgorithm ;
}
2017-08-15 21:23:07 +03:00
void Session : : setChokingAlgorithm ( ChokingAlgorithm mode )
2017-08-11 12:06:31 +03:00
{
if ( mode = = m_chokingAlgorithm ) return ;
m_chokingAlgorithm = mode ;
configureDeferred ( ) ;
}
2017-08-15 21:23:07 +03:00
SeedChokingAlgorithm Session : : seedChokingAlgorithm ( ) const
2017-08-11 12:06:31 +03:00
{
return m_seedChokingAlgorithm ;
}
2017-08-15 21:23:07 +03:00
void Session : : setSeedChokingAlgorithm ( SeedChokingAlgorithm mode )
2017-08-11 12:06:31 +03:00
{
if ( mode = = m_seedChokingAlgorithm ) return ;
m_seedChokingAlgorithm = mode ;
configureDeferred ( ) ;
}
2016-05-01 11:05:52 +03:00
bool Session : : isAddTrackersEnabled ( ) const
{
return m_isAddTrackersEnabled ;
}
void Session : : setAddTrackersEnabled ( bool enabled )
{
m_isAddTrackersEnabled = enabled ;
}
QString Session : : additionalTrackers ( ) const
{
return m_additionalTrackers ;
}
void Session : : setAdditionalTrackers ( const QString & trackers )
{
if ( trackers ! = additionalTrackers ( ) ) {
m_additionalTrackers = trackers ;
populateAdditionalTrackers ( ) ;
}
}
2016-10-29 19:14:27 +03:00
bool Session : : isIPFilteringEnabled ( ) const
2016-05-01 11:05:52 +03:00
{
2016-10-29 19:14:27 +03:00
return m_isIPFilteringEnabled ;
2016-05-01 11:05:52 +03:00
}
2016-10-29 19:14:27 +03:00
void Session : : setIPFilteringEnabled ( bool enabled )
2016-05-01 11:05:52 +03:00
{
2016-10-29 19:14:27 +03:00
if ( enabled ! = m_isIPFilteringEnabled ) {
m_isIPFilteringEnabled = enabled ;
2016-06-03 17:03:17 +03:00
m_IPFilteringChanged = true ;
2016-05-01 11:05:52 +03:00
configureDeferred ( ) ;
}
}
QString Session : : IPFilterFile ( ) const
{
return Utils : : Fs : : fromNativePath ( m_IPFilterFile ) ;
}
void Session : : setIPFilterFile ( QString path )
{
path = Utils : : Fs : : fromNativePath ( path ) ;
if ( path ! = IPFilterFile ( ) ) {
m_IPFilterFile = path ;
2016-06-03 17:03:17 +03:00
m_IPFilteringChanged = true ;
2016-05-01 11:05:52 +03:00
configureDeferred ( ) ;
}
}
2017-03-06 15:40:34 +03:00
void Session : : setBannedIPs ( const QStringList & newList )
{
if ( newList = = m_bannedIPs )
return ; // do nothing
// here filter out incorrect IP
QStringList filteredList ;
for ( const QString & ip : newList ) {
if ( Utils : : Net : : isValidIP ( ip ) ) {
// the same IPv6 addresses could be written in different forms;
// QHostAddress::toString() result format follows RFC5952;
// thus we avoid duplicate entries pointing to the same address
filteredList < < QHostAddress ( ip ) . toString ( ) ;
}
else {
Logger : : instance ( ) - > addMessage (
tr ( " %1 is not a valid IP address and was rejected while applying the list of banned addresses. " )
. arg ( ip )
, Log : : WARNING ) ;
}
}
// now we have to sort IPs and make them unique
filteredList . sort ( ) ;
filteredList . removeDuplicates ( ) ;
// Again ensure that the new list is different from the stored one.
if ( filteredList = = m_bannedIPs )
return ; // do nothing
// store to session settings
// also here we have to recreate filter list including 3rd party ban file
// and install it again into m_session
m_bannedIPs = filteredList ;
m_IPFilteringChanged = true ;
configureDeferred ( ) ;
}
QStringList Session : : bannedIPs ( ) const
{
return m_bannedIPs ;
}
2016-05-01 11:05:52 +03:00
int Session : : maxConnectionsPerTorrent ( ) const
{
return m_maxConnectionsPerTorrent ;
}
void Session : : setMaxConnectionsPerTorrent ( int max )
{
max = ( max > 0 ) ? max : - 1 ;
if ( max ! = maxConnectionsPerTorrent ( ) ) {
m_maxConnectionsPerTorrent = max ;
// Apply this to all session torrents
for ( const auto & handle : m_nativeSession - > get_torrents ( ) ) {
if ( ! handle . is_valid ( ) ) continue ;
try {
handle . set_max_connections ( max ) ;
}
2017-08-12 16:21:01 +03:00
catch ( std : : exception ) { }
2016-05-01 11:05:52 +03:00
}
}
}
int Session : : maxUploadsPerTorrent ( ) const
{
return m_maxUploadsPerTorrent ;
}
void Session : : setMaxUploadsPerTorrent ( int max )
{
max = ( max > 0 ) ? max : - 1 ;
if ( max ! = maxUploadsPerTorrent ( ) ) {
m_maxUploadsPerTorrent = max ;
// Apply this to all session torrents
for ( const auto & handle : m_nativeSession - > get_torrents ( ) ) {
if ( ! handle . is_valid ( ) ) continue ;
try {
handle . set_max_uploads ( max ) ;
}
2017-08-12 16:21:01 +03:00
catch ( std : : exception ) { }
2016-05-01 11:05:52 +03:00
}
}
}
bool Session : : announceToAllTrackers ( ) const
{
return m_announceToAllTrackers ;
}
void Session : : setAnnounceToAllTrackers ( bool val )
{
if ( val ! = m_announceToAllTrackers ) {
m_announceToAllTrackers = val ;
configureDeferred ( ) ;
}
}
2017-10-30 21:04:14 +03:00
bool Session : : announceToAllTiers ( ) const
{
return m_announceToAllTiers ;
}
void Session : : setAnnounceToAllTiers ( bool val )
{
if ( val ! = m_announceToAllTiers ) {
m_announceToAllTiers = val ;
configureDeferred ( ) ;
}
}
2017-08-18 03:05:36 +03:00
int Session : : diskCacheSize ( ) const
2016-05-01 11:05:52 +03:00
{
2017-08-18 03:05:36 +03:00
int size = m_diskCacheSize ;
2016-05-01 11:05:52 +03:00
// These macros may not be available on compilers other than MSVC and GCC
# if defined(__x86_64__) || defined(_M_X64)
2017-08-18 03:05:36 +03:00
size = qMin ( size , 4096 ) ; // 4GiB
2016-05-01 11:05:52 +03:00
# else
// When build as 32bit binary, set the maximum at less than 2GB to prevent crashes
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
2017-08-18 03:05:36 +03:00
size = qMin ( size , 1536 ) ;
2016-05-01 11:05:52 +03:00
# endif
return size ;
}
2017-08-18 03:05:36 +03:00
void Session : : setDiskCacheSize ( int size )
2016-05-01 11:05:52 +03:00
{
# if defined(__x86_64__) || defined(_M_X64)
2017-08-18 03:05:36 +03:00
size = qMin ( size , 4096 ) ; // 4GiB
2016-05-01 11:05:52 +03:00
# else
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
2017-08-18 03:05:36 +03:00
size = qMin ( size , 1536 ) ;
2016-05-01 11:05:52 +03:00
# endif
if ( size ! = m_diskCacheSize ) {
m_diskCacheSize = size ;
configureDeferred ( ) ;
}
}
2017-08-18 20:20:53 +03:00
int Session : : diskCacheTTL ( ) const
2016-05-01 11:05:52 +03:00
{
return m_diskCacheTTL ;
}
2017-08-18 20:20:53 +03:00
void Session : : setDiskCacheTTL ( int ttl )
2016-05-01 11:05:52 +03:00
{
if ( ttl ! = m_diskCacheTTL ) {
m_diskCacheTTL = ttl ;
configureDeferred ( ) ;
}
}
bool Session : : useOSCache ( ) const
{
return m_useOSCache ;
}
void Session : : setUseOSCache ( bool use )
{
if ( use ! = m_useOSCache ) {
m_useOSCache = use ;
configureDeferred ( ) ;
}
}
2017-08-11 10:50:56 +03:00
bool Session : : isGuidedReadCacheEnabled ( ) const
{
return m_guidedReadCacheEnabled ;
}
void Session : : setGuidedReadCacheEnabled ( bool enabled )
{
if ( enabled = = m_guidedReadCacheEnabled ) return ;
m_guidedReadCacheEnabled = enabled ;
configureDeferred ( ) ;
}
2017-08-11 14:15:18 +03:00
bool Session : : isSuggestModeEnabled ( ) const
{
return m_isSuggestMode ;
}
void Session : : setSuggestMode ( bool mode )
{
if ( mode = = m_isSuggestMode ) return ;
m_isSuggestMode = mode ;
configureDeferred ( ) ;
}
2017-08-11 14:48:58 +03:00
int Session : : sendBufferWatermark ( ) const
{
return m_sendBufferWatermark ;
}
void Session : : setSendBufferWatermark ( int value )
{
if ( value = = m_sendBufferWatermark ) return ;
m_sendBufferWatermark = value ;
configureDeferred ( ) ;
}
int Session : : sendBufferLowWatermark ( ) const
{
return m_sendBufferLowWatermark ;
}
void Session : : setSendBufferLowWatermark ( int value )
{
if ( value = = m_sendBufferLowWatermark ) return ;
m_sendBufferLowWatermark = value ;
configureDeferred ( ) ;
}
int Session : : sendBufferWatermarkFactor ( ) const
{
return m_sendBufferWatermarkFactor ;
}
void Session : : setSendBufferWatermarkFactor ( int value )
{
if ( value = = m_sendBufferWatermarkFactor ) return ;
m_sendBufferWatermarkFactor = value ;
configureDeferred ( ) ;
}
2016-05-01 11:05:52 +03:00
bool Session : : isAnonymousModeEnabled ( ) const
{
return m_isAnonymousModeEnabled ;
}
void Session : : setAnonymousModeEnabled ( bool enabled )
{
if ( enabled ! = m_isAnonymousModeEnabled ) {
m_isAnonymousModeEnabled = enabled ;
configureDeferred ( ) ;
2016-06-03 17:03:17 +03:00
Logger : : instance ( ) - > addMessage (
tr ( " Anonymous mode [%1] " ) . arg ( isAnonymousModeEnabled ( ) ? tr ( " ON " ) : tr ( " OFF " ) )
, Log : : INFO ) ;
2016-05-01 11:05:52 +03:00
}
}
bool Session : : isQueueingSystemEnabled ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isQueueingEnabled ;
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setQueueingSystemEnabled ( bool enabled )
{
if ( enabled ! = m_isQueueingEnabled ) {
m_isQueueingEnabled = enabled ;
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
}
2016-05-01 11:05:52 +03:00
int Session : : maxActiveDownloads ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_maxActiveDownloads ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setMaxActiveDownloads ( int max )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
max = std : : max ( max , - 1 ) ;
if ( max ! = m_maxActiveDownloads ) {
m_maxActiveDownloads = max ;
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
}
2016-05-01 11:05:52 +03:00
int Session : : maxActiveUploads ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_maxActiveUploads ;
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setMaxActiveUploads ( int max )
{
max = std : : max ( max , - 1 ) ;
if ( max ! = m_maxActiveUploads ) {
m_maxActiveUploads = max ;
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
}
2016-05-01 11:05:52 +03:00
int Session : : maxActiveTorrents ( ) const
2015-07-22 08:51:23 +03:00
{
2016-05-01 11:05:52 +03:00
return m_maxActiveTorrents ;
2015-07-22 08:51:23 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setMaxActiveTorrents ( int max )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
max = std : : max ( max , - 1 ) ;
if ( max ! = m_maxActiveTorrents ) {
m_maxActiveTorrents = max ;
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
}
2016-05-01 11:05:52 +03:00
bool Session : : ignoreSlowTorrentsForQueueing ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_ignoreSlowTorrentsForQueueing ;
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setIgnoreSlowTorrentsForQueueing ( bool ignore )
{
if ( ignore ! = m_ignoreSlowTorrentsForQueueing ) {
m_ignoreSlowTorrentsForQueueing = ignore ;
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
}
2017-08-18 20:20:53 +03:00
int Session : : outgoingPortsMin ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_outgoingPortsMin ;
2015-04-19 18:17:47 +03:00
}
2017-08-18 20:20:53 +03:00
void Session : : setOutgoingPortsMin ( int min )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( min ! = m_outgoingPortsMin ) {
m_outgoingPortsMin = min ;
configureDeferred ( ) ;
}
}
2015-08-16 20:03:32 +03:00
2017-08-18 20:20:53 +03:00
int Session : : outgoingPortsMax ( ) const
2016-05-01 11:05:52 +03:00
{
return m_outgoingPortsMax ;
2015-04-19 18:17:47 +03:00
}
2017-08-18 20:20:53 +03:00
void Session : : setOutgoingPortsMax ( int max )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( max ! = m_outgoingPortsMax ) {
m_outgoingPortsMax = max ;
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
}
2016-05-01 11:05:52 +03:00
bool Session : : ignoreLimitsOnLAN ( ) const
2015-06-15 01:06:56 +03:00
{
2016-05-01 11:05:52 +03:00
return m_ignoreLimitsOnLAN ;
2015-06-15 01:06:56 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setIgnoreLimitsOnLAN ( bool ignore )
2015-06-15 01:06:56 +03:00
{
2016-05-01 11:05:52 +03:00
if ( ignore ! = m_ignoreLimitsOnLAN ) {
m_ignoreLimitsOnLAN = ignore ;
configureDeferred ( ) ;
2015-06-15 01:06:56 +03:00
}
}
2016-05-01 11:05:52 +03:00
bool Session : : includeOverheadInLimits ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_includeOverheadInLimits ;
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setIncludeOverheadInLimits ( bool include )
{
if ( include ! = m_includeOverheadInLimits ) {
m_includeOverheadInLimits = include ;
configureDeferred ( ) ;
2016-05-27 01:35:58 +03:00
}
2016-05-01 11:05:52 +03:00
}
2016-05-27 01:35:58 +03:00
2016-10-31 02:22:11 +03:00
QString Session : : announceIP ( ) const
2016-05-01 11:05:52 +03:00
{
2016-10-31 02:22:11 +03:00
return m_announceIP ;
2016-05-01 11:05:52 +03:00
}
2015-04-19 18:17:47 +03:00
2016-10-31 02:22:11 +03:00
void Session : : setAnnounceIP ( const QString & ip )
2016-05-01 11:05:52 +03:00
{
2016-10-31 02:22:11 +03:00
if ( ip ! = m_announceIP ) {
m_announceIP = ip ;
2016-05-01 11:05:52 +03:00
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
}
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
bool Session : : isSuperSeedingEnabled ( ) const
{
return m_isSuperSeedingEnabled ;
}
2016-04-13 11:51:29 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setSuperSeedingEnabled ( bool enabled )
{
if ( enabled ! = m_isSuperSeedingEnabled ) {
m_isSuperSeedingEnabled = enabled ;
configureDeferred ( ) ;
2015-11-07 03:06:07 +03:00
}
2016-05-01 11:05:52 +03:00
}
2015-11-07 03:06:07 +03:00
2016-05-01 11:05:52 +03:00
int Session : : maxConnections ( ) const
{
return m_maxConnections ;
}
2015-11-07 03:06:07 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setMaxConnections ( int max )
{
max = ( max > 0 ) ? max : - 1 ;
if ( max ! = m_maxConnections ) {
m_maxConnections = max ;
configureDeferred ( ) ;
}
2015-11-07 03:06:07 +03:00
}
2016-05-01 11:05:52 +03:00
int Session : : maxHalfOpenConnections ( ) const
2015-11-07 03:06:07 +03:00
{
2016-05-01 11:05:52 +03:00
return m_maxHalfOpenConnections ;
}
2015-11-07 03:06:07 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setMaxHalfOpenConnections ( int max )
{
max = ( max > 0 ) ? max : - 1 ;
if ( max ! = m_maxHalfOpenConnections ) {
m_maxHalfOpenConnections = max ;
configureDeferred ( ) ;
}
}
2015-11-07 03:06:07 +03:00
2016-05-01 11:05:52 +03:00
int Session : : maxUploads ( ) const
{
return m_maxUploads ;
}
2015-11-07 03:06:07 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setMaxUploads ( int max )
{
max = ( max > 0 ) ? max : - 1 ;
if ( max ! = m_maxUploads ) {
m_maxUploads = max ;
configureDeferred ( ) ;
}
}
2015-11-07 03:06:07 +03:00
2017-09-13 23:29:54 +03:00
BTProtocol Session : : btProtocol ( ) const
2016-05-01 11:05:52 +03:00
{
2017-09-13 23:29:54 +03:00
return m_btProtocol ;
2016-05-01 11:05:52 +03:00
}
2015-11-07 03:06:07 +03:00
2017-09-13 23:29:54 +03:00
void Session : : setBTProtocol ( BTProtocol protocol )
2016-05-01 11:05:52 +03:00
{
2017-09-13 23:29:54 +03:00
if ( ( protocol < BTProtocol : : Both ) | | ( BTProtocol : : UTP < protocol ) )
return ;
if ( protocol = = m_btProtocol ) return ;
m_btProtocol = protocol ;
configureDeferred ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
bool Session : : isUTPRateLimited ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isUTPRateLimited ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setUTPRateLimited ( bool limited )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( limited ! = m_isUTPRateLimited ) {
m_isUTPRateLimited = limited ;
configureDeferred ( ) ;
}
2015-04-19 18:17:47 +03:00
}
2017-08-15 21:23:07 +03:00
MixedModeAlgorithm Session : : utpMixedMode ( ) const
2017-08-11 11:28:52 +03:00
{
return m_utpMixedMode ;
}
2017-08-15 21:23:07 +03:00
void Session : : setUtpMixedMode ( MixedModeAlgorithm mode )
2017-08-11 11:28:52 +03:00
{
if ( mode = = m_utpMixedMode ) return ;
m_utpMixedMode = mode ;
configureDeferred ( ) ;
}
2017-08-11 11:37:32 +03:00
bool Session : : multiConnectionsPerIpEnabled ( ) const
{
return m_multiConnectionsPerIpEnabled ;
}
void Session : : setMultiConnectionsPerIpEnabled ( bool enabled )
{
if ( enabled = = m_multiConnectionsPerIpEnabled ) return ;
m_multiConnectionsPerIpEnabled = enabled ;
configureDeferred ( ) ;
}
2016-05-01 11:05:52 +03:00
bool Session : : isTrackerFilteringEnabled ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isTrackerFilteringEnabled ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setTrackerFilteringEnabled ( bool enabled )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( enabled ! = m_isTrackerFilteringEnabled ) {
m_isTrackerFilteringEnabled = enabled ;
configureDeferred ( ) ;
}
2015-04-19 18:17:47 +03:00
}
bool Session : : isListening ( ) const
{
return m_nativeSession - > is_listening ( ) ;
}
2016-02-09 11:56:48 +03:00
MaxRatioAction Session : : maxRatioAction ( ) const
{
2016-05-01 11:05:52 +03:00
return static_cast < MaxRatioAction > ( m_maxRatioAction . value ( ) ) ;
2016-02-09 11:56:48 +03:00
}
void Session : : setMaxRatioAction ( MaxRatioAction act )
{
2016-05-01 11:05:52 +03:00
m_maxRatioAction = static_cast < int > ( act ) ;
2015-04-19 18:17:47 +03:00
}
// If this functions returns true, we cannot add torrent to session,
// but it is still possible to merge trackers in some case
bool Session : : isKnownTorrent ( const InfoHash & hash ) const
{
return ( m_torrents . contains ( hash )
| | m_addingTorrents . contains ( hash )
| | m_loadedMetadata . contains ( hash ) ) ;
}
2016-02-07 20:31:50 +03:00
void Session : : updateSeedingLimitTimer ( )
2015-04-19 18:17:47 +03:00
{
2017-09-06 22:47:05 +03:00
if ( ( globalMaxRatio ( ) = = TorrentHandle : : NO_RATIO_LIMIT ) & & ! hasPerTorrentRatioLimit ( )
2016-02-07 20:31:50 +03:00
& & ( globalMaxSeedingMinutes ( ) = = TorrentHandle : : NO_SEEDING_TIME_LIMIT ) & & ! hasPerTorrentSeedingTimeLimit ( ) ) {
if ( m_seedingLimitTimer - > isActive ( ) )
m_seedingLimitTimer - > stop ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-02-07 20:31:50 +03:00
else if ( ! m_seedingLimitTimer - > isActive ( ) ) {
m_seedingLimitTimer - > start ( ) ;
2015-04-19 18:17:47 +03:00
}
}
2016-02-07 20:31:50 +03:00
void Session : : handleTorrentShareLimitChanged ( TorrentHandle * const torrent )
2015-04-19 18:17:47 +03:00
{
Q_UNUSED ( torrent ) ;
2016-02-07 20:31:50 +03:00
updateSeedingLimitTimer ( ) ;
2015-04-19 18:17:47 +03:00
}
2017-01-18 19:23:57 +03:00
void Session : : saveTorrentResumeData ( TorrentHandle * const torrent , bool finalSave )
2015-04-19 18:17:47 +03:00
{
2017-01-18 19:23:57 +03:00
torrent - > saveResumeData ( finalSave ) ;
2015-04-19 18:17:47 +03:00
+ + m_numResumeData ;
}
void Session : : handleTorrentSavePathChanged ( TorrentHandle * const torrent )
{
emit torrentSavePathChanged ( torrent ) ;
}
2016-02-09 11:56:48 +03:00
void Session : : handleTorrentCategoryChanged ( TorrentHandle * const torrent , const QString & oldCategory )
2015-06-07 15:03:30 +03:00
{
2016-02-09 11:56:48 +03:00
emit torrentCategoryChanged ( torrent , oldCategory ) ;
}
2015-08-16 20:03:32 +03:00
2017-06-05 03:22:17 +03:00
void Session : : handleTorrentTagAdded ( TorrentHandle * const torrent , const QString & tag )
{
emit torrentTagAdded ( torrent , tag ) ;
}
void Session : : handleTorrentTagRemoved ( TorrentHandle * const torrent , const QString & tag )
{
emit torrentTagRemoved ( torrent , tag ) ;
}
2016-02-09 11:56:48 +03:00
void Session : : handleTorrentSavingModeChanged ( TorrentHandle * const torrent )
{
emit torrentSavingModeChanged ( torrent ) ;
2015-06-07 15:03:30 +03:00
}
2015-04-19 18:17:47 +03:00
void Session : : handleTorrentTrackersAdded ( TorrentHandle * const torrent , const QList < TrackerEntry > & newTrackers )
{
foreach ( const TrackerEntry & newTracker , newTrackers )
Logger : : instance ( ) - > addMessage ( tr ( " Tracker '%1' was added to torrent '%2' " ) . arg ( newTracker . url ( ) ) . arg ( torrent - > name ( ) ) ) ;
emit trackersAdded ( torrent , newTrackers ) ;
if ( torrent - > trackers ( ) . size ( ) = = newTrackers . size ( ) )
emit trackerlessStateChanged ( torrent , false ) ;
emit trackersChanged ( torrent ) ;
}
void Session : : handleTorrentTrackersRemoved ( TorrentHandle * const torrent , const QList < TrackerEntry > & deletedTrackers )
{
foreach ( const TrackerEntry & deletedTracker , deletedTrackers )
Logger : : instance ( ) - > addMessage ( tr ( " Tracker '%1' was deleted from torrent '%2' " ) . arg ( deletedTracker . url ( ) ) . arg ( torrent - > name ( ) ) ) ;
emit trackersRemoved ( torrent , deletedTrackers ) ;
if ( torrent - > trackers ( ) . size ( ) = = 0 )
emit trackerlessStateChanged ( torrent , true ) ;
emit trackersChanged ( torrent ) ;
}
void Session : : handleTorrentTrackersChanged ( TorrentHandle * const torrent )
{
emit trackersChanged ( torrent ) ;
}
void Session : : handleTorrentUrlSeedsAdded ( TorrentHandle * const torrent , const QList < QUrl > & newUrlSeeds )
{
foreach ( const QUrl & newUrlSeed , newUrlSeeds )
Logger : : instance ( ) - > addMessage ( tr ( " URL seed '%1' was added to torrent '%2' " ) . arg ( newUrlSeed . toString ( ) ) . arg ( torrent - > name ( ) ) ) ;
}
void Session : : handleTorrentUrlSeedsRemoved ( TorrentHandle * const torrent , const QList < QUrl > & urlSeeds )
{
foreach ( const QUrl & urlSeed , urlSeeds )
Logger : : instance ( ) - > addMessage ( tr ( " URL seed '%1' was removed from torrent '%2' " ) . arg ( urlSeed . toString ( ) ) . arg ( torrent - > name ( ) ) ) ;
}
void Session : : handleTorrentMetadataReceived ( TorrentHandle * const torrent )
{
saveTorrentResumeData ( torrent ) ;
// Save metadata
const QDir resumeDataDir ( m_resumeFolderPath ) ;
QString torrentFile = resumeDataDir . absoluteFilePath ( QString ( " %1.torrent " ) . arg ( torrent - > hash ( ) ) ) ;
if ( torrent - > saveTorrentFile ( torrentFile ) ) {
// Copy the torrent file to the export folder
2016-05-01 11:05:52 +03:00
if ( ! torrentExportDirectory ( ) . isEmpty ( ) )
2015-04-19 18:17:47 +03:00
exportTorrentFile ( torrent ) ;
}
emit torrentMetadataLoaded ( torrent ) ;
}
void Session : : handleTorrentPaused ( TorrentHandle * const torrent )
{
if ( ! torrent - > hasError ( ) & & ! torrent - > hasMissingFiles ( ) )
saveTorrentResumeData ( torrent ) ;
emit torrentPaused ( torrent ) ;
}
void Session : : handleTorrentResumed ( TorrentHandle * const torrent )
{
emit torrentResumed ( torrent ) ;
}
void Session : : handleTorrentChecked ( TorrentHandle * const torrent )
{
emit torrentFinishedChecking ( torrent ) ;
}
void Session : : handleTorrentFinished ( TorrentHandle * const torrent )
{
2015-11-29 19:40:24 +03:00
if ( ! torrent - > hasError ( ) & & ! torrent - > hasMissingFiles ( ) )
saveTorrentResumeData ( torrent ) ;
2015-04-19 18:17:47 +03:00
emit torrentFinished ( torrent ) ;
qDebug ( " Checking if the torrent contains torrent files to download " ) ;
// Check if there are torrent files inside
for ( int i = 0 ; i < torrent - > filesCount ( ) ; + + i ) {
const QString torrentRelpath = torrent - > filePath ( i ) ;
if ( torrentRelpath . endsWith ( " .torrent " , Qt : : CaseInsensitive ) ) {
qDebug ( " Found possible recursive torrent download. " ) ;
2015-10-24 15:28:29 +03:00
const QString torrentFullpath = torrent - > savePath ( true ) + " / " + torrentRelpath ;
2017-08-13 13:56:03 +03:00
qDebug ( " Full subtorrent path is %s " , qUtf8Printable ( torrentFullpath ) ) ;
2015-04-19 18:17:47 +03:00
TorrentInfo torrentInfo = TorrentInfo : : loadFromFile ( torrentFullpath ) ;
if ( torrentInfo . isValid ( ) ) {
qDebug ( " emitting recursiveTorrentDownloadPossible() " ) ;
emit recursiveTorrentDownloadPossible ( torrent ) ;
break ;
}
else {
qDebug ( " Caught error loading torrent " ) ;
2015-08-08 16:19:46 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " Unable to decode '%1' torrent file. " ) . arg ( Utils : : Fs : : toNativePath ( torrentFullpath ) ) , Log : : CRITICAL ) ;
2015-04-19 18:17:47 +03:00
}
}
}
// Move .torrent file to another folder
2016-05-01 11:05:52 +03:00
if ( ! finishedTorrentExportDirectory ( ) . isEmpty ( ) )
2015-04-19 18:17:47 +03:00
exportTorrentFile ( torrent , TorrentExportFolder : : Finished ) ;
if ( ! hasUnfinishedTorrents ( ) )
emit allTorrentsFinished ( ) ;
}
void Session : : handleTorrentResumeDataReady ( TorrentHandle * const torrent , const libtorrent : : entry & data )
{
- - m_numResumeData ;
2015-12-13 15:38:19 +03:00
// Separated thread is used for the blocking IO which results in slow processing of many torrents.
// Encoding data in parallel while doing IO saves time. Copying libtorrent::entry objects around
// isn't cheap too.
QByteArray out ;
libt : : bencode ( std : : back_inserter ( out ) , data ) ;
QMetaObject : : invokeMethod ( m_resumeDataSavingManager , " saveResumeData " ,
2015-12-16 17:08:27 +03:00
Q_ARG ( QString , torrent - > hash ( ) ) , Q_ARG ( QByteArray , out ) ) ;
2015-04-19 18:17:47 +03:00
}
void Session : : handleTorrentResumeDataFailed ( TorrentHandle * const torrent )
{
Q_UNUSED ( torrent )
- - m_numResumeData ;
}
void Session : : handleTorrentTrackerReply ( TorrentHandle * const torrent , const QString & trackerUrl )
{
emit trackerSuccess ( torrent , trackerUrl ) ;
}
void Session : : handleTorrentTrackerError ( TorrentHandle * const torrent , const QString & trackerUrl )
{
emit trackerError ( torrent , trackerUrl ) ;
}
void Session : : handleTorrentTrackerAuthenticationRequired ( TorrentHandle * const torrent , const QString & trackerUrl )
{
Q_UNUSED ( trackerUrl ) ;
emit trackerAuthenticationRequired ( torrent ) ;
}
void Session : : handleTorrentTrackerWarning ( TorrentHandle * const torrent , const QString & trackerUrl )
{
emit trackerWarning ( torrent , trackerUrl ) ;
}
bool Session : : hasPerTorrentRatioLimit ( ) const
{
foreach ( TorrentHandle * const torrent , m_torrents )
if ( torrent - > ratioLimit ( ) > = 0 ) return true ;
return false ;
}
2016-02-07 20:31:50 +03:00
bool Session : : hasPerTorrentSeedingTimeLimit ( ) const
{
foreach ( TorrentHandle * const torrent , m_torrents )
if ( torrent - > seedingTimeLimit ( ) > = 0 ) return true ;
return false ;
}
2015-04-19 18:17:47 +03:00
void Session : : initResumeFolder ( )
{
2016-05-11 14:25:29 +03:00
m_resumeFolderPath = Utils : : Fs : : expandPathAbs ( specialFolderLocation ( SpecialFolder : : Data ) + RESUME_FOLDER ) ;
2015-04-19 18:17:47 +03:00
QDir resumeFolderDir ( m_resumeFolderPath ) ;
if ( resumeFolderDir . exists ( ) | | resumeFolderDir . mkpath ( resumeFolderDir . absolutePath ( ) ) ) {
m_resumeFolderLock . setFileName ( resumeFolderDir . absoluteFilePath ( " session.lock " ) ) ;
if ( ! m_resumeFolderLock . open ( QFile : : WriteOnly ) ) {
throw std : : runtime_error ( " Cannot write to torrent resume folder. " ) ;
}
}
else {
throw std : : runtime_error ( " Cannot create torrent resume folder. " ) ;
}
}
2016-05-01 11:05:52 +03:00
void Session : : configureDeferred ( )
{
2017-05-02 14:39:47 +03:00
if ( ! m_deferredConfigureScheduled ) {
QMetaObject : : invokeMethod ( this , " configure " , Qt : : QueuedConnection ) ;
m_deferredConfigureScheduled = true ;
}
2016-05-01 11:05:52 +03:00
}
2015-04-19 18:17:47 +03:00
// Enable IP Filtering
2017-03-06 15:40:34 +03:00
// this method creates ban list from scratch combining user ban list and 3rd party ban list file
2016-06-03 17:03:17 +03:00
void Session : : enableIPFilter ( )
2015-04-19 18:17:47 +03:00
{
2015-09-04 22:56:08 +03:00
qDebug ( " Enabling IPFilter " ) ;
2017-03-07 02:34:55 +03:00
// 1. Parse the IP filter
// 2. In the slot add the manually banned IPs to the provided libtorrent::ip_filter
// 3. Set the ip_filter in one go so there isn't a time window where there isn't an ip_filter
// set between clearing the old one and setting the new one.
2015-04-19 18:17:47 +03:00
if ( ! m_filterParser ) {
2017-03-07 02:34:55 +03:00
m_filterParser = new FilterParserThread ( this ) ;
2015-04-19 18:17:47 +03:00
connect ( m_filterParser . data ( ) , SIGNAL ( IPFilterParsed ( int ) ) , SLOT ( handleIPFilterParsed ( int ) ) ) ;
connect ( m_filterParser . data ( ) , SIGNAL ( IPFilterError ( ) ) , SLOT ( handleIPFilterError ( ) ) ) ;
}
2016-06-03 17:03:17 +03:00
m_filterParser - > processFilterFile ( IPFilterFile ( ) ) ;
2015-04-19 18:17:47 +03:00
}
// Disable IP Filtering
void Session : : disableIPFilter ( )
{
qDebug ( " Disabling IPFilter " ) ;
if ( m_filterParser ) {
disconnect ( m_filterParser . data ( ) , 0 , this , 0 ) ;
delete m_filterParser ;
}
2016-06-03 17:03:17 +03:00
// Add the banned IPs after the IPFilter disabling
// which creates an empty filter and overrides all previously
// applied bans.
2017-03-07 02:34:55 +03:00
libt : : ip_filter filter ;
processBannedIPs ( filter ) ;
m_nativeSession - > set_ip_filter ( filter ) ;
2015-04-19 18:17:47 +03:00
}
void Session : : recursiveTorrentDownload ( const InfoHash & hash )
{
TorrentHandle * const torrent = m_torrents . value ( hash ) ;
if ( ! torrent ) return ;
for ( int i = 0 ; i < torrent - > filesCount ( ) ; + + i ) {
const QString torrentRelpath = torrent - > filePath ( i ) ;
if ( torrentRelpath . endsWith ( " .torrent " ) ) {
Logger : : instance ( ) - > addMessage (
2015-08-08 16:19:46 +03:00
tr ( " Recursive download of file '%1' embedded in torrent '%2' "
, " Recursive download of 'test.torrent' embedded in torrent 'test2' " )
2015-05-06 14:53:27 +03:00
. arg ( Utils : : Fs : : toNativePath ( torrentRelpath ) ) . arg ( torrent - > name ( ) ) ) ;
2015-04-19 18:17:47 +03:00
const QString torrentFullpath = torrent - > savePath ( ) + " / " + torrentRelpath ;
AddTorrentParams params ;
// Passing the save path along to the sub torrent file
params . savePath = torrent - > savePath ( ) ;
addTorrent ( TorrentInfo : : loadFromFile ( torrentFullpath ) , params ) ;
}
}
}
2017-04-29 14:45:30 +03:00
const SessionStatus & Session : : status ( ) const
2015-04-19 18:17:47 +03:00
{
2017-04-29 14:45:30 +03:00
return m_status ;
2015-04-19 18:17:47 +03:00
}
2017-04-29 14:45:30 +03:00
const CacheStatus & Session : : cacheStatus ( ) const
2015-04-19 18:17:47 +03:00
{
2017-04-29 14:45:30 +03:00
return m_cacheStatus ;
2015-04-19 18:17:47 +03:00
}
// Will resume torrents in backup directory
void Session : : startUpTorrents ( )
{
qDebug ( " Resuming torrents... " ) ;
const QDir resumeDataDir ( m_resumeFolderPath ) ;
QStringList fastresumes = resumeDataDir . entryList (
2015-12-16 17:08:27 +03:00
QStringList ( QLatin1String ( " *.fastresume " ) ) , QDir : : Files , QDir : : Unsorted ) ;
2015-04-19 18:17:47 +03:00
Logger * const logger = Logger : : instance ( ) ;
2015-12-16 17:08:27 +03:00
typedef struct
{
QString hash ;
MagnetUri magnetUri ;
AddTorrentData addTorrentData ;
QByteArray data ;
} TorrentResumeData ;
2017-01-23 18:45:37 +03:00
int resumedTorrentsCount = 0 ;
const auto startupTorrent = [ this , logger , & resumeDataDir , & resumedTorrentsCount ] ( const TorrentResumeData & params )
2015-12-17 16:47:34 +03:00
{
QString filePath = resumeDataDir . filePath ( QString ( " %1.torrent " ) . arg ( params . hash ) ) ;
qDebug ( ) < < " Starting up torrent " < < params . hash < < " ... " ;
if ( ! addTorrent_impl ( params . addTorrentData , params . magnetUri , TorrentInfo : : loadFromFile ( filePath ) , params . data ) )
logger - > addMessage ( tr ( " Unable to resume torrent '%1'. " , " e.g: Unable to resume torrent 'hash'. " )
. arg ( params . hash ) , Log : : CRITICAL ) ;
2017-01-23 18:45:37 +03:00
// process add torrent messages before message queue overflow
if ( resumedTorrentsCount % 100 = = 0 ) readAlerts ( ) ;
+ + resumedTorrentsCount ;
2015-12-17 16:47:34 +03:00
} ;
2015-04-19 18:17:47 +03:00
qDebug ( " Starting up torrents " ) ;
2015-12-16 17:08:27 +03:00
qDebug ( " Queue size: %d " , fastresumes . size ( ) ) ;
2015-04-19 18:17:47 +03:00
// Resume downloads
2015-12-16 17:08:27 +03:00
QMap < int , TorrentResumeData > queuedResumeData ;
2015-12-17 16:47:34 +03:00
int nextQueuePosition = 1 ;
2017-01-18 19:17:51 +03:00
int numOfRemappedFiles = 0 ;
2015-12-16 17:08:27 +03:00
QRegExp rx ( QLatin1String ( " ^([A-Fa-f0-9]{40}) \ \ . fastresume $ " )) ;
foreach ( const QString & fastresumeName , fastresumes ) {
if ( rx . indexIn ( fastresumeName ) = = - 1 ) continue ;
2015-04-19 18:17:47 +03:00
2015-12-16 17:08:27 +03:00
QString hash = rx . cap ( 1 ) ;
2015-12-17 16:47:34 +03:00
QString fastresumePath = resumeDataDir . absoluteFilePath ( fastresumeName ) ;
2015-04-19 18:17:47 +03:00
QByteArray data ;
AddTorrentData resumeData ;
2015-06-04 11:03:19 +03:00
MagnetUri magnetUri ;
2015-12-16 17:08:27 +03:00
int queuePosition ;
if ( readFile ( fastresumePath , data ) & & loadTorrentResumeData ( data , resumeData , queuePosition , magnetUri ) ) {
2015-12-17 16:47:34 +03:00
if ( queuePosition < = nextQueuePosition ) {
startupTorrent ( { hash , magnetUri , resumeData , data } ) ;
if ( queuePosition = = nextQueuePosition ) {
+ + nextQueuePosition ;
while ( queuedResumeData . contains ( nextQueuePosition ) ) {
startupTorrent ( queuedResumeData . take ( nextQueuePosition ) ) ;
+ + nextQueuePosition ;
}
}
2015-12-16 17:08:27 +03:00
}
else {
2017-01-18 19:17:51 +03:00
int q = queuePosition ;
for ( ; queuedResumeData . contains ( q ) ; + + q ) {
}
if ( q ! = queuePosition ) {
+ + numOfRemappedFiles ;
}
queuedResumeData [ q ] = { hash , magnetUri , resumeData , data } ;
2015-12-16 17:08:27 +03:00
}
2015-04-19 18:17:47 +03:00
}
}
2015-12-16 17:08:27 +03:00
2017-01-18 19:17:51 +03:00
if ( numOfRemappedFiles > 0 ) {
logger - > addMessage (
QString ( tr ( " Queue positions were corrected in %1 resume files " ) ) . arg ( numOfRemappedFiles ) ,
Log : : CRITICAL ) ;
}
2015-12-16 17:08:27 +03:00
// starting up downloading torrents (queue position > 0)
2015-12-17 16:47:34 +03:00
foreach ( const TorrentResumeData & torrentResumeData , queuedResumeData )
startupTorrent ( torrentResumeData ) ;
2015-04-19 18:17:47 +03:00
}
quint64 Session : : getAlltimeDL ( ) const
{
return m_statistics - > getAlltimeDL ( ) ;
}
quint64 Session : : getAlltimeUL ( ) const
{
return m_statistics - > getAlltimeUL ( ) ;
}
void Session : : refresh ( )
{
m_nativeSession - > post_torrent_updates ( ) ;
2017-04-29 14:52:28 +03:00
# if LIBTORRENT_VERSION_NUM >= 10100
m_nativeSession - > post_session_stats ( ) ;
# endif
2015-04-19 18:17:47 +03:00
}
void Session : : handleIPFilterParsed ( int ruleCount )
{
2017-04-17 17:07:12 +03:00
if ( m_filterParser ) {
2017-03-07 02:34:55 +03:00
libt : : ip_filter filter = m_filterParser - > IPfilter ( ) ;
processBannedIPs ( filter ) ;
m_nativeSession - > set_ip_filter ( filter ) ;
}
2015-04-19 18:17:47 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " Successfully parsed the provided IP filter: %1 rules were applied. " , " %1 is a number " ) . arg ( ruleCount ) ) ;
2016-05-01 11:05:52 +03:00
emit IPFilterParsed ( false , ruleCount ) ;
2015-04-19 18:17:47 +03:00
}
void Session : : handleIPFilterError ( )
{
2017-03-07 02:34:55 +03:00
libt : : ip_filter filter ;
processBannedIPs ( filter ) ;
m_nativeSession - > set_ip_filter ( filter ) ;
2015-04-19 18:17:47 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " Error: Failed to parse the provided IP filter. " ) , Log : : CRITICAL ) ;
2016-05-01 11:05:52 +03:00
emit IPFilterParsed ( true , 0 ) ;
2015-04-19 18:17:47 +03:00
}
2016-04-28 10:56:58 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2016-12-08 15:13:14 +03:00
void Session : : dispatchAlerts ( libt : : alert * alertPtr )
2015-04-19 18:17:47 +03:00
{
QMutexLocker lock ( & m_alertsMutex ) ;
2016-04-28 10:56:58 +03:00
bool wasEmpty = m_alerts . empty ( ) ;
2015-04-19 18:17:47 +03:00
2016-12-08 15:13:14 +03:00
m_alerts . push_back ( alertPtr ) ;
2015-04-19 18:17:47 +03:00
if ( wasEmpty ) {
m_alertsWaitCondition . wakeAll ( ) ;
QMetaObject : : invokeMethod ( this , " readAlerts " , Qt : : QueuedConnection ) ;
}
}
2016-04-28 10:56:58 +03:00
# endif
2015-04-19 18:17:47 +03:00
2016-04-28 10:56:58 +03:00
void Session : : getPendingAlerts ( std : : vector < libt : : alert * > & out , ulong time )
2015-04-19 18:17:47 +03:00
{
Q_ASSERT ( out . empty ( ) ) ;
2016-04-28 10:56:58 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2015-04-19 18:17:47 +03:00
QMutexLocker lock ( & m_alertsMutex ) ;
2015-12-08 00:54:38 +03:00
if ( m_alerts . empty ( ) )
2015-04-19 18:17:47 +03:00
m_alertsWaitCondition . wait ( & m_alertsMutex , time ) ;
m_alerts . swap ( out ) ;
2016-04-28 10:56:58 +03:00
# else
if ( time > 0 )
m_nativeSession - > wait_for_alert ( libt : : milliseconds ( time ) ) ;
m_nativeSession - > pop_alerts ( & out ) ;
# endif
2015-04-19 18:17:47 +03:00
}
2017-04-15 17:21:24 +03:00
bool Session : : isCreateTorrentSubfolder ( ) const
{
return m_isCreateTorrentSubfolder ;
}
void Session : : setCreateTorrentSubfolder ( bool value )
{
m_isCreateTorrentSubfolder = value ;
}
2015-04-19 18:17:47 +03:00
// Read alerts sent by the BitTorrent session
void Session : : readAlerts ( )
{
2016-04-28 10:56:58 +03:00
std : : vector < libt : : alert * > alerts ;
2015-04-19 18:17:47 +03:00
getPendingAlerts ( alerts ) ;
2016-04-28 10:56:58 +03:00
for ( const auto a : alerts ) {
2015-04-19 18:17:47 +03:00
handleAlert ( a ) ;
2016-04-28 10:56:58 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2015-04-19 18:17:47 +03:00
delete a ;
2016-04-28 10:56:58 +03:00
# endif
2015-04-19 18:17:47 +03:00
}
}
void Session : : handleAlert ( libt : : alert * a )
{
try {
switch ( a - > type ( ) ) {
case libt : : stats_alert : : alert_type :
case libt : : file_renamed_alert : : alert_type :
case libt : : file_completed_alert : : alert_type :
case libt : : torrent_finished_alert : : alert_type :
case libt : : save_resume_data_alert : : alert_type :
case libt : : save_resume_data_failed_alert : : alert_type :
case libt : : storage_moved_alert : : alert_type :
case libt : : storage_moved_failed_alert : : alert_type :
case libt : : torrent_paused_alert : : alert_type :
case libt : : tracker_error_alert : : alert_type :
case libt : : tracker_reply_alert : : alert_type :
case libt : : tracker_warning_alert : : alert_type :
case libt : : fastresume_rejected_alert : : alert_type :
case libt : : torrent_checked_alert : : alert_type :
dispatchTorrentAlert ( a ) ;
break ;
case libt : : metadata_received_alert : : alert_type :
handleMetadataReceivedAlert ( static_cast < libt : : metadata_received_alert * > ( a ) ) ;
dispatchTorrentAlert ( a ) ;
break ;
case libt : : state_update_alert : : alert_type :
handleStateUpdateAlert ( static_cast < libt : : state_update_alert * > ( a ) ) ;
break ;
2017-04-29 14:52:28 +03:00
# if LIBTORRENT_VERSION_NUM >= 10100
case libt : : session_stats_alert : : alert_type :
handleSessionStatsAlert ( static_cast < libt : : session_stats_alert * > ( a ) ) ;
break ;
# endif
2015-04-19 18:17:47 +03:00
case libt : : file_error_alert : : alert_type :
handleFileErrorAlert ( static_cast < libt : : file_error_alert * > ( a ) ) ;
break ;
case libt : : add_torrent_alert : : alert_type :
handleAddTorrentAlert ( static_cast < libt : : add_torrent_alert * > ( a ) ) ;
break ;
case libt : : torrent_removed_alert : : alert_type :
handleTorrentRemovedAlert ( static_cast < libt : : torrent_removed_alert * > ( a ) ) ;
break ;
case libt : : torrent_deleted_alert : : alert_type :
handleTorrentDeletedAlert ( static_cast < libt : : torrent_deleted_alert * > ( a ) ) ;
break ;
2015-08-09 10:27:56 +03:00
case libt : : torrent_delete_failed_alert : : alert_type :
handleTorrentDeleteFailedAlert ( static_cast < libt : : torrent_delete_failed_alert * > ( a ) ) ;
break ;
2015-04-19 18:17:47 +03:00
case libt : : portmap_error_alert : : alert_type :
handlePortmapWarningAlert ( static_cast < libt : : portmap_error_alert * > ( a ) ) ;
break ;
case libt : : portmap_alert : : alert_type :
handlePortmapAlert ( static_cast < libt : : portmap_alert * > ( a ) ) ;
break ;
case libt : : peer_blocked_alert : : alert_type :
handlePeerBlockedAlert ( static_cast < libt : : peer_blocked_alert * > ( a ) ) ;
break ;
case libt : : peer_ban_alert : : alert_type :
handlePeerBanAlert ( static_cast < libt : : peer_ban_alert * > ( a ) ) ;
break ;
case libt : : url_seed_alert : : alert_type :
handleUrlSeedAlert ( static_cast < libt : : url_seed_alert * > ( a ) ) ;
break ;
case libt : : listen_succeeded_alert : : alert_type :
handleListenSucceededAlert ( static_cast < libt : : listen_succeeded_alert * > ( a ) ) ;
break ;
case libt : : listen_failed_alert : : alert_type :
handleListenFailedAlert ( static_cast < libt : : listen_failed_alert * > ( a ) ) ;
break ;
case libt : : external_ip_alert : : alert_type :
handleExternalIPAlert ( static_cast < libt : : external_ip_alert * > ( a ) ) ;
break ;
}
}
catch ( std : : exception & exc ) {
2017-03-07 14:41:38 +03:00
qWarning ( ) < < " Caught exception in " < < Q_FUNC_INFO < < " : " < < QString : : fromStdString ( exc . what ( ) ) ;
2015-04-19 18:17:47 +03:00
}
}
void Session : : dispatchTorrentAlert ( libt : : alert * a )
{
2015-09-25 10:52:25 +03:00
TorrentHandle * const torrent = m_torrents . value ( static_cast < libt : : torrent_alert * > ( a ) - > handle . info_hash ( ) ) ;
2015-04-19 18:17:47 +03:00
if ( torrent )
torrent - > handleAlert ( a ) ;
}
2016-01-20 09:57:02 +03:00
void Session : : createTorrentHandle ( const libt : : torrent_handle & nativeHandle )
2015-04-19 18:17:47 +03:00
{
// Magnet added for preload its metadata
2016-01-20 09:57:02 +03:00
if ( ! m_addingTorrents . contains ( nativeHandle . info_hash ( ) ) ) return ;
2015-04-19 18:17:47 +03:00
2016-01-20 09:57:02 +03:00
AddTorrentData data = m_addingTorrents . take ( nativeHandle . info_hash ( ) ) ;
2015-04-19 18:17:47 +03:00
2016-01-20 09:57:02 +03:00
TorrentHandle * const torrent = new TorrentHandle ( this , nativeHandle , data ) ;
2015-04-19 18:17:47 +03:00
m_torrents . insert ( torrent - > hash ( ) , torrent ) ;
2016-01-20 09:57:02 +03:00
Logger * const logger = Logger : : instance ( ) ;
2015-04-19 18:17:47 +03:00
bool fromMagnetUri = ! torrent - > hasMetadata ( ) ;
if ( data . resumed ) {
2017-04-24 11:59:16 +03:00
if ( fromMagnetUri & & ! data . addPaused )
torrent - > resume ( data . addForced ) ;
2015-06-04 11:03:19 +03:00
2015-04-19 18:17:47 +03:00
logger - > addMessage ( tr ( " '%1' resumed. (fast resume) " , " 'torrent name' was resumed. (fast resume) " )
. arg ( torrent - > name ( ) ) ) ;
}
else {
qDebug ( " This is a NEW torrent (first time)... " ) ;
// The following is useless for newly added magnet
if ( ! fromMagnetUri ) {
// Backup torrent file
const QDir resumeDataDir ( m_resumeFolderPath ) ;
const QString newFile = resumeDataDir . absoluteFilePath ( QString ( " %1.torrent " ) . arg ( torrent - > hash ( ) ) ) ;
if ( torrent - > saveTorrentFile ( newFile ) ) {
// Copy the torrent file to the export folder
2016-05-01 11:05:52 +03:00
if ( ! torrentExportDirectory ( ) . isEmpty ( ) )
2015-04-19 18:17:47 +03:00
exportTorrentFile ( torrent ) ;
}
else {
2015-08-08 16:19:46 +03:00
logger - > addMessage ( tr ( " Couldn't save '%1.torrent' " ) . arg ( torrent - > hash ( ) ) , Log : : CRITICAL ) ;
2015-04-19 18:17:47 +03:00
}
}
2016-05-01 11:05:52 +03:00
if ( isAddTrackersEnabled ( ) & & ! torrent - > isPrivate ( ) )
torrent - > addTrackers ( m_additionalTrackerList ) ;
2015-06-30 21:03:17 +03:00
2015-04-19 18:17:47 +03:00
// Start torrent because it was added in paused state
2017-04-24 11:59:16 +03:00
if ( ! data . addPaused )
2015-04-19 18:17:47 +03:00
torrent - > resume ( ) ;
logger - > addMessage ( tr ( " '%1' added to download list. " , " 'torrent name' was added to download list. " )
. arg ( torrent - > name ( ) ) ) ;
2015-11-29 19:40:24 +03:00
// In case of crash before the scheduled generation
// of the fastresumes.
saveTorrentResumeData ( torrent ) ;
2015-04-19 18:17:47 +03:00
}
2016-02-07 20:31:50 +03:00
if ( ( ( torrent - > ratioLimit ( ) > = 0 ) | | ( torrent - > seedingTimeLimit ( ) > = 0 ) )
& & ! m_seedingLimitTimer - > isActive ( ) )
m_seedingLimitTimer - > start ( ) ;
2015-04-19 18:17:47 +03:00
// Send torrent addition signal
emit torrentAdded ( torrent ) ;
2016-04-30 01:38:24 +03:00
// Send new torrent signal
if ( ! data . resumed )
emit torrentNew ( torrent ) ;
2015-04-19 18:17:47 +03:00
}
2016-01-20 09:57:02 +03:00
void Session : : handleAddTorrentAlert ( libt : : add_torrent_alert * p )
{
if ( p - > error ) {
qDebug ( " /! \\ Error: Failed to add torrent! " ) ;
2017-03-07 14:41:38 +03:00
QString msg = QString : : fromStdString ( p - > message ( ) ) ;
2016-01-20 09:57:02 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " Couldn't add torrent. Reason: %1 " ) . arg ( msg ) , Log : : WARNING ) ;
emit addTorrentFailed ( msg ) ;
}
else {
createTorrentHandle ( p - > handle ) ;
}
}
void Session : : handleTorrentRemovedAlert ( libt : : torrent_removed_alert * p )
2015-04-19 18:17:47 +03:00
{
if ( m_loadedMetadata . contains ( p - > info_hash ) )
emit metadataLoaded ( m_loadedMetadata . take ( p - > info_hash ) ) ;
2017-09-14 19:55:14 +03:00
if ( m_removingTorrents . contains ( p - > info_hash ) ) {
const RemovingTorrentData tmpRemovingTorrentData = m_removingTorrents [ p - > info_hash ] ;
if ( ! tmpRemovingTorrentData . requestedFileDeletion ) {
LogMsg ( tr ( " '%1' was removed from the transfer list. " , " 'xxx.avi' was removed... " ) . arg ( tmpRemovingTorrentData . name ) ) ;
m_removingTorrents . remove ( p - > info_hash ) ;
}
}
2015-04-19 18:17:47 +03:00
}
void Session : : handleTorrentDeletedAlert ( libt : : torrent_deleted_alert * p )
{
2017-09-14 19:55:14 +03:00
if ( ! m_removingTorrents . contains ( p - > info_hash ) )
return ;
const RemovingTorrentData tmpRemovingTorrentData = m_removingTorrents . take ( p - > info_hash ) ;
Utils : : Fs : : smartRemoveEmptyFolderTree ( tmpRemovingTorrentData . savePathToRemove ) ;
LogMsg ( tr ( " '%1' was removed from the transfer list and hard disk. " , " 'xxx.avi' was removed... " ) . arg ( tmpRemovingTorrentData . name ) ) ;
2015-08-09 10:27:56 +03:00
}
void Session : : handleTorrentDeleteFailedAlert ( libt : : torrent_delete_failed_alert * p )
{
2017-09-14 19:55:14 +03:00
if ( ! m_removingTorrents . contains ( p - > info_hash ) )
return ;
const RemovingTorrentData tmpRemovingTorrentData = m_removingTorrents . take ( p - > info_hash ) ;
2015-08-09 10:27:56 +03:00
// libtorrent won't delete the directory if it contains files not listed in the torrent,
// so we remove the directory ourselves
2017-09-14 19:55:14 +03:00
Utils : : Fs : : smartRemoveEmptyFolderTree ( tmpRemovingTorrentData . savePathToRemove ) ;
LogMsg ( tr ( " '%1' was removed from the transfer list but the files couldn't be deleted. Error: %2 " , " 'xxx.avi' was removed... " )
. arg ( tmpRemovingTorrentData . name )
. arg ( QString : : fromLocal8Bit ( p - > error . message ( ) . c_str ( ) ) ) , Log : : CRITICAL ) ;
2015-04-19 18:17:47 +03:00
}
void Session : : handleMetadataReceivedAlert ( libt : : metadata_received_alert * p )
{
InfoHash hash = p - > handle . info_hash ( ) ;
if ( m_loadedMetadata . contains ( hash ) ) {
- - m_extraLimit ;
adjustLimits ( ) ;
m_loadedMetadata [ hash ] = TorrentInfo ( p - > handle . torrent_file ( ) ) ;
m_nativeSession - > remove_torrent ( p - > handle , libt : : session : : delete_files ) ;
}
}
void Session : : handleFileErrorAlert ( libt : : file_error_alert * p )
{
qDebug ( ) < < Q_FUNC_INFO ;
// NOTE: Check this function!
TorrentHandle * const torrent = m_torrents . value ( p - > handle . info_hash ( ) ) ;
if ( torrent ) {
2017-03-07 14:41:38 +03:00
QString msg = QString : : fromStdString ( p - > message ( ) ) ;
2015-04-19 18:17:47 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " An I/O error occurred, '%1' paused. %2 " )
. arg ( torrent - > name ( ) ) . arg ( msg ) ) ;
emit fullDiskError ( torrent , msg ) ;
}
}
void Session : : handlePortmapWarningAlert ( libt : : portmap_error_alert * p )
{
2017-03-07 14:41:38 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " UPnP/NAT-PMP: Port mapping failure, message: %1 " ) . arg ( QString : : fromStdString ( p - > message ( ) ) ) , Log : : CRITICAL ) ;
2015-04-19 18:17:47 +03:00
}
void Session : : handlePortmapAlert ( libt : : portmap_alert * p )
{
qDebug ( " UPnP Success, msg: %s " , p - > message ( ) . c_str ( ) ) ;
2017-03-07 14:41:38 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " UPnP/NAT-PMP: Port mapping successful, message: %1 " ) . arg ( QString : : fromStdString ( p - > message ( ) ) ) , Log : : INFO ) ;
2015-04-19 18:17:47 +03:00
}
void Session : : handlePeerBlockedAlert ( libt : : peer_blocked_alert * p )
{
boost : : system : : error_code ec ;
std : : string ip = p - > ip . to_string ( ec ) ;
QString reason ;
switch ( p - > reason ) {
case libt : : peer_blocked_alert : : ip_filter :
reason = tr ( " due to IP filter. " , " this peer was blocked due to ip filter. " ) ;
break ;
case libt : : peer_blocked_alert : : port_filter :
reason = tr ( " due to port filter. " , " this peer was blocked due to port filter. " ) ;
break ;
case libt : : peer_blocked_alert : : i2p_mixed :
reason = tr ( " due to i2p mixed mode restrictions. " , " this peer was blocked due to i2p mixed mode restrictions. " ) ;
break ;
case libt : : peer_blocked_alert : : privileged_ports :
reason = tr ( " because it has a low port. " , " this peer was blocked because it has a low port. " ) ;
break ;
case libt : : peer_blocked_alert : : utp_disabled :
2015-09-04 22:56:08 +03:00
reason = trUtf8 ( " because %1 is disabled. " , " this peer was blocked because uTP is disabled. " ) . arg ( QString : : fromUtf8 ( C_UTP ) ) ; // don't translate μTP
2015-04-19 18:17:47 +03:00
break ;
case libt : : peer_blocked_alert : : tcp_disabled :
2015-09-04 22:56:08 +03:00
reason = tr ( " because %1 is disabled. " , " this peer was blocked because TCP is disabled. " ) . arg ( " TCP " ) ; // don't translate TCP
2015-04-19 18:17:47 +03:00
break ;
}
if ( ! ec )
Logger : : instance ( ) - > addPeer ( QString : : fromLatin1 ( ip . c_str ( ) ) , true , reason ) ;
}
void Session : : handlePeerBanAlert ( libt : : peer_ban_alert * p )
{
boost : : system : : error_code ec ;
std : : string ip = p - > ip . address ( ) . to_string ( ec ) ;
if ( ! ec )
Logger : : instance ( ) - > addPeer ( QString : : fromLatin1 ( ip . c_str ( ) ) , false ) ;
}
void Session : : handleUrlSeedAlert ( libt : : url_seed_alert * p )
{
2017-05-01 19:25:10 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " URL seed lookup failed for URL: '%1', message: %2 " )
# if LIBTORRENT_VERSION_NUM >= 10100
. arg ( QString : : fromStdString ( p - > server_url ( ) ) )
# else
. arg ( QString : : fromStdString ( p - > url ) )
# endif
. arg ( QString : : fromStdString ( p - > message ( ) ) ) , Log : : CRITICAL ) ;
2015-04-19 18:17:47 +03:00
}
void Session : : handleListenSucceededAlert ( libt : : listen_succeeded_alert * p )
{
boost : : system : : error_code ec ;
QString proto = " TCP " ;
if ( p - > sock_type = = libt : : listen_succeeded_alert : : udp )
proto = " UDP " ;
else if ( p - > sock_type = = libt : : listen_succeeded_alert : : tcp )
proto = " TCP " ;
else if ( p - > sock_type = = libt : : listen_succeeded_alert : : tcp_ssl )
proto = " TCP_SSL " ;
qDebug ( ) < < " Successfully listening on " < < proto < < p - > endpoint . address ( ) . to_string ( ec ) . c_str ( ) < < " / " < < p - > endpoint . port ( ) ;
Logger : : instance ( ) - > addMessage ( tr ( " qBittorrent is successfully listening on interface %1 port: %2/%3 " , " e.g: qBittorrent is successfully listening on interface 192.168.0.1 port: TCP/6881 " ) . arg ( p - > endpoint . address ( ) . to_string ( ec ) . c_str ( ) ) . arg ( proto ) . arg ( QString : : number ( p - > endpoint . port ( ) ) ) , Log : : INFO ) ;
// Force reannounce on all torrents because some trackers blacklist some ports
std : : vector < libt : : torrent_handle > torrents = m_nativeSession - > get_torrents ( ) ;
std : : vector < libt : : torrent_handle > : : iterator it = torrents . begin ( ) ;
std : : vector < libt : : torrent_handle > : : iterator itend = torrents . end ( ) ;
for ( ; it ! = itend ; + + it )
it - > force_reannounce ( ) ;
}
void Session : : handleListenFailedAlert ( libt : : listen_failed_alert * p )
{
2016-02-21 19:42:55 +03:00
boost : : system : : error_code ec ;
2015-04-19 18:17:47 +03:00
QString proto = " TCP " ;
if ( p - > sock_type = = libt : : listen_failed_alert : : udp )
proto = " UDP " ;
else if ( p - > sock_type = = libt : : listen_failed_alert : : tcp )
proto = " TCP " ;
else if ( p - > sock_type = = libt : : listen_failed_alert : : tcp_ssl )
proto = " TCP_SSL " ;
else if ( p - > sock_type = = libt : : listen_failed_alert : : i2p )
proto = " I2P " ;
else if ( p - > sock_type = = libt : : listen_failed_alert : : socks5 )
proto = " SOCKS5 " ;
qDebug ( ) < < " Failed listening on " < < proto < < p - > endpoint . address ( ) . to_string ( ec ) . c_str ( ) < < " / " < < p - > endpoint . port ( ) ;
Logger : : instance ( ) - > addMessage (
2015-11-30 19:53:19 +03:00
tr ( " qBittorrent failed listening on interface %1 port: %2/%3. Reason: %4. " ,
2016-01-20 09:57:02 +03:00
" e.g: qBittorrent failed listening on interface 192.168.0.1 port: TCP/6881. Reason: already in use. " )
2015-04-19 18:17:47 +03:00
. arg ( p - > endpoint . address ( ) . to_string ( ec ) . c_str ( ) ) . arg ( proto ) . arg ( QString : : number ( p - > endpoint . port ( ) ) )
2015-11-30 19:53:19 +03:00
. arg ( QString : : fromLocal8Bit ( p - > error . message ( ) . c_str ( ) ) ) , Log : : CRITICAL ) ;
2015-04-19 18:17:47 +03:00
}
void Session : : handleExternalIPAlert ( libt : : external_ip_alert * p )
{
boost : : system : : error_code ec ;
Logger : : instance ( ) - > addMessage ( tr ( " External IP: %1 " , " e.g. External IP: 192.168.0.1 " ) . arg ( p - > external_address . to_string ( ec ) . c_str ( ) ) , Log : : INFO ) ;
}
2017-04-29 14:52:28 +03:00
# if LIBTORRENT_VERSION_NUM >= 10100
void Session : : handleSessionStatsAlert ( libt : : session_stats_alert * p )
{
qreal interval = m_statsUpdateTimer . restart ( ) / 1000. ;
m_status . hasIncomingConnections = static_cast < bool > ( p - > values [ m_metricIndices . net . hasIncomingConnections ] ) ;
const auto ipOverheadDownload = p - > values [ m_metricIndices . net . recvIPOverheadBytes ] ;
const auto ipOverheadUpload = p - > values [ m_metricIndices . net . sentIPOverheadBytes ] ;
const auto totalDownload = p - > values [ m_metricIndices . net . recvBytes ] + ipOverheadDownload ;
const auto totalUpload = p - > values [ m_metricIndices . net . sentBytes ] + ipOverheadUpload ;
const auto totalPayloadDownload = p - > values [ m_metricIndices . net . recvPayloadBytes ] ;
const auto totalPayloadUpload = p - > values [ m_metricIndices . net . sentPayloadBytes ] ;
const auto trackerDownload = p - > values [ m_metricIndices . net . recvTrackerBytes ] ;
const auto trackerUpload = p - > values [ m_metricIndices . net . sentTrackerBytes ] ;
const auto dhtDownload = p - > values [ m_metricIndices . dht . dhtBytesIn ] ;
const auto dhtUpload = p - > values [ m_metricIndices . dht . dhtBytesOut ] ;
auto calcRate = [ interval ] ( quint64 previous , quint64 current )
{
Q_ASSERT ( current > = previous ) ;
return static_cast < quint64 > ( ( current - previous ) / interval ) ;
} ;
m_status . payloadDownloadRate = calcRate ( m_status . totalPayloadDownload , totalPayloadDownload ) ;
m_status . payloadUploadRate = calcRate ( m_status . totalPayloadUpload , totalPayloadUpload ) ;
m_status . downloadRate = calcRate ( m_status . totalDownload , totalDownload ) ;
m_status . uploadRate = calcRate ( m_status . totalUpload , totalUpload ) ;
m_status . ipOverheadDownloadRate = calcRate ( m_status . ipOverheadDownload , ipOverheadDownload ) ;
m_status . ipOverheadUploadRate = calcRate ( m_status . ipOverheadUpload , ipOverheadUpload ) ;
m_status . dhtDownloadRate = calcRate ( m_status . dhtDownload , dhtDownload ) ;
m_status . dhtUploadRate = calcRate ( m_status . dhtUpload , dhtUpload ) ;
m_status . trackerDownloadRate = calcRate ( m_status . trackerDownload , trackerDownload ) ;
m_status . trackerUploadRate = calcRate ( m_status . trackerUpload , trackerUpload ) ;
m_status . totalDownload = totalDownload ;
m_status . totalUpload = totalUpload ;
m_status . totalPayloadDownload = totalPayloadDownload ;
m_status . totalPayloadUpload = totalPayloadUpload ;
m_status . ipOverheadDownload = ipOverheadDownload ;
m_status . ipOverheadUpload = ipOverheadUpload ;
m_status . trackerDownload = trackerDownload ;
m_status . trackerUpload = trackerUpload ;
m_status . dhtDownload = dhtDownload ;
m_status . dhtUpload = dhtUpload ;
m_status . totalWasted = p - > values [ m_metricIndices . net . recvRedundantBytes ]
+ p - > values [ m_metricIndices . net . recvFailedBytes ] ;
m_status . dhtNodes = p - > values [ m_metricIndices . dht . dhtNodes ] ;
m_status . diskReadQueue = p - > values [ m_metricIndices . peer . numPeersUpDisk ] ;
m_status . diskWriteQueue = p - > values [ m_metricIndices . peer . numPeersDownDisk ] ;
m_status . peersCount = p - > values [ m_metricIndices . peer . numPeersConnected ] ;
const auto numBlocksRead = p - > values [ m_metricIndices . disk . numBlocksRead ] ;
m_cacheStatus . totalUsedBuffers = p - > values [ m_metricIndices . disk . diskBlocksInUse ] ;
m_cacheStatus . readRatio = numBlocksRead > 0
? static_cast < qreal > ( p - > values [ m_metricIndices . disk . numBlocksCacheHits ] ) / numBlocksRead
: - 1 ;
m_cacheStatus . jobQueueLength = p - > values [ m_metricIndices . disk . queuedDiskJobs ] ;
2017-08-14 17:27:31 +03:00
quint64 totalJobs = p - > values [ m_metricIndices . disk . writeJobs ] + p - > values [ m_metricIndices . disk . readJobs ]
+ p - > values [ m_metricIndices . disk . hashJobs ] ;
m_cacheStatus . averageJobTime = totalJobs > 0
? ( p - > values [ m_metricIndices . disk . diskJobTime ] / totalJobs ) : 0 ;
2017-04-29 14:52:28 +03:00
emit statsUpdated ( ) ;
}
# else
2017-04-29 14:45:30 +03:00
void Session : : updateStats ( )
{
libt : : session_status ss = m_nativeSession - > status ( ) ;
m_status . hasIncomingConnections = ss . has_incoming_connections ;
m_status . payloadDownloadRate = ss . payload_download_rate ;
m_status . payloadUploadRate = ss . payload_upload_rate ;
m_status . downloadRate = ss . download_rate ;
m_status . uploadRate = ss . upload_rate ;
m_status . ipOverheadDownloadRate = ss . ip_overhead_download_rate ;
m_status . ipOverheadUploadRate = ss . ip_overhead_upload_rate ;
m_status . dhtDownloadRate = ss . dht_download_rate ;
m_status . dhtUploadRate = ss . dht_upload_rate ;
m_status . trackerDownloadRate = ss . tracker_download_rate ;
m_status . trackerUploadRate = ss . tracker_upload_rate ;
2017-04-29 14:52:28 +03:00
2017-04-29 14:45:30 +03:00
m_status . totalDownload = ss . total_download ;
m_status . totalUpload = ss . total_upload ;
m_status . totalPayloadDownload = ss . total_payload_download ;
m_status . totalPayloadUpload = ss . total_payload_upload ;
m_status . totalWasted = ss . total_redundant_bytes + ss . total_failed_bytes ;
m_status . diskReadQueue = ss . disk_read_queue ;
m_status . diskWriteQueue = ss . disk_write_queue ;
m_status . dhtNodes = ss . dht_nodes ;
m_status . peersCount = ss . num_peers ;
libt : : cache_status cs = m_nativeSession - > get_cache_status ( ) ;
m_cacheStatus . totalUsedBuffers = cs . total_used_buffers ;
m_cacheStatus . readRatio = cs . blocks_read > 0
? static_cast < qreal > ( cs . blocks_read_hit ) / cs . blocks_read
: - 1 ;
m_cacheStatus . jobQueueLength = cs . job_queue_length ;
m_cacheStatus . averageJobTime = cs . average_job_time ;
2017-04-29 14:52:28 +03:00
m_cacheStatus . queuedBytes = cs . queued_bytes ; // it seems that it is constantly equal to zero
2017-04-29 14:45:30 +03:00
emit statsUpdated ( ) ;
}
2017-04-29 14:52:28 +03:00
# endif
2017-04-29 14:45:30 +03:00
2015-04-19 18:17:47 +03:00
void Session : : handleStateUpdateAlert ( libt : : state_update_alert * p )
{
2017-04-29 14:52:28 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2017-04-29 14:45:30 +03:00
updateStats ( ) ;
2017-04-29 14:52:28 +03:00
# endif
2017-04-29 14:45:30 +03:00
2015-04-19 18:17:47 +03:00
foreach ( const libt : : torrent_status & status , p - > status ) {
TorrentHandle * const torrent = m_torrents . value ( status . info_hash ) ;
2015-11-05 19:17:10 +03:00
if ( torrent )
2015-09-25 10:52:25 +03:00
torrent - > handleStateUpdate ( status ) ;
2015-04-19 18:17:47 +03:00
}
2015-11-05 19:17:10 +03:00
m_torrentStatusReport = TorrentStatusReport ( ) ;
2015-04-19 18:17:47 +03:00
foreach ( TorrentHandle * const torrent , m_torrents ) {
if ( torrent - > isDownloading ( ) )
2015-11-05 19:17:10 +03:00
+ + m_torrentStatusReport . nbDownloading ;
2015-04-19 18:17:47 +03:00
if ( torrent - > isUploading ( ) )
2015-11-05 19:17:10 +03:00
+ + m_torrentStatusReport . nbSeeding ;
2015-04-19 18:17:47 +03:00
if ( torrent - > isCompleted ( ) )
2015-11-05 19:17:10 +03:00
+ + m_torrentStatusReport . nbCompleted ;
2015-04-19 18:17:47 +03:00
if ( torrent - > isPaused ( ) )
2015-11-05 19:17:10 +03:00
+ + m_torrentStatusReport . nbPaused ;
2015-04-19 18:17:47 +03:00
if ( torrent - > isResumed ( ) )
2015-11-05 19:17:10 +03:00
+ + m_torrentStatusReport . nbResumed ;
2015-04-19 18:17:47 +03:00
if ( torrent - > isActive ( ) )
2015-11-05 19:17:10 +03:00
+ + m_torrentStatusReport . nbActive ;
2015-04-19 18:17:47 +03:00
if ( torrent - > isInactive ( ) )
2015-11-05 19:17:10 +03:00
+ + m_torrentStatusReport . nbInactive ;
2015-11-11 09:51:22 +03:00
if ( torrent - > isErrored ( ) )
+ + m_torrentStatusReport . nbErrored ;
2015-04-19 18:17:47 +03:00
}
2015-11-05 19:17:10 +03:00
emit torrentsUpdated ( ) ;
2015-04-19 18:17:47 +03:00
}
2016-02-09 11:56:48 +03:00
namespace
2015-04-19 18:17:47 +03:00
{
2016-02-09 11:56:48 +03:00
bool readFile ( const QString & path , QByteArray & buf )
{
QFile file ( path ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
2017-08-13 13:56:03 +03:00
qDebug ( " Cannot read file %s: %s " , qUtf8Printable ( path ) , qUtf8Printable ( file . errorString ( ) ) ) ;
2016-02-09 11:56:48 +03:00
return false ;
}
2015-04-19 18:17:47 +03:00
2016-02-09 11:56:48 +03:00
buf = file . readAll ( ) ;
return true ;
2016-01-01 16:28:40 +03:00
}
2016-02-09 11:56:48 +03:00
bool loadTorrentResumeData ( const QByteArray & data , AddTorrentData & torrentData , int & prio , MagnetUri & magnetUri )
{
torrentData = AddTorrentData ( ) ;
torrentData . resumed = true ;
torrentData . skipChecking = false ;
libt : : error_code ec ;
2016-06-03 17:03:17 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
libt : : lazy_entry fast ;
2016-02-09 11:56:48 +03:00
libt : : lazy_bdecode ( data . constData ( ) , data . constData ( ) + data . size ( ) , fast , ec ) ;
if ( ec | | ( fast . type ( ) ! = libt : : lazy_entry : : dict_t ) ) return false ;
2016-06-03 17:03:17 +03:00
# else
libt : : bdecode_node fast ;
libt : : bdecode ( data . constData ( ) , data . constData ( ) + data . size ( ) , fast , ec ) ;
if ( ec | | ( fast . type ( ) ! = libt : : bdecode_node : : dict_t ) ) return false ;
# endif
2016-02-09 11:56:48 +03:00
2016-05-13 21:32:47 +03:00
torrentData . savePath = Profile : : instance ( ) . fromPortablePath (
Utils : : Fs : : fromNativePath ( QString : : fromStdString ( fast . dict_find_string_value ( " qBt-savePath " ) ) ) ) ;
2017-10-08 09:59:52 +03:00
std : : string ratioLimitString = fast . dict_find_string_value ( " qBt-ratioLimit " ) ;
if ( ratioLimitString . empty ( ) )
torrentData . ratioLimit = fast . dict_find_int_value ( " qBt-ratioLimit " , TorrentHandle : : USE_GLOBAL_RATIO * 1000 ) / 1000.0 ;
else
torrentData . ratioLimit = QString : : fromStdString ( ratioLimitString ) . toDouble ( ) ;
2016-02-07 20:31:50 +03:00
torrentData . seedingTimeLimit = fast . dict_find_int_value ( " qBt-seedingTimeLimit " , TorrentHandle : : USE_GLOBAL_SEEDING_TIME ) ;
2016-02-09 11:56:48 +03:00
// **************************************************************************************
// Workaround to convert legacy label to category
// TODO: Should be removed in future
2017-03-07 14:41:38 +03:00
torrentData . category = QString : : fromStdString ( fast . dict_find_string_value ( " qBt-label " ) ) ;
2016-02-09 11:56:48 +03:00
if ( torrentData . category . isEmpty ( ) )
// **************************************************************************************
2017-03-07 14:41:38 +03:00
torrentData . category = QString : : fromStdString ( fast . dict_find_string_value ( " qBt-category " ) ) ;
2017-06-05 03:22:17 +03:00
// auto because the return type depends on the #if above.
const auto tagsEntry = fast . dict_find_list ( " qBt-tags " ) ;
if ( isList ( tagsEntry ) )
torrentData . tags = entryListToSet ( tagsEntry ) ;
2017-03-07 14:41:38 +03:00
torrentData . name = QString : : fromStdString ( fast . dict_find_string_value ( " qBt-name " ) ) ;
2016-02-09 11:56:48 +03:00
torrentData . hasSeedStatus = fast . dict_find_int_value ( " qBt-seedStatus " ) ;
torrentData . disableTempPath = fast . dict_find_int_value ( " qBt-tempPathDisabled " ) ;
2016-01-04 16:00:50 +03:00
torrentData . hasRootFolder = fast . dict_find_int_value ( " qBt-hasRootFolder " ) ;
2016-02-09 11:56:48 +03:00
2017-03-07 14:41:38 +03:00
magnetUri = MagnetUri ( QString : : fromStdString ( fast . dict_find_string_value ( " qBt-magnetUri " ) ) ) ;
2017-04-24 11:59:16 +03:00
torrentData . addPaused = fast . dict_find_int_value ( " qBt-paused " ) ;
torrentData . addForced = fast . dict_find_int_value ( " qBt-forced " ) ;
2016-07-15 05:15:10 +03:00
torrentData . firstLastPiecePriority = fast . dict_find_int_value ( " qBt-firstLastPiecePriority " ) ;
torrentData . sequential = fast . dict_find_int_value ( " qBt-sequential " ) ;
2016-02-09 11:56:48 +03:00
prio = fast . dict_find_int_value ( " qBt-queuePosition " ) ;
2015-04-19 18:17:47 +03:00
2016-02-09 11:56:48 +03:00
return true ;
2015-04-19 18:17:47 +03:00
}
2016-02-09 11:56:48 +03:00
void torrentQueuePositionUp ( const libt : : torrent_handle & handle )
{
try {
handle . queue_position_up ( ) ;
}
catch ( std : : exception & exc ) {
qDebug ( ) < < Q_FUNC_INFO < < " fails: " < < exc . what ( ) ;
}
2015-04-19 18:17:47 +03:00
}
2016-02-09 11:56:48 +03:00
void torrentQueuePositionDown ( const libt : : torrent_handle & handle )
{
try {
handle . queue_position_down ( ) ;
}
catch ( std : : exception & exc ) {
qDebug ( ) < < Q_FUNC_INFO < < " fails: " < < exc . what ( ) ;
}
2015-04-19 18:17:47 +03:00
}
2016-02-09 11:56:48 +03:00
void torrentQueuePositionTop ( const libt : : torrent_handle & handle )
{
try {
handle . queue_position_top ( ) ;
}
catch ( std : : exception & exc ) {
qDebug ( ) < < Q_FUNC_INFO < < " fails: " < < exc . what ( ) ;
}
2015-04-19 18:17:47 +03:00
}
2016-02-09 11:56:48 +03:00
void torrentQueuePositionBottom ( const libt : : torrent_handle & handle )
{
try {
handle . queue_position_bottom ( ) ;
}
catch ( std : : exception & exc ) {
qDebug ( ) < < Q_FUNC_INFO < < " fails: " < < exc . what ( ) ;
}
2015-04-19 18:17:47 +03:00
}
2017-08-13 00:58:22 +03:00
# ifdef Q_OS_WIN
QString convertIfaceNameToGuid ( const QString & name )
{
// Under Windows XP or on Qt version <= 5.5 'name' will be a GUID already.
QUuid uuid ( name ) ;
if ( ! uuid . isNull ( ) )
return uuid . toString ( ) . toUpper ( ) ; // Libtorrent expects the GUID in uppercase
using PCONVERTIFACENAMETOLUID = NETIO_STATUS ( WINAPI * ) ( const WCHAR * , PNET_LUID ) ;
PCONVERTIFACENAMETOLUID ConvertIfaceNameToLuid = reinterpret_cast < PCONVERTIFACENAMETOLUID > ( : : GetProcAddress ( : : GetModuleHandleW ( L " Iphlpapi.dll " ) , " ConvertInterfaceNameToLuidW " ) ) ;
if ( ! ConvertIfaceNameToLuid ) return QString ( ) ;
using PCONVERTIFACELUIDTOGUID = NETIO_STATUS ( WINAPI * ) ( const NET_LUID * , GUID * ) ;
PCONVERTIFACELUIDTOGUID ConvertIfaceLuidToGuid = reinterpret_cast < PCONVERTIFACELUIDTOGUID > ( : : GetProcAddress ( : : GetModuleHandleW ( L " Iphlpapi.dll " ) , " ConvertInterfaceLuidToGuid " ) ) ;
if ( ! ConvertIfaceLuidToGuid ) return QString ( ) ;
NET_LUID luid ;
LONG res = ConvertIfaceNameToLuid ( name . toStdWString ( ) . c_str ( ) , & luid ) ;
if ( res = = 0 ) {
GUID guid ;
if ( ConvertIfaceLuidToGuid ( & luid , & guid ) = = 0 )
return QUuid ( guid ) . toString ( ) . toUpper ( ) ;
}
return QString ( ) ;
}
# endif
2015-04-19 18:17:47 +03:00
}