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 .
*/
# include "session.h"
using namespace BitTorrent ;
# include <QDebug>
# include <QDir>
# include <QDateTime>
# include <QString>
# include <QStringList>
# include <QNetworkInterface>
# include <QHostAddress>
# include <QNetworkAddressEntry>
# include <QTimer>
# include <QProcess>
# include <QCoreApplication>
2015-12-13 15:38:19 +03:00
# include <QThread>
2015-04-19 18:17:47 +03:00
# include <queue>
# include <vector>
2016-01-20 09:57:02 +03:00
# include <boost/bind.hpp>
2015-04-19 18:17:47 +03:00
# include <libtorrent/session.hpp>
# include <libtorrent/lazy_entry.hpp>
# include <libtorrent/bencode.hpp>
# include <libtorrent/error_code.hpp>
# include <libtorrent/identify_client.hpp>
# include <libtorrent/alert_types.hpp>
# include <libtorrent/torrent_info.hpp>
# include <libtorrent/ip_filter.hpp>
# include <libtorrent/magnet_uri.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>
//#include <libtorrent/extensions/metadata_transfer.hpp>
2015-09-25 11:10:05 +03:00
# include "base/utils/misc.h"
# include "base/utils/fs.h"
# include "base/utils/string.h"
# include "base/unicodestrings.h"
# include "base/logger.h"
# include "base/preferences.h"
# include "base/torrentfilter.h"
# include "base/net/downloadmanager.h"
# include "base/net/downloadhandler.h"
# include "base/net/portforwarder.h"
# include "base/utils/string.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 "trackerentry.h"
# include "tracker.h"
# include "magneturi.h"
# include "cachestatus.h"
# include "sessionstatus.h"
# include "torrenthandle.h"
# include "session.h"
static const char PEER_ID [ ] = " qB " ;
2015-06-18 10:08:07 +03:00
static const char RESUME_FOLDER [ ] = " BT_backup " ;
2015-04-19 18:17:47 +03:00
namespace libt = libtorrent ;
using namespace BitTorrent ;
static bool readFile ( const QString & path , QByteArray & buf ) ;
2015-12-16 17:08:27 +03:00
static bool loadTorrentResumeData ( const QByteArray & data , AddTorrentData & out , int & prio , MagnetUri & magnetUri ) ;
2015-04-19 18:17:47 +03:00
static void torrentQueuePositionUp ( const libt : : torrent_handle & handle ) ;
static void torrentQueuePositionDown ( const libt : : torrent_handle & handle ) ;
static void torrentQueuePositionTop ( const libt : : torrent_handle & handle ) ;
static void torrentQueuePositionBottom ( const libt : : torrent_handle & handle ) ;
// Session
Session * Session : : m_instance = 0 ;
Session : : Session ( QObject * parent )
: QObject ( parent )
, m_LSDEnabled ( false )
, m_DHTEnabled ( false )
, m_PeXEnabled ( false )
, m_queueingEnabled ( false )
, m_torrentExportEnabled ( false )
, m_finishedTorrentExportEnabled ( false )
, m_preAllocateAll ( false )
, m_globalMaxRatio ( - 1 )
, m_numResumeData ( 0 )
, m_extraLimit ( 0 )
, m_appendLabelToSavePath ( false )
, m_appendExtension ( false )
, m_refreshInterval ( 0 )
, m_highRatioAction ( MaxRatioAction : : Pause )
{
Preferences * const pref = Preferences : : instance ( ) ;
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 ( ) ) ) ;
// Creating BitTorrent session
// Construct session
libt : : fingerprint fingerprint ( PEER_ID , VERSION_MAJOR , VERSION_MINOR , VERSION_BUGFIX , VERSION_BUILD ) ;
2015-11-07 03:06:07 +03:00
const unsigned short port = pref - > getSessionPort ( ) ;
std : : pair < int , int > ports ( port , port ) ;
const QString ip = getListeningIPs ( ) . first ( ) ;
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
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 ) ;
2015-11-10 01:22:18 +03:00
m_nativeSession = new libt : : session ( fingerprint , ports , 0 , 0 , alertMask ) ;
2015-11-07 03:06:07 +03:00
}
else {
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-11-10 01:22:18 +03:00
m_nativeSession = new libt : : session ( fingerprint , ports , ip . toLatin1 ( ) . constData ( ) , 0 , alertMask ) ;
2015-11-07 03:06:07 +03:00
}
logger - > addMessage ( tr ( " Peer ID: " ) + Utils : : String : : fromStdString ( fingerprint . to_string ( ) ) ) ;
2015-04-19 18:17:47 +03:00
m_nativeSession - > set_alert_dispatch ( boost : : bind ( & Session : : dispatchAlerts , this , _1 ) ) ;
// Enabling plugins
//m_nativeSession->add_extension(&libt::create_metadata_plugin);
m_nativeSession - > add_extension ( & libt : : create_ut_metadata_plugin ) ;
if ( pref - > trackerExchangeEnabled ( ) )
m_nativeSession - > add_extension ( & libt : : create_lt_trackers_plugin ) ;
m_PeXEnabled = pref - > isPeXEnabled ( ) ;
if ( m_PeXEnabled )
m_nativeSession - > add_extension ( & libt : : create_ut_pex_plugin ) ;
m_nativeSession - > add_extension ( & libt : : create_smart_ban_plugin ) ;
m_refreshTimer = new QTimer ( this ) ;
m_refreshTimer - > setInterval ( 2000 ) ;
connect ( m_refreshTimer , SIGNAL ( timeout ( ) ) , SLOT ( refresh ( ) ) ) ;
m_refreshTimer - > start ( ) ;
// Regular saving of fastresume data
m_resumeDataTimer = new QTimer ( this ) ;
connect ( m_resumeDataTimer , SIGNAL ( timeout ( ) ) , SLOT ( generateResumeData ( ) ) ) ;
m_statistics = new Statistics ( this ) ;
// Apply user settings to BitTorrent session
configure ( ) ;
connect ( pref , SIGNAL ( changed ( ) ) , SLOT ( configure ( ) ) ) ;
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
{
return m_DHTEnabled ;
}
bool Session : : isLSDEnabled ( ) const
{
return m_LSDEnabled ;
}
bool Session : : isPexEnabled ( ) const
{
return m_PeXEnabled ;
}
bool Session : : isQueueingEnabled ( ) const
{
return m_queueingEnabled ;
}
bool Session : : isTempPathEnabled ( ) const
{
return ! m_tempPath . isEmpty ( ) ;
}
bool Session : : isAppendExtensionEnabled ( ) const
{
return m_appendExtension ;
}
bool Session : : useAppendLabelToSavePath ( ) const
{
return m_appendLabelToSavePath ;
}
QString Session : : defaultSavePath ( ) const
{
return m_defaultSavePath ;
}
QString Session : : tempPath ( ) const
{
return m_tempPath ;
}
qreal Session : : globalMaxRatio ( ) const
{
return m_globalMaxRatio ;
}
// 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 ;
}
void Session : : setSessionSettings ( )
{
Preferences * const pref = Preferences : : instance ( ) ;
Logger * const logger = Logger : : instance ( ) ;
libt : : session_settings sessionSettings = m_nativeSession - > settings ( ) ;
sessionSettings . user_agent = " qBittorrent " VERSION ;
2015-03-30 14:15:48 +03:00
//std::cout << "HTTP User-Agent is " << sessionSettings.user_agent << std::endl;
2015-08-08 16:19:46 +03:00
logger - > addMessage ( tr ( " HTTP User-Agent is '%1' " ) . arg ( Utils : : String : : fromStdString ( sessionSettings . user_agent ) ) ) ;
2015-04-19 18:17:47 +03:00
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
bool announce_to_all = pref - > announceToAllTrackers ( ) ;
sessionSettings . announce_to_all_trackers = announce_to_all ;
sessionSettings . announce_to_all_tiers = announce_to_all ;
sessionSettings . auto_scrape_min_interval = 900 ; // 15 minutes
int cache_size = pref - > diskCacheSize ( ) ;
sessionSettings . cache_size = cache_size ? cache_size * 64 : - 1 ;
sessionSettings . cache_expiry = pref - > diskCacheTTL ( ) ;
qDebug ( ) < < " Using a disk cache size of " < < cache_size < < " MiB " ;
libt : : session_settings : : io_buffer_mode_t mode = pref - > osCache ( ) ? libt : : session_settings : : enable_os_cache : libt : : session_settings : : disable_os_cache ;
sessionSettings . disk_io_read_mode = mode ;
sessionSettings . disk_io_write_mode = mode ;
m_resumeDataTimer - > setInterval ( pref - > saveResumeDataInterval ( ) * 60 * 1000 ) ;
sessionSettings . anonymous_mode = pref - > isAnonymousModeEnabled ( ) ;
if ( sessionSettings . anonymous_mode )
logger - > addMessage ( tr ( " Anonymous mode [ON] " ) , Log : : INFO ) ;
else
logger - > addMessage ( tr ( " Anonymous mode [OFF] " ) , Log : : INFO ) ;
// Queueing System
m_queueingEnabled = pref - > isQueueingSystemEnabled ( ) ;
if ( m_queueingEnabled ) {
adjustLimits ( sessionSettings ) ;
sessionSettings . active_seeds = pref - > getMaxActiveUploads ( ) ;
sessionSettings . dont_count_slow_torrents = pref - > ignoreSlowTorrentsForQueueing ( ) ;
}
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-01-20 10:15:10 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
2015-04-19 18:17:47 +03:00
sessionSettings . outgoing_ports = std : : make_pair ( pref - > outgoingPortsMin ( ) , pref - > outgoingPortsMax ( ) ) ;
2016-01-20 10:15:10 +03:00
# else
sessionSettings . outgoing_port = pref - > outgoingPortsMin ( ) ;
sessionSettings . num_outgoing_ports = pref - > outgoingPortsMax ( ) - pref - > outgoingPortsMin ( ) ;
# endif
2015-04-19 18:17:47 +03:00
// Ignore limits on LAN
2015-07-21 21:43:59 +03:00
qDebug ( ) < < " Ignore limits on LAN " < < pref - > getIgnoreLimitsOnLAN ( ) ;
sessionSettings . ignore_limits_on_local_network = pref - > getIgnoreLimitsOnLAN ( ) ;
2015-04-19 18:17:47 +03:00
// Include overhead in transfer limits
sessionSettings . rate_limit_ip_overhead = pref - > includeOverheadInLimits ( ) ;
// IP address to announce to trackers
2015-12-03 22:22:56 +03:00
sessionSettings . announce_ip = Utils : : String : : toStdString ( pref - > getNetworkAddress ( ) ) ;
2015-04-19 18:17:47 +03:00
// Super seeding
sessionSettings . strict_super_seeding = pref - > isSuperSeedingEnabled ( ) ;
// * Max Half-open connections
sessionSettings . half_open_limit = pref - > getMaxHalfOpenConnections ( ) ;
// * Max connections limit
sessionSettings . connections_limit = pref - > getMaxConnecs ( ) ;
// * Global max upload slots
sessionSettings . unchoke_slots_limit = pref - > getMaxUploads ( ) ;
// uTP
sessionSettings . enable_incoming_utp = pref - > isuTPEnabled ( ) ;
sessionSettings . enable_outgoing_utp = pref - > isuTPEnabled ( ) ;
// uTP rate limiting
sessionSettings . rate_limit_utp = pref - > isuTPRateLimited ( ) ;
if ( sessionSettings . rate_limit_utp )
sessionSettings . mixed_mode_algorithm = libt : : session_settings : : prefer_tcp ;
else
sessionSettings . mixed_mode_algorithm = libt : : session_settings : : peer_proportional ;
sessionSettings . connection_speed = 20 ; //default is 10
if ( pref - > isProxyEnabled ( ) )
sessionSettings . force_proxy = pref - > getForceProxy ( ) ;
else
sessionSettings . force_proxy = false ;
sessionSettings . no_connect_privileged_ports = false ;
sessionSettings . seed_choking_algorithm = libt : : session_settings : : fastest_upload ;
qDebug ( ) < < " Set session settings " ;
m_nativeSession - > set_settings ( sessionSettings ) ;
}
void Session : : adjustLimits ( )
{
if ( m_queueingEnabled ) {
libt : : session_settings sessionSettings ( m_nativeSession - > settings ( ) ) ;
adjustLimits ( sessionSettings ) ;
m_nativeSession - > set_settings ( sessionSettings ) ;
}
}
void Session : : adjustLimits ( libt : : session_settings & sessionSettings )
{
Preferences * const pref = Preferences : : instance ( ) ;
//Internally increase the queue limits to ensure that the magnet is started
int max_downloading = pref - > getMaxActiveDownloads ( ) ;
int max_active = pref - > getMaxActiveTorrents ( ) ;
2015-09-16 21:57:50 +03:00
2015-04-19 18:17:47 +03:00
if ( max_downloading > - 1 )
sessionSettings . active_downloads = max_downloading + m_extraLimit ;
else
sessionSettings . active_downloads = max_downloading ;
2015-09-16 21:57:50 +03:00
if ( max_active > - 1 )
sessionSettings . active_limit = max_active + m_extraLimit ;
else
2015-04-19 18:17:47 +03:00
sessionSettings . active_limit = max_active ;
}
// Set BitTorrent session configuration
void Session : : configure ( )
{
qDebug ( " Configuring session " ) ;
Preferences * const pref = Preferences : : instance ( ) ;
const unsigned short oldListenPort = m_nativeSession - > listen_port ( ) ;
const unsigned short newListenPort = pref - > getSessionPort ( ) ;
if ( oldListenPort ! = newListenPort ) {
qDebug ( " Session port changes in program preferences: %d -> %d " , oldListenPort , newListenPort ) ;
2015-06-15 01:06:56 +03:00
setListeningPort ( ) ;
2015-04-19 18:17:47 +03:00
}
// * Save path
setDefaultSavePath ( pref - > getSavePath ( ) ) ;
// * Temp path
if ( pref - > isTempPathEnabled ( ) )
setDefaultTempPath ( pref - > getTempPath ( ) ) ;
else
setDefaultTempPath ( ) ;
uint newRefreshInterval = pref - > getRefreshInterval ( ) ;
if ( newRefreshInterval ! = m_refreshInterval ) {
m_refreshInterval = newRefreshInterval ;
m_refreshTimer - > setInterval ( m_refreshInterval ) ;
}
setAppendLabelToSavePath ( pref - > appendTorrentLabel ( ) ) ;
setAppendExtension ( pref - > useIncompleteFilesExtension ( ) ) ;
preAllocateAllFiles ( pref - > preAllocateAllFiles ( ) ) ;
// * Torrent export directory
const bool torrentExportEnabled = pref - > isTorrentExportEnabled ( ) ;
if ( m_torrentExportEnabled ! = torrentExportEnabled ) {
m_torrentExportEnabled = torrentExportEnabled ;
if ( m_torrentExportEnabled ) {
qDebug ( " Torrent export is enabled, exporting the current torrents " ) ;
2015-12-01 17:41:56 +03:00
for ( auto torrent : m_torrents )
exportTorrentFile ( torrent ) ;
2015-04-19 18:17:47 +03:00
}
}
// * Finished Torrent export directory
const bool finishedTorrentExportEnabled = pref - > isFinishedTorrentExportEnabled ( ) ;
if ( m_finishedTorrentExportEnabled ! = finishedTorrentExportEnabled )
m_finishedTorrentExportEnabled = finishedTorrentExportEnabled ;
// Connection
// * Global download limit
const bool alternative_speeds = pref - > isAltBandwidthEnabled ( ) ;
int down_limit ;
if ( alternative_speeds )
down_limit = pref - > getAltGlobalDownloadLimit ( ) ;
else
down_limit = pref - > getGlobalDownloadLimit ( ) ;
if ( down_limit < = 0 ) {
// Download limit disabled
setDownloadRateLimit ( - 1 ) ;
}
else {
// Enabled
setDownloadRateLimit ( down_limit * 1024 ) ;
}
int up_limit ;
if ( alternative_speeds )
up_limit = pref - > getAltGlobalUploadLimit ( ) ;
else
up_limit = pref - > getGlobalUploadLimit ( ) ;
// * Global Upload limit
if ( up_limit < = 0 ) {
// Upload limit disabled
setUploadRateLimit ( - 1 ) ;
}
else {
// Enabled
setUploadRateLimit ( up_limit * 1024 ) ;
}
if ( pref - > isSchedulerEnabled ( ) ) {
if ( ! m_bwScheduler ) {
m_bwScheduler = new BandwidthScheduler ( this ) ;
2015-07-22 08:51:23 +03:00
connect ( m_bwScheduler . data ( ) , SIGNAL ( switchToAlternativeMode ( bool ) ) , this , SLOT ( switchToAlternativeMode ( bool ) ) ) ;
2015-04-19 18:17:47 +03:00
}
m_bwScheduler - > start ( ) ;
}
else {
delete m_bwScheduler ;
}
Logger * const logger = Logger : : instance ( ) ;
// * Session settings
setSessionSettings ( ) ;
// Bittorrent
// * Max connections per torrent limit
setMaxConnectionsPerTorrent ( pref - > getMaxConnecsPerTorrent ( ) ) ;
// * Max uploads per torrent limit
setMaxUploadsPerTorrent ( pref - > getMaxUploadsPerTorrent ( ) ) ;
// * DHT
enableDHT ( pref - > isDHTEnabled ( ) ) ;
// * PeX
if ( m_PeXEnabled )
logger - > addMessage ( tr ( " PeX support [ON] " ) , Log : : INFO ) ;
else
logger - > addMessage ( tr ( " PeX support [OFF] " ) , Log : : CRITICAL ) ;
if ( m_PeXEnabled ! = pref - > isPeXEnabled ( ) )
logger - > addMessage ( tr ( " Restart is required to toggle PeX support " ) , Log : : CRITICAL ) ;
// * LSD
if ( pref - > isLSDEnabled ( ) ) {
enableLSD ( true ) ;
logger - > addMessage ( tr ( " Local Peer Discovery support [ON] " ) , Log : : INFO ) ;
}
else {
enableLSD ( false ) ;
logger - > addMessage ( tr ( " Local Peer Discovery support [OFF] " ) , Log : : INFO ) ;
}
// * Encryption
const int encryptionState = pref - > getEncryptionSetting ( ) ;
// The most secure, rc4 only so that all streams and encrypted
libt : : pe_settings encryptionSettings ;
encryptionSettings . allowed_enc_level = libt : : pe_settings : : rc4 ;
encryptionSettings . prefer_rc4 = true ;
switch ( encryptionState ) {
case 0 : //Enabled
encryptionSettings . out_enc_policy = libt : : pe_settings : : enabled ;
encryptionSettings . in_enc_policy = libt : : pe_settings : : enabled ;
logger - > addMessage ( tr ( " Encryption support [ON] " ) , Log : : INFO ) ;
break ;
case 1 : // Forced
encryptionSettings . out_enc_policy = libt : : pe_settings : : forced ;
encryptionSettings . in_enc_policy = libt : : pe_settings : : forced ;
logger - > addMessage ( tr ( " Encryption support [FORCED] " ) , Log : : INFO ) ;
break ;
default : // Disabled
encryptionSettings . out_enc_policy = libt : : pe_settings : : disabled ;
encryptionSettings . in_enc_policy = libt : : pe_settings : : disabled ;
logger - > addMessage ( tr ( " Encryption support [OFF] " ) , Log : : INFO ) ;
}
qDebug ( " Applying encryption settings " ) ;
m_nativeSession - > set_pe_settings ( encryptionSettings ) ;
2015-06-30 21:03:17 +03:00
// * Add trackers
2016-01-13 19:12:31 +03:00
m_additionalTrackers . clear ( ) ;
2015-06-30 21:03:17 +03:00
if ( pref - > isAddTrackersEnabled ( ) ) {
foreach ( QString tracker , pref - > getTrackersList ( ) . split ( " \n " ) ) {
tracker = tracker . trimmed ( ) ;
if ( ! tracker . isEmpty ( ) )
m_additionalTrackers < < tracker ;
}
}
2015-04-19 18:17:47 +03:00
// * Maximum ratio
m_highRatioAction = pref - > getMaxRatioAction ( ) ;
setGlobalMaxRatio ( pref - > getGlobalMaxRatio ( ) ) ;
// Ip Filter
if ( pref - > isFilteringEnabled ( ) )
enableIPFilter ( pref - > getFilter ( ) ) ;
else
disableIPFilter ( ) ;
2015-11-04 18:15:37 +03:00
// Add the banned IPs after the possibly disabled IPFilter
// which creates an empty filter and overrides all previously
// applied bans.
FilterParserThread : : processFilterList ( m_nativeSession , pref - > bannedIPs ( ) ) ;
2015-04-19 18:17:47 +03:00
// * Proxy settings
libt : : proxy_settings proxySettings ;
if ( pref - > isProxyEnabled ( ) ) {
qDebug ( " Enabling P2P proxy " ) ;
2015-05-06 14:53:27 +03:00
proxySettings . hostname = Utils : : String : : toStdString ( pref - > getProxyIp ( ) ) ;
2015-04-19 18:17:47 +03:00
qDebug ( " hostname is %s " , proxySettings . hostname . c_str ( ) ) ;
proxySettings . port = pref - > getProxyPort ( ) ;
qDebug ( " port is %d " , proxySettings . port ) ;
if ( pref - > isProxyAuthEnabled ( ) ) {
2015-05-06 14:53:27 +03:00
proxySettings . username = Utils : : String : : toStdString ( pref - > getProxyUsername ( ) ) ;
proxySettings . password = Utils : : String : : toStdString ( pref - > getProxyPassword ( ) ) ;
2015-04-19 18:17:47 +03:00
qDebug ( " username is %s " , proxySettings . username . c_str ( ) ) ;
qDebug ( " password is %s " , proxySettings . password . c_str ( ) ) ;
}
}
switch ( pref - > getProxyType ( ) ) {
case Proxy : : HTTP :
qDebug ( " type: http " ) ;
proxySettings . type = libt : : proxy_settings : : http ;
break ;
case Proxy : : HTTP_PW :
qDebug ( " type: http_pw " ) ;
proxySettings . type = libt : : proxy_settings : : http_pw ;
break ;
case Proxy : : SOCKS4 :
proxySettings . type = libt : : proxy_settings : : socks4 ;
break ;
case Proxy : : SOCKS5 :
qDebug ( " type: socks5 " ) ;
proxySettings . type = libt : : proxy_settings : : socks5 ;
break ;
case Proxy : : SOCKS5_PW :
qDebug ( " type: socks5_pw " ) ;
proxySettings . type = libt : : proxy_settings : : socks5_pw ;
break ;
default :
proxySettings . type = libt : : proxy_settings : : none ;
}
setProxySettings ( proxySettings ) ;
// Tracker
if ( pref - > isTrackerEnabled ( ) ) {
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 ;
}
qDebug ( " Session configured " ) ;
}
void Session : : preAllocateAllFiles ( bool b )
{
const bool change = ( m_preAllocateAll ! = b ) ;
if ( change ) {
qDebug ( " PreAllocateAll changed, reloading all torrents! " ) ;
m_preAllocateAll = b ;
}
}
void Session : : processBigRatios ( )
{
qDebug ( " Process big ratios... " ) ;
foreach ( TorrentHandle * const torrent , m_torrents ) {
if ( torrent - > isSeed ( ) & & ( torrent - > ratioLimit ( ) ! = TorrentHandle : : NO_RATIO_LIMIT ) ) {
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...
if ( m_globalMaxRatio > = 0 )
ratioLimit = m_globalMaxRatio ;
else
continue ;
}
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 ( ) ;
if ( m_highRatioAction = = 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
}
void Session : : changeSpeedLimitMode ( bool alternative )
{
Preferences * const pref = Preferences : : instance ( ) ;
// Stop the scheduler when the user has manually changed the bandwidth mode
2015-07-22 08:51:23 +03:00
if ( pref - > isSchedulerEnabled ( ) ) {
pref - > setSchedulerEnabled ( false ) ;
2015-04-19 18:17:47 +03:00
delete m_bwScheduler ;
2015-07-22 08:51:23 +03:00
}
2015-04-19 18:17:47 +03:00
2015-07-22 08:51:23 +03:00
changeSpeedLimitMode_impl ( alternative ) ;
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 )
{
FilterParserThread : : processFilterList ( m_nativeSession , QStringList ( ip ) ) ;
Preferences : : instance ( ) - > banIP ( ip ) ;
}
// 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 ( ) ;
m_nativeSession - > remove_torrent ( torrent - > nativeHandle ( ) ) ;
// 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-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 ,
2015-04-19 18:17:47 +03:00
const TorrentInfo & torrentInfo , const QByteArray & fastresumeData )
{
2016-01-01 16:28:40 +03:00
if ( ! addData . resumed ) {
// manage save path
QString defaultSavePath = this - > defaultSavePath ( ) ;
if ( addData . savePath . isEmpty ( ) )
addData . savePath = defaultSavePath ;
if ( ! addData . savePath . endsWith ( " / " ) )
addData . savePath + = " / " ;
if ( useAppendLabelToSavePath ( ) ) {
if ( ( addData . savePath = = defaultSavePath ) & & ! addData . label . isEmpty ( ) )
addData . savePath + = QString ( " %1/ " ) . arg ( addData . label ) ;
}
}
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 ;
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
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
if ( m_preAllocateAll )
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
Preferences * const pref = Preferences : : instance ( ) ;
p . max_connections = pref - > getMaxConnecsPerTorrent ( ) ;
p . max_uploads = pref - > getMaxUploadsPerTorrent ( ) ;
QString savePath ;
// Set actual save path (e.g. temporary folder)
2015-11-01 09:22:18 +03:00
if ( isTempPathEnabled ( ) & & ! addData . disableTempPath & & ! addData . hasSeedStatus )
2015-04-19 18:17:47 +03:00
savePath = m_tempPath ;
2015-11-01 09:22:18 +03:00
else
2015-04-19 18:17:47 +03:00
savePath = addData . savePath ;
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
// Check if save path exists, creating it otherwise
if ( ! QDir ( savePath ) . exists ( ) )
QDir ( ) . mkpath ( savePath ) ;
m_addingTorrents . insert ( hash , addData ) ;
// Adding torrent to BitTorrent session
m_nativeSession - > async_add_torrent ( p ) ;
return true ;
}
// 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
if ( m_preAllocateAll )
p . storage_mode = libt : : storage_mode_allocate ;
else
p . storage_mode = libt : : storage_mode_sparse ;
Preferences * const pref = Preferences : : instance ( ) ;
// Limits
p . max_connections = pref - > getMaxConnecsPerTorrent ( ) ;
p . max_uploads = pref - > getMaxUploadsPerTorrent ( ) ;
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
// Check if save path exists, creating it otherwise
if ( ! QDir ( savePath ) . exists ( ) )
QDir ( ) . mkpath ( savePath ) ;
// 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 )
{
Q_ASSERT ( ( ( folder = = TorrentExportFolder : : Regular ) & & m_torrentExportEnabled ) | |
( ( folder = = TorrentExportFolder : : Finished ) & & m_finishedTorrentExportEnabled ) ) ;
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 ) ;
QDir exportPath ( folder = = TorrentExportFolder : : Regular ? Preferences : : instance ( ) - > getTorrentExportDir ( ) : Preferences : : instance ( ) - > getFinishedTorrentExportDir ( ) ) ;
if ( exportPath . exists ( ) | | exportPath . mkpath ( exportPath . absolutePath ( ) ) ) {
2015-12-01 17:41:56 +03:00
QString newTorrentPath = exportPath . absoluteFilePath ( torrentExportFilename ) ;
int counter = 0 ;
while ( QFile : : exists ( newTorrentPath ) & & ! Utils : : Fs : : sameFiles ( torrentPath , newTorrentPath ) ) {
// Append number to torrent name to make it unique
torrentExportFilename = QString ( " %1 %2.torrent " ) . arg ( validName ) . arg ( + + counter ) ;
newTorrentPath = exportPath . absoluteFilePath ( torrentExportFilename ) ;
2015-04-19 18:17:47 +03:00
}
2015-12-01 17:41:56 +03:00
if ( ! QFile : : exists ( newTorrentPath ) )
QFile : : copy ( torrentPath , newTorrentPath ) ;
2015-04-19 18:17:47 +03:00
}
}
void Session : : setMaxConnectionsPerTorrent ( int max )
{
qDebug ( ) < < Q_FUNC_INFO < < max ;
// Apply this to all session torrents
std : : vector < libt : : torrent_handle > handles = m_nativeSession - > get_torrents ( ) ;
std : : vector < libt : : torrent_handle > : : const_iterator it = handles . begin ( ) ;
std : : vector < libt : : torrent_handle > : : const_iterator itend = handles . end ( ) ;
for ( ; it ! = itend ; + + it ) {
if ( ! it - > is_valid ( ) ) continue ;
try {
it - > set_max_connections ( max ) ;
}
catch ( std : : exception ) { }
}
}
void Session : : setMaxUploadsPerTorrent ( int max )
{
qDebug ( ) < < Q_FUNC_INFO < < max ;
// Apply this to all session torrents
std : : vector < libt : : torrent_handle > handles = m_nativeSession - > get_torrents ( ) ;
std : : vector < libt : : torrent_handle > : : const_iterator it = handles . begin ( ) ;
std : : vector < libt : : torrent_handle > : : const_iterator itend = handles . end ( ) ;
for ( ; it ! = itend ; + + it ) {
if ( ! it - > is_valid ( ) ) continue ;
try {
it - > set_max_uploads ( max ) ;
}
catch ( std : : exception ) { }
}
}
void Session : : enableLSD ( bool enable )
{
if ( enable ) {
if ( ! m_LSDEnabled ) {
qDebug ( " Enabling Local Peer Discovery " ) ;
m_nativeSession - > start_lsd ( ) ;
m_LSDEnabled = true ;
}
}
else {
if ( m_LSDEnabled ) {
qDebug ( " Disabling Local Peer Discovery " ) ;
m_nativeSession - > stop_lsd ( ) ;
m_LSDEnabled = false ;
}
}
}
// Enable DHT
void Session : : enableDHT ( bool enable )
{
Logger * const logger = Logger : : instance ( ) ;
if ( enable ) {
if ( ! m_DHTEnabled ) {
try {
qDebug ( ) < < " Starting DHT... " ;
Q_ASSERT ( ! m_nativeSession - > is_dht_running ( ) ) ;
m_nativeSession - > start_dht ( ) ;
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
m_DHTEnabled = true ;
logger - > addMessage ( tr ( " DHT support [ON] " ) , Log : : INFO ) ;
qDebug ( " DHT enabled " ) ;
}
catch ( std : : exception & e ) {
qDebug ( " Could not enable DHT, reason: %s " , e . what ( ) ) ;
2015-05-06 14:53:27 +03:00
logger - > addMessage ( tr ( " DHT support [OFF]. Reason: %1 " ) . arg ( Utils : : String : : fromStdString ( e . what ( ) ) ) , Log : : CRITICAL ) ;
2015-04-19 18:17:47 +03:00
}
}
}
else {
if ( m_DHTEnabled ) {
m_DHTEnabled = false ;
m_nativeSession - > stop_dht ( ) ;
logger - > addMessage ( tr ( " DHT support [OFF] " ) , Log : : INFO ) ;
qDebug ( " DHT disabled " ) ;
}
}
}
2015-07-22 08:51:23 +03:00
void Session : : changeSpeedLimitMode_impl ( bool alternative )
{
qDebug ( ) < < Q_FUNC_INFO < < alternative ;
Preferences * const pref = Preferences : : instance ( ) ;
// Save new state to remember it on startup
pref - > setAltBandwidthEnabled ( alternative ) ;
// Apply settings to the bittorrent session
int downLimit = alternative ? pref - > getAltGlobalDownloadLimit ( ) : pref - > getGlobalDownloadLimit ( ) ;
if ( downLimit < = 0 )
downLimit = - 1 ;
else
downLimit * = 1024 ;
setDownloadRateLimit ( downLimit ) ;
// Upload rate
int upLimit = alternative ? pref - > getAltGlobalUploadLimit ( ) : pref - > getGlobalUploadLimit ( ) ;
if ( upLimit < = 0 )
upLimit = - 1 ;
else
upLimit * = 1024 ;
setUploadRateLimit ( upLimit ) ;
// 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 ) {
QVector < libt : : alert * > alerts ;
getPendingAlerts ( alerts , 30 * 1000 ) ;
if ( alerts . empty ( ) ) {
std : : cerr < < " aborting with " < < m_numResumeData
< < " outstanding torrents to save resume data for "
< < std : : endl ;
break ;
}
foreach ( libt : : alert * const a , alerts ) {
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 ;
}
delete a ;
}
}
}
void Session : : setDefaultSavePath ( const QString & path )
{
if ( path . isEmpty ( ) ) return ;
2015-08-16 20:03:32 +03:00
m_defaultSavePath = Utils : : Fs : : fromNativePath ( path ) ;
if ( ! m_defaultSavePath . endsWith ( " / " ) )
m_defaultSavePath + = " / " ;
2015-04-19 18:17:47 +03:00
}
void Session : : setDefaultTempPath ( const QString & path )
{
QString tempPath ;
if ( ! path . isEmpty ( ) ) {
2015-05-06 14:53:27 +03:00
tempPath = Utils : : Fs : : fromNativePath ( path ) ;
2015-04-19 18:17:47 +03:00
if ( ! tempPath . endsWith ( " / " ) )
tempPath + = " / " ;
}
if ( m_tempPath ! = tempPath ) {
m_tempPath = tempPath ;
2015-09-25 10:52:25 +03:00
foreach ( TorrentHandle * const torrent , m_torrents )
2015-04-19 18:17:47 +03:00
torrent - > handleTempPathChanged ( ) ;
}
}
void Session : : setAppendLabelToSavePath ( bool append )
{
if ( m_appendLabelToSavePath ! = append ) {
m_appendLabelToSavePath = append ;
2015-08-16 20:03:32 +03:00
foreach ( TorrentHandle * const torrent , m_torrents ) {
QString label = torrent - > label ( ) ;
if ( label . isEmpty ( ) ) continue ;
QString testedOldSavePath = m_defaultSavePath ;
QString newSavePath = m_defaultSavePath ;
if ( ! m_appendLabelToSavePath )
testedOldSavePath + = QString ( " %1/ " ) . arg ( label ) ;
else
newSavePath + = QString ( " %1/ " ) . arg ( label ) ;
if ( torrent - > savePath ( ) = = testedOldSavePath )
torrent - > move ( newSavePath ) ;
}
2015-04-19 18:17:47 +03:00
}
}
void Session : : setAppendExtension ( bool append )
{
if ( m_appendExtension ! = append ) {
m_appendExtension = append ;
// append or remove .!qB extension for incomplete files
2015-09-25 10:52:25 +03:00
foreach ( TorrentHandle * const torrent , m_torrents )
2015-04-19 18:17:47 +03:00
torrent - > handleAppendExtensionToggled ( ) ;
}
}
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 )
{
const QString configuredInterfaceName = Preferences : : instance ( ) - > getNetworkInterface ( ) ;
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.
2015-11-29 15:30:42 +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 ) ;
setListeningPort ( ) ;
}
}
2015-11-07 03:06:07 +03:00
const QStringList Session : : getListeningIPs ( )
2015-04-19 18:17:47 +03:00
{
Preferences * const pref = Preferences : : instance ( ) ;
Logger * const logger = Logger : : instance ( ) ;
2015-11-07 03:06:07 +03:00
QStringList IPs ;
2015-04-19 18:17:47 +03:00
2015-11-07 03:06:07 +03:00
const QString ifaceName = pref - > getNetworkInterface ( ) ;
const bool listenIPv6 = pref - > getListenIPv6 ( ) ;
2015-04-19 18:17:47 +03:00
2015-11-07 03:06:07 +03:00
if ( ifaceName . isEmpty ( ) ) {
IPs . append ( QString ( ) ) ;
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 ;
2015-11-07 03:06:07 +03:00
IPs . append ( ipString ) ;
}
// 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
void Session : : setListeningPort ( )
{
Preferences * const pref = Preferences : : instance ( ) ;
const unsigned short port = pref - > getSessionPort ( ) ;
qDebug ( ) < < Q_FUNC_INFO < < port ;
Logger * const logger = Logger : : instance ( ) ;
std : : pair < int , int > ports ( port , port ) ;
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 ;
}
}
}
// Set download rate limit
// -1 to disable
void Session : : setDownloadRateLimit ( int rate )
{
qDebug ( ) < < Q_FUNC_INFO < < rate ;
Q_ASSERT ( ( rate = = - 1 ) | | ( rate > = 0 ) ) ;
libt : : session_settings settings = m_nativeSession - > settings ( ) ;
settings . download_rate_limit = rate ;
m_nativeSession - > set_settings ( settings ) ;
}
// Set upload rate limit
// -1 to disable
void Session : : setUploadRateLimit ( int rate )
{
qDebug ( ) < < Q_FUNC_INFO < < rate ;
Q_ASSERT ( ( rate = = - 1 ) | | ( rate > = 0 ) ) ;
libt : : session_settings settings = m_nativeSession - > settings ( ) ;
settings . upload_rate_limit = rate ;
m_nativeSession - > set_settings ( settings ) ;
}
int Session : : downloadRateLimit ( ) const
{
return m_nativeSession - > settings ( ) . download_rate_limit ;
}
int Session : : uploadRateLimit ( ) const
{
return m_nativeSession - > settings ( ) . upload_rate_limit ;
}
bool Session : : isListening ( ) const
{
return m_nativeSession - > is_listening ( ) ;
}
// Torrents will a ratio superior to the given value will
// be automatically deleted
void Session : : setGlobalMaxRatio ( qreal ratio )
{
if ( ratio < 0 )
ratio = - 1. ;
if ( m_globalMaxRatio ! = ratio ) {
m_globalMaxRatio = ratio ;
qDebug ( " * Set globalMaxRatio to %.1f " , m_globalMaxRatio ) ;
updateRatioTimer ( ) ;
}
}
// 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 ( )
{
if ( ( m_globalMaxRatio = = - 1 ) & & ! hasPerTorrentRatioLimit ( ) ) {
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 ) ;
}
2015-06-07 15:03:30 +03:00
void Session : : handleTorrentLabelChanged ( TorrentHandle * const torrent , const QString & oldLabel )
{
2015-08-16 20:03:32 +03:00
if ( m_appendLabelToSavePath ) {
QString testedOldSavePath = m_defaultSavePath ;
if ( ! oldLabel . isEmpty ( ) )
testedOldSavePath + = QString ( " %1/ " ) . arg ( oldLabel ) ;
QString newLabel = torrent - > label ( ) ;
if ( torrent - > savePath ( ) = = testedOldSavePath ) {
QString newSavePath = m_defaultSavePath ;
if ( ! newLabel . isEmpty ( ) )
newSavePath + = QString ( " %1/ " ) . arg ( newLabel ) ;
torrent - > move ( newSavePath ) ;
}
}
2015-06-07 15:03:30 +03:00
emit torrentLabelChanged ( torrent , oldLabel ) ;
}
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
if ( m_torrentExportEnabled )
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
}
}
}
Preferences * const pref = Preferences : : instance ( ) ;
// Move .torrent file to another folder
if ( pref - > isFinishedTorrentExportEnabled ( ) )
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. " ) ;
}
}
// Enable IP Filtering
void Session : : enableIPFilter ( const QString & filterPath , bool force )
{
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 ( ) ) ) ;
}
2015-05-06 14:53:27 +03:00
if ( m_filterPath . isEmpty ( ) | | m_filterPath ! = Utils : : Fs : : fromNativePath ( filterPath ) | | force ) {
m_filterPath = Utils : : Fs : : fromNativePath ( filterPath ) ;
m_filterParser - > processFilterFile ( Utils : : Fs : : fromNativePath ( filterPath ) ) ;
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 ;
}
m_filterPath = " " ;
}
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 ( ) ;
}
// Set Proxy
void Session : : setProxySettings ( libt : : proxy_settings proxySettings )
{
qDebug ( ) < < Q_FUNC_INFO ;
proxySettings . proxy_peer_connections = Preferences : : instance ( ) - > proxyPeerConnections ( ) ;
m_nativeSession - > set_proxy ( proxySettings ) ;
2015-08-04 15:12:58 +03:00
// Define environment variables for urllib in search engine plugins
2015-08-03 15:27:47 +03:00
if ( Preferences : : instance ( ) - > isProxyOnlyForTorrents ( ) ) {
2015-04-19 18:17:47 +03:00
qputenv ( " http_proxy " , QByteArray ( ) ) ;
2015-08-04 15:12:58 +03:00
qputenv ( " https_proxy " , QByteArray ( ) ) ;
2015-04-19 18:17:47 +03:00
qputenv ( " sock_proxy " , QByteArray ( ) ) ;
}
2015-08-03 15:27:47 +03:00
else {
QString proxy_str ;
switch ( proxySettings . type ) {
case libt : : proxy_settings : : http_pw :
proxy_str = QString ( " http://%1:%2@%3:%4 " ) . arg ( Utils : : String : : fromStdString ( proxySettings . username ) ) . arg ( Utils : : String : : fromStdString ( proxySettings . password ) )
. arg ( Utils : : String : : fromStdString ( proxySettings . hostname ) ) . arg ( proxySettings . port ) ;
break ;
case libt : : proxy_settings : : http :
proxy_str = QString ( " http://%1:%2 " ) . arg ( Utils : : String : : fromStdString ( proxySettings . hostname ) ) . arg ( proxySettings . port ) ;
break ;
case libt : : proxy_settings : : socks5 :
proxy_str = QString ( " %1:%2 " ) . arg ( Utils : : String : : fromStdString ( proxySettings . hostname ) ) . arg ( proxySettings . port ) ;
break ;
case libt : : proxy_settings : : socks5_pw :
proxy_str = QString ( " %1:%2@%3:%4 " ) . arg ( Utils : : String : : fromStdString ( proxySettings . username ) ) . arg ( Utils : : String : : fromStdString ( proxySettings . password ) )
. arg ( Utils : : String : : fromStdString ( proxySettings . hostname ) ) . arg ( proxySettings . port ) ;
break ;
default :
qDebug ( " Disabling HTTP communications proxy " ) ;
qputenv ( " http_proxy " , QByteArray ( ) ) ;
2015-08-04 15:12:58 +03:00
qputenv ( " https_proxy " , QByteArray ( ) ) ;
2015-08-03 15:27:47 +03:00
qputenv ( " sock_proxy " , QByteArray ( ) ) ;
return ;
}
qDebug ( " HTTP communications proxy string: %s " , qPrintable ( proxy_str ) ) ;
if ( ( proxySettings . type = = libt : : proxy_settings : : socks5 ) | | ( proxySettings . type = = libt : : proxy_settings : : socks5_pw ) )
qputenv ( " sock_proxy " , proxy_str . toLocal8Bit ( ) ) ;
2015-08-04 15:12:58 +03:00
else {
2015-08-03 15:27:47 +03:00
qputenv ( " http_proxy " , proxy_str . toLocal8Bit ( ) ) ;
2015-08-04 15:12:58 +03:00
qputenv ( " https_proxy " , proxy_str . toLocal8Bit ( ) ) ;
}
2015-08-03 15:27:47 +03:00
}
2015-04-19 18:17:47 +03:00
}
// Will resume torrents in backup directory
void Session : : startUpTorrents ( )
{
qDebug ( " Resuming torrents... " ) ;
const QDir resumeDataDir ( m_resumeFolderPath ) ;
QStringList fastresumes = resumeDataDir . entryList (
2015-12-16 17:08:27 +03:00
QStringList ( QLatin1String ( " *.fastresume " ) ) , QDir : : Files , QDir : : Unsorted ) ;
2015-04-19 18:17:47 +03:00
Logger * const logger = Logger : : instance ( ) ;
2015-12-16 17:08:27 +03:00
typedef struct
{
QString hash ;
MagnetUri magnetUri ;
AddTorrentData addTorrentData ;
QByteArray data ;
} TorrentResumeData ;
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 ) ) ;
emit ipFilterParsed ( false , ruleCount ) ;
}
void Session : : handleIPFilterError ( )
{
Logger : : instance ( ) - > addMessage ( tr ( " Error: Failed to parse the provided IP filter. " ) , Log : : CRITICAL ) ;
emit ipFilterParsed ( true , 0 ) ;
}
void Session : : dispatchAlerts ( std : : auto_ptr < libt : : alert > alertPtr )
{
QMutexLocker lock ( & m_alertsMutex ) ;
bool wasEmpty = m_alerts . isEmpty ( ) ;
m_alerts . append ( alertPtr . release ( ) ) ;
if ( wasEmpty ) {
m_alertsWaitCondition . wakeAll ( ) ;
QMetaObject : : invokeMethod ( this , " readAlerts " , Qt : : QueuedConnection ) ;
}
}
void Session : : getPendingAlerts ( QVector < libt : : alert * > & out , ulong time )
{
Q_ASSERT ( out . empty ( ) ) ;
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 ) ;
}
// Read alerts sent by the BitTorrent session
void Session : : readAlerts ( )
{
QVector < libt : : alert * > alerts ;
getPendingAlerts ( alerts ) ;
foreach ( libt : : alert * const a , alerts ) {
handleAlert ( a ) ;
delete a ;
}
}
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 ) ;
Preferences * const pref = Preferences : : instance ( ) ;
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
if ( m_torrentExportEnabled )
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
}
}
2015-06-30 21:03:17 +03:00
if ( pref - > isAddTrackersEnabled ( ) & & ! torrent - > isPrivate ( ) )
torrent - > addTrackers ( m_additionalTrackers ) ;
2015-04-19 18:17:47 +03:00
bool addPaused = data . addPaused ;
if ( data . addPaused = = TriStateBool : : Undefined )
addPaused = pref - > addTorrentsInPause ( ) ;
// 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-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 )
{
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 " ;
2016-01-20 10:15:10 +03:00
# if LIBTORRENT_VERSION_NUM < 10100
boost : : system : : error_code ec ;
2015-04-19 18:17:47 +03:00
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 ) ;
2016-01-20 10:15:10 +03:00
# else
qDebug ( ) < < " Failed listening on " < < proto < < p - > listen_interface ( ) ;
Logger : : instance ( ) - > addMessage (
tr ( " qBittorrent failed listening on interface %1 [%2]. Reason: %3. " ,
" e.g: qBittorrent failed listening on interface 192.168.0.1 [TCP]. Reason: already in use. " )
. arg ( QString : : fromUtf8 ( p - > listen_interface ( ) ) )
. arg ( proto )
. arg ( Utils : : String : : fromStdString ( p - > error . message ( ) ) ) , Log : : CRITICAL ) ;
# endif
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
}
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 ;
}
buf = file . readAll ( ) ;
return true ;
}
2015-12-16 17:08:27 +03:00
bool loadTorrentResumeData ( const QByteArray & data , AddTorrentData & out , int & prio , MagnetUri & magnetUri )
2015-04-19 18:17:47 +03:00
{
out = AddTorrentData ( ) ;
out . resumed = true ;
2015-10-25 01:39:40 +03:00
out . skipChecking = false ;
2015-04-19 18:17:47 +03:00
libt : : lazy_entry fast ;
libt : : error_code ec ;
libt : : lazy_bdecode ( data . constData ( ) , data . constData ( ) + data . size ( ) , fast , ec ) ;
2016-01-01 16:17:10 +03:00
if ( ec | | ( fast . type ( ) ! = libt : : lazy_entry : : dict_t ) ) return false ;
2015-04-19 18:17:47 +03:00
2015-05-06 14:53:27 +03:00
out . savePath = Utils : : Fs : : fromNativePath ( Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-savePath " ) ) ) ;
2016-01-01 16:28:40 +03:00
if ( out . savePath . isEmpty ( ) ) {
Logger : : instance ( ) - > addMessage ( " Empty torrent save path was loaded from .fastresume file! Using default one... " , Log : : WARNING ) ;
out . savePath = Preferences : : instance ( ) - > getSavePath ( ) ;
}
2015-05-06 14:53:27 +03:00
out . ratioLimit = Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-ratioLimit " ) ) . toDouble ( ) ;
out . label = Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-label " ) ) ;
out . name = Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-name " ) ) ;
2015-04-19 18:17:47 +03:00
out . hasSeedStatus = fast . dict_find_int_value ( " qBt-seedStatus " ) ;
out . disableTempPath = fast . dict_find_int_value ( " qBt-tempPathDisabled " ) ;
2015-06-04 11:03:19 +03:00
magnetUri = MagnetUri ( Utils : : String : : fromStdString ( fast . dict_find_string_value ( " qBt-magnetUri " ) ) ) ;
out . addPaused = fast . dict_find_int_value ( " qBt-paused " ) ;
out . addForced = fast . dict_find_int_value ( " qBt-forced " ) ;
2015-12-16 17:08:27 +03:00
prio = fast . dict_find_int_value ( " qBt-queuePosition " ) ;
2015-04-19 18:17:47 +03:00
return true ;
}
void torrentQueuePositionUp ( const libt : : torrent_handle & handle )
{
try {
handle . queue_position_up ( ) ;
}
catch ( std : : exception & exc ) {
2015-10-17 17:41:53 +03:00
qDebug ( ) < < Q_FUNC_INFO < < " fails: " < < exc . what ( ) ;
2015-04-19 18:17:47 +03:00
}
}
void torrentQueuePositionDown ( const libt : : torrent_handle & handle )
{
try {
handle . queue_position_down ( ) ;
}
catch ( std : : exception & exc ) {
2015-10-17 17:41:53 +03:00
qDebug ( ) < < Q_FUNC_INFO < < " fails: " < < exc . what ( ) ;
2015-04-19 18:17:47 +03:00
}
}
void torrentQueuePositionTop ( const libt : : torrent_handle & handle )
{
try {
handle . queue_position_top ( ) ;
}
catch ( std : : exception & exc ) {
2015-10-17 17:41:53 +03:00
qDebug ( ) < < Q_FUNC_INFO < < " fails: " < < exc . what ( ) ;
2015-04-19 18:17:47 +03:00
}
}
void torrentQueuePositionBottom ( const libt : : torrent_handle & handle )
{
try {
handle . queue_position_bottom ( ) ;
}
catch ( std : : exception & exc ) {
2015-10-17 17:41:53 +03:00
qDebug ( ) < < Q_FUNC_INFO < < " fails: " < < exc . what ( ) ;
2015-04-19 18:17:47 +03:00
}
}