2015-06-30 21:03:17 +03:00
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"
# include <QCoreApplication>
# include <QDateTime>
2015-04-19 18:17:47 +03:00
# include <QDebug>
# include <QDir>
2016-04-19 09:54:48 +03:00
# include <QDirIterator>
2015-04-19 18:17:47 +03:00
# 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>
2015-04-19 18:17:47 +03:00
2016-05-01 11:05:52 +03:00
# include <cstdlib>
2015-04-19 18:17:47 +03:00
# include <queue>
# include <vector>
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>
# include <libtorrent/error_code.hpp>
# include <libtorrent/extensions/ut_metadata.hpp>
# include <libtorrent/extensions/lt_trackers.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>
# 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"
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/misc.h"
# include "base/utils/fs.h"
2015-09-25 11:10:05 +03:00
# include "base/utils/string.h"
2016-04-19 09:54:48 +03:00
# include "cachestatus.h"
# include "magneturi.h"
2015-04-19 18:17:47 +03:00
# include "private/filterparserthread.h"
# include "private/statistics.h"
# include "private/bandwidthscheduler.h"
2015-12-13 15:38:19 +03:00
# include "private/resumedatasavingmanager.h"
2015-04-19 18:17:47 +03:00
# include "sessionstatus.h"
# 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
2016-10-30 00:11:52 +03:00
static const char PEER_ID [ ] = " qB " ;
static const char RESUME_FOLDER [ ] = " BT_backup " ;
static const char USER_AGENT [ ] = " qBittorrent " VERSION ;
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 ) ;
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 ;
}
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-03-06 09:25:55 +03:00
QString normalizeSavePath ( QString path , const QString & defaultPath = Utils : : Fs : : QDesktopServicesDownloadLocation ( ) )
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
QStringList findAllFiles ( const QString & dirPath )
{
QStringList files ;
QDirIterator it ( dirPath , QDir : : Files , QDirIterator : : Subdirectories ) ;
while ( it . hasNext ( ) )
files < < it . next ( ) ;
return files ;
}
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 )
{
}
T operator ( ) ( T val )
{
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 ) ; }
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 )
, m_isTrackerExchangeEnabled ( BITTORRENT_SESSION_KEY ( " TrackerExchangeEnabled " ) , false )
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 " ) )
, m_announceToAllTrackers ( BITTORRENT_SESSION_KEY ( " AnnounceToAllTrackers " ) , true )
, m_diskCacheSize ( BITTORRENT_SESSION_KEY ( " DiskCacheSize " ) , 0 )
, m_diskCacheTTL ( BITTORRENT_SESSION_KEY ( " DiskCacheTTL " ) , 60 )
, m_useOSCache ( BITTORRENT_SESSION_KEY ( " UseOSCache " ) , true )
, 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 ) )
, m_isUTPEnabled ( BITTORRENT_SESSION_KEY ( " uTPEnabled " ) , true )
, m_isUTPRateLimited ( BITTORRENT_SESSION_KEY ( " uTPRateLimited " ) , true )
, 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 ; } )
, m_isAddTorrentPaused ( BITTORRENT_SESSION_KEY ( " AddTorrentPaused " ) , false )
, 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 )
, m_storedCategories ( BITTORRENT_SESSION_KEY ( " Categories " ) )
, m_maxRatioAction ( BITTORRENT_SESSION_KEY ( " MaxRatioAction " ) , Pause )
, m_defaultSavePath ( BITTORRENT_SESSION_KEY ( " DefaultSavePath " ) , Utils : : Fs : : QDesktopServicesDownloadLocation ( ) , normalizePath )
, 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 )
, m_bannedIPs ( " State/BannedIPs " )
2016-10-31 03:06:29 +03:00
, m_wasPexEnabled ( m_isPeXEnabled )
2016-11-01 23:24:55 +03:00
, m_wasTrackerExchangeEnabled ( m_isTrackerExchangeEnabled )
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 ( ) ;
m_bigRatioTimer = new QTimer ( this ) ;
m_bigRatioTimer - > setInterval ( 10000 ) ;
connect ( m_bigRatioTimer , SIGNAL ( timeout ( ) ) , SLOT ( processBigRatios ( ) ) ) ;
2015-11-10 01:22:18 +03:00
// Set severity level of libtorrent session
int alertMask = libt : : alert : : error_notification
| 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
| 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
2016-06-03 17:03:17 +03:00
libt : : fingerprint fingerprint ( PEER_ID , VERSION_MAJOR , VERSION_MINOR , VERSION_BUGFIX , VERSION_BUILD ) ;
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 ;
sessionSettings . seed_choking_algorithm = libt : : session_settings : : fastest_upload ;
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 )
{
dispatchAlerts ( alertPtr ) ;
} ) ;
# else
2016-10-31 03:31:56 +03:00
std : : string peerId = libt : : generate_fingerprint ( PEER_ID , VERSION_MAJOR , VERSION_MINOR , VERSION_BUGFIX , 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 : : upnp_ignore_nonrouters , true ) ;
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 ) ;
pack . set_int ( libt : : settings_pack : : seed_choking_algorithm , libt : : settings_pack : : fastest_upload ) ;
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 ) ;
} ) ;
# 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-05-01 11:05:52 +03:00
if ( isTrackerExchangeEnabled ( ) )
2015-04-19 18:17:47 +03:00
m_nativeSession - > add_extension ( & libt : : create_lt_trackers_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 ) ;
2016-06-03 17:03:17 +03:00
logger - > addMessage ( tr ( " Peer ID: " ) + Utils : : String : : fromStdString ( peerId ) ) ;
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 ) ;
2016-10-29 19:14:27 +03:00
if ( isIPFilteringEnabled ( ) )
2016-06-03 17:03:17 +03:00
enableIPFilter ( ) ;
// Add the banned IPs
processBannedIPs ( ) ;
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
}
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 ( ) ) ;
2015-04-19 18:17:47 +03:00
connect ( m_refreshTimer , SIGNAL ( timeout ( ) ) , SLOT ( refresh ( ) ) ) ;
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 ) ;
2015-04-19 18:17:47 +03:00
connect ( m_resumeDataTimer , SIGNAL ( timeout ( ) ) , SLOT ( generateResumeData ( ) ) ) ;
m_statistics = new Statistics ( this ) ;
2016-05-01 11:05:52 +03:00
updateRatioTimer ( ) ;
populateAdditionalTrackers ( ) ;
enableTracker ( isTrackerEnabled ( ) ) ;
connect ( Net : : ProxyConfigurationManager : : instance ( ) , SIGNAL ( proxyConfigurationChanged ( ) ) , SLOT ( configureDeferred ( ) ) ) ;
2016-02-09 11:56:48 +03:00
2016-05-01 11:05:52 +03:00
if ( isBandwidthSchedulerEnabled ( ) )
enableBandwidthScheduler ( ) ;
2015-04-19 18:17:47 +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 ) ;
connect ( m_ioThread , SIGNAL ( finished ( ) ) , m_resumeDataSavingManager , SLOT ( deleteLater ( ) ) ) ;
m_ioThread - > start ( ) ;
2015-04-19 18:17:47 +03:00
m_resumeDataTimer - > start ( ) ;
// initialize PortForwarder instance
Net : : PortForwarder : : initInstance ( m_nativeSession ) ;
qDebug ( " * BitTorrent Session constructed " ) ;
startUpTorrents ( ) ;
}
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
}
2016-05-01 11:05:52 +03:00
bool Session : : isTrackerExchangeEnabled ( ) const
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
return m_isTrackerExchangeEnabled ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setTrackerExchangeEnabled ( bool enabled )
2015-04-19 18:17:47 +03:00
{
2016-10-31 03:06:29 +03:00
m_isTrackerExchangeEnabled = enabled ;
if ( m_wasTrackerExchangeEnabled ! = enabled )
2016-05-01 11:05:52 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " Restart is required to toggle Tracker Exchange 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
}
2016-04-23 19:34:01 +03:00
QString Session : : torrentTempPath ( const InfoHash & hash ) const
{
2016-05-01 11:05:52 +03:00
return tempPath ( )
2016-04-23 21:01:56 +03:00
+ static_cast < QString > ( hash ) . left ( 7 )
+ " / " ;
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 ;
}
QStringList Session : : categories ( ) const
{
return m_categories . keys ( ) ;
}
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 ;
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 ( ) ;
}
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 ;
updateRatioTimer ( ) ;
}
}
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 ( )
{
if ( ! m_instance )
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
2016-06-03 17:03:17 +03:00
// Set BitTorrent session configuration
void Session : : configure ( )
{
qDebug ( " Configuring session " ) ;
2016-10-30 00:43:53 +03:00
if ( ! m_deferredConfigureScheduled ) return ; // Obtaining the lock is expensive, let's check early
QWriteLocker locker ( & m_lock ) ;
if ( ! m_deferredConfigureScheduled ) return ; // something might have changed while we were getting the lock
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 ) ;
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
}
2016-06-03 17:03:17 +03:00
void Session : : processBannedIPs ( )
2015-04-19 18:17:47 +03:00
{
2016-06-03 17:03:17 +03:00
// First, import current filter
libt : : ip_filter filter = m_nativeSession - > get_ip_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
m_nativeSession - > set_ip_filter ( filter ) ;
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
}
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
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 ) ;
break ;
}
}
2015-04-19 18:17:47 +03:00
2016-06-03 17:03:17 +03:00
m_listenInterfaceChanged = false ;
2015-04-19 18:17:47 +03:00
}
2016-06-03 17:03:17 +03:00
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 ( ) ) ;
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 ) {
settingsPack . set_str ( libt : : settings_pack : : proxy_hostname , Utils : : String : : toStdString ( proxyConfig . ip ) ) ;
settingsPack . set_int ( libt : : settings_pack : : proxy_port , proxyConfig . port ) ;
if ( proxyManager - > isAuthenticationRequired ( ) ) {
settingsPack . set_str ( libt : : settings_pack : : proxy_username , Utils : : String : : toStdString ( proxyConfig . username ) ) ;
settingsPack . set_str ( libt : : settings_pack : : proxy_password , Utils : : String : : toStdString ( proxyConfig . password ) ) ;
}
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
2016-06-03 17:03:17 +03:00
const bool announceToAll = announceToAllTrackers ( ) ;
settingsPack . set_bool ( libt : : settings_pack : : announce_to_all_trackers , announceToAll ) ;
settingsPack . set_bool ( libt : : settings_pack : : announce_to_all_tiers , announceToAll ) ;
2015-04-19 18:17:47 +03:00
2016-06-03 17:03:17 +03:00
const int cacheSize = diskCacheSize ( ) ;
settingsPack . set_int ( libt : : settings_pack : : cache_size , ( cacheSize > 0 ) ? cacheSize * 64 : - 1 ) ;
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 ) ;
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 ) ;
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 ) ;
// Ignore limits on LAN
settingsPack . set_bool ( libt : : settings_pack : : ignore_limits_on_local_network , ignoreLimitsOnLAN ( ) ) ;
// Include overhead in transfer limits
settingsPack . set_bool ( libt : : settings_pack : : rate_limit_ip_overhead , includeOverheadInLimits ( ) ) ;
// IP address to announce to trackers
2016-10-31 02:22:11 +03:00
settingsPack . set_str ( libt : : settings_pack : : announce_ip , Utils : : String : : toStdString ( announceIP ( ) ) ) ;
2016-06-03 17:03:17 +03:00
// Super seeding
settingsPack . set_bool ( libt : : settings_pack : : strict_super_seeding , isSuperSeedingEnabled ( ) ) ;
// * Max Half-open connections
settingsPack . set_int ( libt : : settings_pack : : half_open_limit , maxHalfOpenConnections ( ) ) ;
// * 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
settingsPack . set_bool ( libt : : settings_pack : : enable_incoming_utp , isUTPEnabled ( ) ) ;
settingsPack . set_bool ( libt : : settings_pack : : enable_outgoing_utp , isUTPEnabled ( ) ) ;
// uTP rate limiting
settingsPack . set_bool ( libt : : settings_pack : : rate_limit_utp , isUTPRateLimited ( ) ) ;
settingsPack . set_int ( libt : : settings_pack : : mixed_mode_algorithm , isUTPRateLimited ( )
? libt : : settings_pack : : prefer_tcp
: libt : : settings_pack : : peer_proportional ) ;
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 ( ) ) ;
2016-05-01 11:05:52 +03:00
}
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
}
2016-06-03 17:03:17 +03:00
void Session : : configure ( libtorrent : : 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 ( ) ;
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 ) {
proxySettings . hostname = Utils : : String : : toStdString ( proxyConfig . ip ) ;
proxySettings . port = proxyConfig . port ;
if ( proxyManager - > isAuthenticationRequired ( ) ) {
proxySettings . username = Utils : : String : : toStdString ( proxyConfig . username ) ;
proxySettings . password = Utils : : String : : toStdString ( proxyConfig . password ) ;
}
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
2016-05-01 11:05:52 +03:00
bool announceToAll = announceToAllTrackers ( ) ;
sessionSettings . announce_to_all_trackers = announceToAll ;
sessionSettings . announce_to_all_tiers = announceToAll ;
int cacheSize = diskCacheSize ( ) ;
2016-10-30 00:11:52 +03:00
sessionSettings . cache_size = ( cacheSize > 0 ) ? cacheSize * 64 : - 1 ;
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 ;
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 ;
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
2016-10-31 02:22:11 +03:00
sessionSettings . announce_ip = Utils : : String : : toStdString ( announceIP ( ) ) ;
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
2016-05-01 11:05:52 +03:00
sessionSettings . enable_incoming_utp = isUTPEnabled ( ) ;
sessionSettings . enable_outgoing_utp = isUTPEnabled ( ) ;
2015-04-19 18:17:47 +03:00
// uTP rate limiting
2016-05-01 11:05:52 +03:00
sessionSettings . rate_limit_utp = isUTPRateLimited ( ) ;
2016-10-30 00:11:52 +03:00
sessionSettings . mixed_mode_algorithm = isUTPRateLimited ( )
? libt : : session_settings : : prefer_tcp
: libt : : session_settings : : peer_proportional ;
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 ( ) ;
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 {
logger - > addMessage ( tr ( " Embedded Tracker [OFF] " ) ) ;
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 ) ;
connect ( m_bwScheduler . data ( ) , SIGNAL ( switchToAlternativeMode ( bool ) ) , this , SLOT ( switchToAlternativeMode ( bool ) ) ) ;
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
}
}
void Session : : processBigRatios ( )
{
qDebug ( " Process big ratios... " ) ;
2016-05-01 11:05:52 +03:00
qreal globalMaxRatio = this - > globalMaxRatio ( ) ;
2015-04-19 18:17:47 +03:00
foreach ( TorrentHandle * const torrent , m_torrents ) {
2016-11-02 19:25:09 +03:00
if ( torrent - > isSeed ( )
& & ( ( torrent - > ratioLimit ( ) ! = TorrentHandle : : NO_RATIO_LIMIT ) | | ! torrent - > isForced ( ) ) ) {
2015-04-19 18:17:47 +03:00
const qreal ratio = torrent - > realRatio ( ) ;
qreal ratioLimit = torrent - > ratioLimit ( ) ;
2015-06-17 12:23:16 +03:00
if ( ratioLimit = = TorrentHandle : : USE_GLOBAL_RATIO ) {
// If Global Max Ratio is really set...
2016-05-01 11:05:52 +03:00
ratioLimit = globalMaxRatio ;
if ( ratioLimit < 0 ) continue ;
2015-06-17 12:23:16 +03:00
}
2015-04-19 18:17:47 +03:00
qDebug ( " Ratio: %f (limit: %f) " , ratio , ratioLimit ) ;
Q_ASSERT ( ratioLimit > = 0.f ) ;
if ( ( ratio < = TorrentHandle : : MAX_RATIO ) & & ( ratio > = ratioLimit ) ) {
Logger * const logger = Logger : : instance ( ) ;
2016-05-01 11:05:52 +03:00
if ( maxRatioAction ( ) = = Remove ) {
2015-08-08 16:19:46 +03:00
logger - > addMessage ( tr ( " '%1' reached the maximum ratio you set. Removing... " ) . arg ( torrent - > name ( ) ) ) ;
2015-04-19 18:17:47 +03:00
deleteTorrent ( torrent - > hash ( ) ) ;
}
else {
// Pause it
if ( ! torrent - > isPaused ( ) ) {
2015-08-08 16:19:46 +03:00
logger - > addMessage ( tr ( " '%1' reached the maximum ratio you set. Pausing... " ) . arg ( torrent - > name ( ) ) ) ;
2015-04-19 18:17:47 +03:00
torrent - > pause ( ) ;
}
}
}
}
}
}
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
}
2015-07-22 08:51:23 +03:00
void Session : : switchToAlternativeMode ( bool alternative )
{
changeSpeedLimitMode_impl ( alternative ) ;
}
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 ;
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 ;
qDebug ( " Deleting torrent with hash: %s " , qPrintable ( torrent - > hash ( ) ) ) ;
emit torrentAboutToBeRemoved ( torrent ) ;
// Remove it from session
if ( deleteLocalFiles ) {
2015-10-24 15:28:29 +03:00
m_savePathsToRemove [ torrent - > hash ( ) ] = torrent - > rootPath ( true ) ;
2015-04-19 18:17:47 +03:00
m_nativeSession - > remove_torrent ( torrent - > nativeHandle ( ) , libt : : session : : delete_files ) ;
}
else {
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 ) {
qDebug ( " Removing unwanted file: %s " , qPrintable ( unwantedFile ) ) ;
2015-05-06 14:53:27 +03:00
Utils : : Fs : : forceRemove ( unwantedFile ) ;
const QString parentFolder = Utils : : Fs : : branchPath ( unwantedFile ) ;
2015-04-19 18:17:47 +03:00
qDebug ( " Attempt to remove parent folder (if empty): %s " , qPrintable ( parentFolder ) ) ;
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
if ( deleteLocalFiles )
Logger : : instance ( ) - > addMessage ( tr ( " '%1' was removed from transfer list and hard disk. " , " 'xxx.avi' was removed... " ) . arg ( torrent - > name ( ) ) ) ;
else
Logger : : instance ( ) - > addMessage ( tr ( " '%1' was removed from transfer list. " , " 'xxx.avi' was removed... " ) . arg ( torrent - > name ( ) ) ) ;
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 ) ;
guard . markAsAddedToSession ( ) ;
2016-01-01 16:28:40 +03:00
return addTorrent_impl ( params , MagnetUri ( ) , TorrentInfo : : loadFromFile ( source ) ) ;
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
{
2016-03-06 09:25:55 +03:00
addData . savePath = normalizeSavePath (
addData . savePath ,
2016-05-01 11:05:52 +03:00
( ( ! addData . resumed & & isAutoTMMDisabledByDefault ( ) ) ? defaultSavePath ( ) : " " ) ) ;
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 < char > buf ( fastresumeData . constData ( ) , fastresumeData . constData ( ) + fastresumeData . size ( ) ) ;
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 ( ) ) {
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
p . resume_data = buf ;
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... " ) ;
qDebug ( " -> Hash: %s " , qPrintable ( hash ) ) ;
// 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 ( ) ;
2015-05-06 14:53:27 +03:00
p . save_path = Utils : : String : : toStdString ( Utils : : Fs : : toNativePath ( savePath ) ) ;
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
{
bool found = false ;
if ( torrentInfo . filesCount ( ) = = 1 ) {
const QString filePath = dirPath + torrentInfo . filePath ( 0 ) ;
if ( QFile ( filePath ) . exists ( ) ) {
found = true ;
}
else if ( QFile ( filePath + QB_EXT ) . exists ( ) ) {
found = true ;
torrentInfo . renameFile ( 0 , torrentInfo . filePath ( 0 ) + QB_EXT ) ;
}
}
else {
QSet < QString > allFiles ;
int dirPathSize = dirPath . size ( ) ;
foreach ( const QString & file , findAllFiles ( dirPath + torrentInfo . name ( ) ) )
allFiles < < file . mid ( dirPathSize ) ;
for ( int i = 0 ; i < torrentInfo . filesCount ( ) ; + + i ) {
QString filePath = torrentInfo . filePath ( i ) ;
if ( allFiles . contains ( filePath ) ) {
found = true ;
}
else {
filePath + = QB_EXT ;
if ( allFiles . contains ( filePath ) ) {
found = true ;
torrentInfo . renameFile ( i , filePath ) ;
}
}
}
}
return found ;
} ;
bool found = findInDir ( savePath , torrentInfo ) ;
if ( ! found & & isTempPathEnabled ( ) ) {
2016-04-23 19:34:01 +03:00
savePath = torrentTempPath ( torrentInfo . hash ( ) ) ;
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... " ) ;
qDebug ( " -> Hash: %s " , qPrintable ( hash ) ) ;
qDebug ( " -> Name: %s " , qPrintable ( name ) ) ;
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 ) ;
2015-05-06 14:53:27 +03:00
p . save_path = Utils : : String : : toStdString ( Utils : : Fs : : toNativePath ( savePath ) ) ;
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
}
}
2015-07-22 08:51:23 +03:00
void Session : : changeSpeedLimitMode_impl ( bool alternative )
{
qDebug ( ) < < Q_FUNC_INFO < < alternative ;
2016-05-01 11:05:52 +03:00
if ( alternative = = isAltGlobalSpeedLimitEnabled ( ) ) return ;
2015-07-22 08:51:23 +03:00
// Save new state to remember it on startup
2016-05-01 11:05:52 +03:00
m_isAltGlobalSpeedLimitEnabled = alternative ;
configureDeferred ( ) ;
2015-07-22 08:51:23 +03:00
// Notify
emit speedLimitModeChanged ( alternative ) ;
}
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 ;
saveTorrentResumeData ( torrent ) ;
qDebug ( " Saving fastresume data for %s " , qPrintable ( torrent - > name ( ) ) ) ;
}
}
// 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 :
2015-09-25 10:52:25 +03:00
TorrentHandle * torrent = m_torrents . take ( static_cast < libt : : torrent_alert * > ( a ) - > handle . info_hash ( ) ) ;
2015-04-19 18:17:47 +03:00
if ( torrent )
torrent - > handleAlert ( a ) ;
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 ( ) ;
2015-11-29 15:30:42 +03:00
if ( configuredInterfaceName = = changedInterface ) {
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 ( ) ) {
qDebug ( " Invalid network interface: %s " , qPrintable ( ifaceName ) ) ;
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
{
2016-05-01 11:05:52 +03:00
// Stop the scheduler when the user has manually changed the bandwidth mode
if ( isBandwidthSchedulerEnabled ( ) )
setBandwidthSchedulerEnabled ( false ) ;
changeSpeedLimitMode_impl ( enabled ) ;
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
{
2016-05-01 11:05:52 +03:00
static int randomPort = rand ( ) % 64512 + 1024 ;
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
}
2016-05-01 11:05:52 +03:00
void Session : : setNetworkInterface ( const QString & interface )
2015-04-19 18:17:47 +03:00
{
2016-05-01 11:05:52 +03:00
if ( interface ! = networkInterface ( ) ) {
m_networkInterface = interface ;
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 ( ) ;
}
}
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 ( ) ;
}
}
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 ) ;
}
catch ( std : : exception ) { }
}
}
}
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 ) ;
}
catch ( std : : exception ) { }
}
}
}
bool Session : : announceToAllTrackers ( ) const
{
return m_announceToAllTrackers ;
}
void Session : : setAnnounceToAllTrackers ( bool val )
{
if ( val ! = m_announceToAllTrackers ) {
m_announceToAllTrackers = val ;
configureDeferred ( ) ;
}
}
uint Session : : diskCacheSize ( ) const
{
uint size = m_diskCacheSize ;
// These macros may not be available on compilers other than MSVC and GCC
# if defined(__x86_64__) || defined(_M_X64)
size = qMin ( size , 4096u ) ; // 4GiB
# 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
size = qMin ( size , 1536u ) ;
# endif
return size ;
}
void Session : : setDiskCacheSize ( uint size )
{
# if defined(__x86_64__) || defined(_M_X64)
size = qMin ( size , 4096u ) ; // 4GiB
# else
// allocate 1536MiB and leave 512MiB to the rest of program data in RAM
size = qMin ( size , 1536u ) ;
# endif
if ( size ! = m_diskCacheSize ) {
m_diskCacheSize = size ;
configureDeferred ( ) ;
}
}
uint Session : : diskCacheTTL ( ) const
{
return m_diskCacheTTL ;
}
void Session : : setDiskCacheTTL ( uint ttl )
{
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 ( ) ;
}
}
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
}
}
2016-05-01 11:05:52 +03:00
uint 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
}
2016-05-01 11:05:52 +03:00
void Session : : setOutgoingPortsMin ( uint 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
2016-05-01 11:05:52 +03:00
uint Session : : outgoingPortsMax ( ) const
{
return m_outgoingPortsMax ;
2015-04-19 18:17:47 +03:00
}
2016-05-01 11:05:52 +03:00
void Session : : setOutgoingPortsMax ( uint 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
2016-05-01 11:05:52 +03:00
bool Session : : isUTPEnabled ( ) const
{
return m_isUTPEnabled ;
}
2015-11-07 03:06:07 +03:00
2016-05-01 11:05:52 +03:00
void Session : : setUTPEnabled ( bool enabled )
{
if ( enabled ! = m_isUTPEnabled ) {
m_isUTPEnabled = enabled ;
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
}
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 ) ) ;
}
void Session : : updateRatioTimer ( )
{
2016-05-01 11:05:52 +03:00
if ( ( globalMaxRatio ( ) = = - 1 ) & & ! hasPerTorrentRatioLimit ( ) ) {
2015-04-19 18:17:47 +03:00
if ( m_bigRatioTimer - > isActive ( ) )
m_bigRatioTimer - > stop ( ) ;
}
else if ( ! m_bigRatioTimer - > isActive ( ) ) {
m_bigRatioTimer - > start ( ) ;
}
}
void Session : : handleTorrentRatioLimitChanged ( TorrentHandle * const torrent )
{
Q_UNUSED ( torrent ) ;
updateRatioTimer ( ) ;
}
void Session : : saveTorrentResumeData ( TorrentHandle * const torrent )
{
torrent - > saveResumeData ( ) ;
+ + 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
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 ;
2015-04-19 18:17:47 +03:00
qDebug ( " Full subtorrent path is %s " , qPrintable ( torrentFullpath ) ) ;
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 ;
}
void Session : : initResumeFolder ( )
{
2015-05-06 14:53:27 +03:00
m_resumeFolderPath = Utils : : Fs : : expandPathAbs ( Utils : : Fs : : QDesktopServicesDataLocation ( ) + 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 ( )
{
2016-10-30 00:43:53 +03:00
if ( m_deferredConfigureScheduled ) return ; // Obtaining the lock is expensive, let's check early
QWriteLocker locker ( & m_lock ) ;
if ( m_deferredConfigureScheduled ) return ; // something might have changed while we were getting the lock
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
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 " ) ;
2015-04-19 18:17:47 +03:00
if ( ! m_filterParser ) {
m_filterParser = new FilterParserThread ( m_nativeSession , this ) ;
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 " ) ;
m_nativeSession - > set_ip_filter ( libt : : ip_filter ( ) ) ;
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.
processBannedIPs ( ) ;
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 ) ;
}
}
}
SessionStatus Session : : status ( ) const
{
return m_nativeSession - > status ( ) ;
}
CacheStatus Session : : cacheStatus ( ) const
{
return m_nativeSession - > get_cache_status ( ) ;
}
// 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 ;
2015-12-17 16:47:34 +03:00
auto startupTorrent = [ this , logger , resumeDataDir ] ( const TorrentResumeData & params )
{
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 ) ;
} ;
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 ;
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 {
queuedResumeData [ queuePosition ] = { hash , magnetUri , resumeData , data } ;
}
2015-04-19 18:17:47 +03:00
}
}
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 ( ) ;
}
void Session : : handleIPFilterParsed ( int ruleCount )
{
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 ( )
{
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
2015-04-19 18:17:47 +03:00
void Session : : dispatchAlerts ( std : : auto_ptr < libt : : alert > alertPtr )
{
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-04-28 10:56:58 +03:00
m_alerts . push_back ( alertPtr . release ( ) ) ;
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
}
// 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 ;
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 ) {
2015-10-17 17:41:53 +03:00
qWarning ( ) < < " Caught exception in " < < Q_FUNC_INFO < < " : " < < Utils : : String : : 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 ) {
2015-06-04 11:03:19 +03:00
if ( fromMagnetUri & & ! data . addPaused )
torrent - > resume ( data . addForced ) ;
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
bool addPaused = data . addPaused ;
if ( data . addPaused = = TriStateBool : : Undefined )
2016-02-09 11:56:48 +03:00
addPaused = isAddTorrentPaused ( ) ;
2015-04-19 18:17:47 +03:00
// Start torrent because it was added in paused state
if ( ! addPaused )
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
}
2015-06-17 12:23:16 +03:00
if ( ( torrent - > ratioLimit ( ) > = 0 ) & & ! m_bigRatioTimer - > isActive ( ) )
m_bigRatioTimer - > 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! " ) ;
QString msg = Utils : : String : : fromStdString ( p - > message ( ) ) ;
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 ) ) ;
}
void Session : : handleTorrentDeletedAlert ( libt : : torrent_deleted_alert * p )
{
2015-08-09 10:27:56 +03:00
m_savePathsToRemove . remove ( p - > info_hash ) ;
}
void Session : : handleTorrentDeleteFailedAlert ( libt : : torrent_delete_failed_alert * p )
{
// libtorrent won't delete the directory if it contains files not listed in the torrent,
// so we remove the directory ourselves
2015-04-19 18:17:47 +03:00
if ( m_savePathsToRemove . contains ( p - > info_hash ) ) {
2015-08-09 10:27:56 +03:00
QString path = m_savePathsToRemove . take ( p - > info_hash ) ;
Utils : : Fs : : smartRemoveEmptyFolderTree ( path ) ;
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 ) {
2015-05-06 14:53:27 +03:00
QString msg = Utils : : String : : 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 )
{
2015-05-06 14:53:27 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " UPnP/NAT-PMP: Port mapping failure, message: %1 " ) . arg ( Utils : : String : : 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 ( ) ) ;
2015-05-06 14:53:27 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " UPnP/NAT-PMP: Port mapping successful, message: %1 " ) . arg ( Utils : : String : : 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 )
{
2015-08-08 16:19:46 +03:00
Logger : : instance ( ) - > addMessage ( tr ( " URL seed lookup failed for URL: '%1', message: %2 " ) . arg ( Utils : : String : : fromStdString ( p - > url ) ) . arg ( Utils : : String : : 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 ) ;
}
void Session : : handleStateUpdateAlert ( libt : : state_update_alert * p )
{
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 ) ) {
qDebug ( " Cannot read file %s: %s " , qPrintable ( path ) , qPrintable ( file . errorString ( ) ) ) ;
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
torrentData . savePath = Utils : : Fs : : fromNativePath ( Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-savePath " ) ) ) ;
torrentData . ratioLimit = Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-ratioLimit " ) ) . toDouble ( ) ;
// **************************************************************************************
// Workaround to convert legacy label to category
// TODO: Should be removed in future
torrentData . category = Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-label " ) ) ;
if ( torrentData . category . isEmpty ( ) )
// **************************************************************************************
torrentData . category = Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-category " ) ) ;
torrentData . name = Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-name " ) ) ;
torrentData . hasSeedStatus = fast . dict_find_int_value ( " qBt-seedStatus " ) ;
torrentData . disableTempPath = fast . dict_find_int_value ( " qBt-tempPathDisabled " ) ;
magnetUri = MagnetUri ( Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-magnetUri " ) ) ) ;
torrentData . addPaused = fast . dict_find_int_value ( " qBt-paused " ) ;
torrentData . addForced = fast . dict_find_int_value ( " qBt-forced " ) ;
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
}
}