2003-10-23 01:00:57 +02:00
/*
Copyright ( c ) 2003 , Arvid Norberg
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
* Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in
the documentation and / or other materials provided with the distribution .
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE .
*/
2007-03-17 18:15:16 +01:00
# include "libtorrent/pch.hpp"
2003-10-23 01:00:57 +02:00
# include <ctime>
# include <algorithm>
# include <set>
# include <cctype>
2003-10-30 00:28:09 +01:00
# include <numeric>
2003-10-23 01:00:57 +02:00
2008-12-14 20:47:02 +01:00
# ifdef TORRENT_DEBUG
# include <iostream>
# endif
2004-01-25 19:18:36 +01:00
# ifdef _MSC_VER
# pragma warning(push, 1)
# endif
2004-08-05 15:56:26 +02:00
# include <boost/bind.hpp>
2003-10-23 01:00:57 +02:00
2004-01-25 19:18:36 +01:00
# ifdef _MSC_VER
# pragma warning(pop)
# endif
2009-09-06 02:57:01 +02:00
# include "libtorrent/config.hpp"
2003-10-26 18:35:23 +01:00
# include "libtorrent/torrent_handle.hpp"
2003-10-23 01:00:57 +02:00
# include "libtorrent/session.hpp"
# include "libtorrent/torrent_info.hpp"
2004-01-31 11:46:15 +01:00
# include "libtorrent/tracker_manager.hpp"
2008-05-17 16:19:34 +02:00
# include "libtorrent/parse_url.hpp"
2003-10-23 01:00:57 +02:00
# include "libtorrent/bencode.hpp"
# include "libtorrent/hasher.hpp"
# include "libtorrent/entry.hpp"
# include "libtorrent/peer.hpp"
2009-12-25 17:52:57 +01:00
# include "libtorrent/peer_connection.hpp"
2006-04-25 23:04:48 +02:00
# include "libtorrent/bt_peer_connection.hpp"
# include "libtorrent/web_peer_connection.hpp"
2008-12-30 04:54:07 +01:00
# include "libtorrent/http_seed_connection.hpp"
2003-10-23 01:00:57 +02:00
# include "libtorrent/peer_id.hpp"
2003-12-22 08:14:35 +01:00
# include "libtorrent/alert.hpp"
# include "libtorrent/identify_client.hpp"
2004-01-18 20:12:18 +01:00
# include "libtorrent/alert_types.hpp"
2006-11-14 01:08:16 +01:00
# include "libtorrent/extensions.hpp"
2006-10-11 16:02:21 +02:00
# include "libtorrent/aux_/session_impl.hpp"
2007-04-25 20:26:35 +02:00
# include "libtorrent/instantiate_connection.hpp"
2007-09-10 08:12:41 +02:00
# include "libtorrent/assert.hpp"
2008-12-26 08:00:21 +01:00
# include "libtorrent/broadcast_socket.hpp"
2009-05-03 22:21:24 +02:00
# include "libtorrent/kademlia/dht_tracker.hpp"
2009-11-26 06:45:43 +01:00
# include "libtorrent/peer_info.hpp"
2010-07-17 09:13:14 +02:00
# include "libtorrent/enum_net.hpp"
2010-12-30 02:47:30 +01:00
# include "libtorrent/http_connection.hpp"
# include "libtorrent/gzip.hpp" // for inflate_gzip
2011-02-26 08:55:51 +01:00
# include "libtorrent/random.hpp"
2003-10-23 01:00:57 +02:00
2010-10-12 10:57:43 +02:00
# ifdef TORRENT_USE_OPENSSL
# include "libtorrent/ssl_stream.hpp"
2011-08-28 23:06:15 +02:00
# include <boost/asio/ssl/context.hpp>
2011-08-29 02:59:42 +02:00
//#include <boost/asio/ssl/verify_context.hpp>
2010-10-12 10:57:43 +02:00
# endif
2011-09-21 11:27:07 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
# include "libtorrent/struct_debug.hpp"
# endif
2009-04-04 11:52:25 +02:00
# if TORRENT_USE_IOSTREAM
# include <iostream>
# endif
2003-10-23 01:00:57 +02:00
using namespace libtorrent ;
2006-01-07 14:48:14 +01:00
using boost : : tuples : : tuple ;
using boost : : tuples : : get ;
using boost : : tuples : : make_tuple ;
2006-10-11 16:02:21 +02:00
using libtorrent : : aux : : session_impl ;
2003-10-23 01:00:57 +02:00
namespace
{
2009-07-23 06:38:52 +02:00
size_type collect_free_download (
torrent : : peer_iterator start
, torrent : : peer_iterator end )
{
size_type accumulator = 0 ;
for ( torrent : : peer_iterator i = start ; i ! = end ; + + i )
{
// if the peer is interested in us, it means it may
// want to trade it's surplus uploads for downloads itself
// (and we should not consider it free). If the share diff is
// negative, there's no free download to get from this peer.
size_type diff = ( * i ) - > share_diff ( ) ;
TORRENT_ASSERT ( diff < ( std : : numeric_limits < size_type > : : max ) ( ) ) ;
if ( ( * i ) - > is_peer_interested ( ) | | diff < = 0 )
continue ;
TORRENT_ASSERT ( diff > 0 ) ;
( * i ) - > add_free_upload ( - diff ) ;
accumulator + = diff ;
TORRENT_ASSERT ( accumulator > 0 ) ;
}
TORRENT_ASSERT ( accumulator > = 0 ) ;
return accumulator ;
}
// returns the amount of free upload left after
// it has been distributed to the peers
2011-02-21 06:24:41 +01:00
boost : : uint32_t distribute_free_upload (
2009-07-23 06:38:52 +02:00
torrent : : peer_iterator start
, torrent : : peer_iterator end
, size_type free_upload )
{
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( free_upload > = 0 ) ;
if ( free_upload < = 0 ) return 0 ;
2009-07-23 06:38:52 +02:00
int num_peers = 0 ;
size_type total_diff = 0 ;
for ( torrent : : peer_iterator i = start ; i ! = end ; + + i )
{
size_type d = ( * i ) - > share_diff ( ) ;
TORRENT_ASSERT ( d < ( std : : numeric_limits < size_type > : : max ) ( ) ) ;
total_diff + = d ;
if ( ! ( * i ) - > is_peer_interested ( ) | | ( * i ) - > share_diff ( ) > = 0 ) continue ;
+ + num_peers ;
}
2011-02-21 06:24:41 +01:00
if ( num_peers = = 0 ) return boost : : uint32_t ( free_upload ) ;
2009-07-23 06:38:52 +02:00
size_type upload_share ;
if ( total_diff > = 0 )
{
upload_share = ( std : : min ) ( free_upload , total_diff ) / num_peers ;
}
else
{
upload_share = ( free_upload + total_diff ) / num_peers ;
}
2011-02-21 06:24:41 +01:00
if ( upload_share < 0 ) return boost : : uint32_t ( free_upload ) ;
2009-07-23 06:38:52 +02:00
for ( torrent : : peer_iterator i = start ; i ! = end ; + + i )
{
peer_connection * p = * i ;
if ( ! p - > is_peer_interested ( ) | | p - > share_diff ( ) > = 0 ) continue ;
p - > add_free_upload ( upload_share ) ;
free_upload - = upload_share ;
}
2011-02-21 06:24:41 +01:00
return ( std : : min ) ( free_upload , size_type ( UINT_MAX ) ) ;
2009-07-23 06:38:52 +02:00
}
2003-10-23 01:00:57 +02:00
2004-01-12 04:05:10 +01:00
struct find_peer_by_ip
{
2006-04-25 23:04:48 +02:00
find_peer_by_ip ( tcp : : endpoint const & a , const torrent * t )
2004-01-25 13:37:15 +01:00
: ip ( a )
, tor ( t )
2007-10-05 02:30:00 +02:00
{ TORRENT_ASSERT ( t ! = 0 ) ; }
2004-01-12 04:05:10 +01:00
2007-10-31 10:48:20 +01:00
bool operator ( ) ( session_impl : : connection_map : : value_type const & c ) const
2004-01-12 04:05:10 +01:00
{
2007-10-31 10:48:20 +01:00
tcp : : endpoint const & sender = c - > remote ( ) ;
2006-04-25 23:04:48 +02:00
if ( sender . address ( ) ! = ip . address ( ) ) return false ;
2007-10-31 10:48:20 +01:00
if ( tor ! = c - > associated_torrent ( ) . lock ( ) . get ( ) ) return false ;
2004-01-12 04:05:10 +01:00
return true ;
}
2006-04-25 23:04:48 +02:00
tcp : : endpoint const & ip ;
torrent const * tor ;
2004-01-12 04:05:10 +01:00
} ;
2004-01-13 04:08:59 +01:00
struct peer_by_id
{
2006-04-25 23:04:48 +02:00
peer_by_id ( const peer_id & i ) : pid ( i ) { }
2004-01-13 04:08:59 +01:00
2007-10-31 10:48:20 +01:00
bool operator ( ) ( session_impl : : connection_map : : value_type const & p ) const
2004-01-13 04:08:59 +01:00
{
2007-10-31 10:48:20 +01:00
if ( p - > pid ( ) ! = pid ) return false ;
2004-01-13 04:08:59 +01:00
// have a special case for all zeros. We can have any number
2006-04-25 23:04:48 +02:00
// of peers with that pid, since it's used to indicate no pid.
2009-08-30 09:38:52 +02:00
if ( pid . is_all_zeros ( ) ) return false ;
2004-01-13 04:08:59 +01:00
return true ;
}
2006-04-25 23:04:48 +02:00
peer_id const & pid ;
2004-01-13 04:08:59 +01:00
} ;
2003-10-23 01:00:57 +02:00
}
namespace libtorrent
{
2007-06-10 22:46:09 +02:00
2010-02-08 05:51:34 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
void torrent : : print_size ( logger & l )
{
2011-09-21 11:27:07 +02:00
char tmp [ 300 ] ;
2010-02-14 02:39:55 +01:00
int temp = 0 ;
2011-09-21 11:27:07 +02:00
int prev_size = 0 ;
2010-02-08 05:51:34 +01:00
PRINT_SIZEOF ( torrent )
2010-02-14 02:39:55 +01:00
2011-09-21 11:27:07 +02:00
PRINT_OFFSETOF ( torrent , m_tracker_address )
PRINT_OFFSETOF ( torrent , m_manager )
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_policy )
PRINT_OFFSETOF ( torrent , m_total_uploaded )
PRINT_OFFSETOF ( torrent , m_total_downloaded )
PRINT_OFFSETOF ( torrent , m_started )
PRINT_OFFSETOF ( torrent , m_torrent_file )
PRINT_OFFSETOF ( torrent , m_owning_storage )
PRINT_OFFSETOF ( torrent , m_storage )
PRINT_OFFSETOF ( torrent , m_connections )
PRINT_OFFSETOF ( torrent , m_web_seeds )
2011-09-23 07:12:29 +02:00
# ifndef TORRENT_DISABLE_EXTENSIONS
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_extensions )
2011-09-23 07:12:29 +02:00
# endif
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_tracker_timer )
PRINT_OFFSETOF ( torrent , m_stat )
2010-03-21 18:41:17 +01:00
// some compilers don't like using offsetof on references it seems
2011-09-23 07:12:29 +02:00
# ifndef _MSC_VER
PRINT_OFFSETOF ( torrent , m_ses )
# endif
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_file_priority )
PRINT_OFFSETOF ( torrent , m_file_progress )
PRINT_OFFSETOF ( torrent , m_picker )
PRINT_OFFSETOF ( torrent , m_trackers )
PRINT_OFFSETOF ( torrent , m_time_critical_pieces )
PRINT_OFFSETOF ( torrent , m_username )
PRINT_OFFSETOF ( torrent , m_password )
2010-07-17 09:13:14 +02:00
PRINT_OFFSETOF ( torrent , m_net_interfaces )
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_save_path )
2011-09-21 11:27:07 +02:00
PRINT_OFFSETOF ( torrent , m_url )
PRINT_OFFSETOF ( torrent , m_uuid )
PRINT_OFFSETOF ( torrent , m_source_feed_url )
PRINT_OFFSETOF ( torrent , m_torrent_file_buf )
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_verified )
PRINT_OFFSETOF ( torrent , m_error )
PRINT_OFFSETOF ( torrent , m_error_file )
PRINT_OFFSETOF ( torrent , m_resume_data )
PRINT_OFFSETOF ( torrent , m_resume_entry )
PRINT_OFFSETOF ( torrent , m_name )
PRINT_OFFSETOF ( torrent , m_storage_constructor )
2011-09-22 12:37:47 +02:00
PRINT_OFFSETOF ( torrent , m_added_time )
PRINT_OFFSETOF ( torrent , m_completed_time )
PRINT_OFFSETOF ( torrent , m_last_seen_complete )
PRINT_OFFSETOF ( torrent , m_last_saved_resume )
2011-08-21 04:04:14 +02:00
# ifndef TORRENT_DISABLE_ENCRYPTION
2010-02-14 02:39:55 +01:00
PRINT_OFFSETOF ( torrent , m_obfuscated_hash )
2011-08-21 04:04:14 +02:00
# endif
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_ratio )
2010-02-14 02:39:55 +01:00
PRINT_OFFSETOF ( torrent , m_available_free_upload )
PRINT_OFFSETOF ( torrent , m_average_piece_time )
PRINT_OFFSETOF ( torrent , m_piece_time_deviation )
PRINT_OFFSETOF ( torrent , m_total_failed_bytes )
PRINT_OFFSETOF ( torrent , m_total_redundant_bytes )
// PRINT_OFFSETOF(torrent, m_upload_mode_time:24)
// PRINT_OFFSETOF(torrent, m_state:3)
// PRINT_OFFSETOF(torrent, m_storage_mode:2)
// PRINT_OFFSETOF(torrent, m_announcing:1)
// PRINT_OFFSETOF(torrent, m_waiting_tracker:1)
// PRINT_OFFSETOF(torrent, m_seed_mode:1)
// PRINT_OFFSETOF(torrent, m_active_time:24)
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_last_working_tracker )
2010-02-14 02:39:55 +01:00
// PRINT_OFFSETOF(torrent, m_finished_time:24)
// PRINT_OFFSETOF(torrent, m_sequential_download:1)
// PRINT_OFFSETOF(torrent, m_got_tracker_response:1)
// PRINT_OFFSETOF(torrent, m_connections_initialized:1)
// PRINT_OFFSETOF(torrent, m_super_seeding:1)
// PRINT_OFFSETOF(torrent, m_override_resume_data:1)
// PRINT_OFFSETOF(torrent, m_resolving_country:1)
// PRINT_OFFSETOF(torrent, m_resolve_countries:1)
2010-04-13 04:29:13 +02:00
// PRINT_OFFSETOF(torrent, m_need_save_resume_data:1)
2010-02-14 02:39:55 +01:00
// PRINT_OFFSETOF(torrent, m_seeding_time:24)
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_time_scaler )
2010-02-14 02:39:55 +01:00
// PRINT_OFFSETOF(torrent, m_max_uploads:24)
PRINT_OFFSETOF ( torrent , m_deficit_counter )
// PRINT_OFFSETOF(torrent, m_num_uploads:24)
// PRINT_OFFSETOF(torrent, m_block_size_shift:5)
// PRINT_OFFSETOF(torrent, m_has_incoming:1)
// PRINT_OFFSETOF(torrent, m_files_checked:1)
// PRINT_OFFSETOF(torrent, m_queued_for_checking:1)
// PRINT_OFFSETOF(torrent, m_max_connections:24)
// PRINT_OFFSETOF(torrent, m_padding:24)
PRINT_OFFSETOF ( torrent , m_sequence_number )
// PRINT_OFFSETOF(torrent, m_complete:24)
2010-02-08 05:51:34 +01:00
PRINT_OFFSETOF ( torrent , m_priority )
2010-02-14 02:39:55 +01:00
// PRINT_OFFSETOF(torrent, m_incomplete:24)
// PRINT_OFFSETOF(torrent, m_progress_ppm:20)
// PRINT_OFFSETOF(torrent, m_abort:1)
2010-03-29 02:34:04 +02:00
// PRINT_OFFSETOF(torrent, m_announce_to_dht:1)
// PRINT_OFFSETOF(torrent, m_announce_to_trackers:1)
// PRINT_OFFSETOF(torrent, m_announce_to_lsd:1)
// PRINT_OFFSETOF(torrent, m_allow_peers:1)
2010-02-14 02:39:55 +01:00
// PRINT_OFFSETOF(torrent, m_upload_mode:1)
// PRINT_OFFSETOF(torrent, m_auto_managed:1)
PRINT_OFFSETOF ( torrent , m_num_verified )
PRINT_OFFSETOF ( torrent , m_last_scrape )
2010-02-08 05:51:34 +01:00
}
# undef PRINT_SIZEOF
# undef PRINT_OFFSETOF
# endif
2010-02-14 02:39:55 +01:00
int root2 ( int x )
{
int ret = 0 ;
x > > = 1 ;
while ( x > 0 )
{
// if this assert triggers, the block size
// is not an even 2 exponent!
TORRENT_ASSERT ( x = = 1 | | ( x & 1 ) = = 0 ) ;
+ + ret ;
x > > = 1 ;
}
return ret ;
}
2011-01-29 13:13:49 +01:00
# ifndef TORRENT_DISABLE_EXTENSIONS
2010-11-29 02:33:05 +01:00
// defined in ut_pex.cpp
bool was_introduced_by ( peer_plugin const * , tcp : : endpoint const & ) ;
2011-01-29 13:13:49 +01:00
# endif
2010-11-29 02:33:05 +01:00
2003-12-07 06:53:04 +01:00
torrent : : torrent (
2006-10-11 16:02:21 +02:00
session_impl & ses
2006-04-25 23:04:48 +02:00
, tcp : : endpoint const & net_interface
, int block_size
2008-04-24 05:28:48 +02:00
, int seq
2010-12-30 02:47:30 +01:00
, add_torrent_params const & p
, sha1_hash const & info_hash )
2008-05-19 04:52:32 +02:00
: m_policy ( this )
, m_total_uploaded ( 0 )
, m_total_downloaded ( 0 )
, m_started ( time_now ( ) )
2004-06-14 01:30:42 +02:00
, m_storage ( 0 )
2008-07-12 10:25:19 +02:00
, m_tracker_timer ( ses . m_io_service )
2003-10-23 01:00:57 +02:00
, m_ses ( ses )
2010-11-18 06:51:52 +01:00
, m_trackerid ( p . trackerid )
2010-12-30 02:47:30 +01:00
, m_save_path ( complete ( p . save_path ) )
, m_url ( p . url )
2011-01-18 04:41:54 +01:00
, m_uuid ( p . uuid )
, m_source_feed_url ( p . source_feed_url )
2009-02-03 08:46:24 +01:00
, m_storage_constructor ( p . storage )
2011-09-22 12:37:47 +02:00
, m_added_time ( time ( 0 ) )
, m_completed_time ( 0 )
, m_last_seen_complete ( 0 )
, m_last_saved_resume ( time ( 0 ) )
2008-05-19 04:52:32 +02:00
, m_ratio ( 0.f )
2010-02-14 02:39:55 +01:00
, m_available_free_upload ( 0 )
, m_average_piece_time ( 0 )
, m_piece_time_deviation ( 0 )
, m_total_failed_bytes ( 0 )
, m_total_redundant_bytes ( 0 )
2011-12-23 20:30:23 +01:00
, m_sequence_number ( seq )
2010-02-14 02:39:55 +01:00
, m_upload_mode_time ( 0 )
, m_state ( torrent_status : : checking_resume_data )
, m_storage_mode ( p . storage_mode )
, m_announcing ( false )
, m_waiting_tracker ( false )
2011-02-26 08:48:05 +01:00
, m_seed_mode ( false )
2010-02-14 02:39:55 +01:00
, m_active_time ( 0 )
2008-05-19 04:52:32 +02:00
, m_last_working_tracker ( - 1 )
2010-02-14 02:39:55 +01:00
, m_finished_time ( 0 )
2008-05-19 04:52:32 +02:00
, m_sequential_download ( false )
, m_got_tracker_response ( false )
2011-02-26 08:48:05 +01:00
, m_connections_initialized ( false )
2008-12-08 07:36:22 +01:00
, m_super_seeding ( false )
2011-11-08 06:36:22 +01:00
, m_override_resume_data ( p . flags & add_torrent_params : : flag_override_resume_data )
2010-02-14 02:39:55 +01:00
# ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
, m_resolving_country ( false )
, m_resolve_countries ( false )
# endif
2010-04-13 04:29:13 +02:00
, m_need_save_resume_data ( true )
2010-02-14 02:39:55 +01:00
, m_seeding_time ( 0 )
, m_time_scaler ( 0 )
, m_max_uploads ( ~ 0 )
, m_deficit_counter ( 0 )
, m_num_uploads ( 0 )
2011-02-26 08:48:05 +01:00
, m_block_size_shift ( root2 ( block_size ) )
2008-06-05 20:19:03 +02:00
, m_has_incoming ( false )
2008-06-07 18:24:56 +02:00
, m_files_checked ( false )
2009-02-08 02:29:09 +01:00
, m_queued_for_checking ( false )
2010-02-14 02:39:55 +01:00
, m_max_connections ( ~ 0 )
, m_padding ( 0 )
2010-03-21 19:15:04 +01:00
, m_complete ( 0xffffff )
2010-02-14 02:39:55 +01:00
, m_priority ( 0 )
2010-03-21 19:15:04 +01:00
, m_incomplete ( 0xffffff )
2010-02-14 02:39:55 +01:00
, m_progress_ppm ( 0 )
, m_abort ( false )
2011-11-08 06:36:22 +01:00
, m_announce_to_dht ( ( p . flags & add_torrent_params : : flag_paused ) = = 0 )
, m_announce_to_trackers ( ( p . flags & add_torrent_params : : flag_paused ) = = 0 )
, m_announce_to_lsd ( ( p . flags & add_torrent_params : : flag_paused ) = = 0 )
, m_allow_peers ( ( p . flags & add_torrent_params : : flag_paused ) = = 0 )
, m_upload_mode ( p . flags & add_torrent_params : : flag_upload_mode )
, m_auto_managed ( p . flags & add_torrent_params : : flag_auto_managed )
, m_share_mode ( p . flags & add_torrent_params : : flag_share_mode )
2010-02-14 02:39:55 +01:00
, m_num_verified ( 0 )
, m_last_scrape ( 0 )
2010-07-08 21:29:38 +02:00
, m_last_download ( 0 )
, m_last_upload ( 0 )
2010-09-06 06:02:15 +02:00
, m_downloaders ( 0xffffff )
2010-07-17 09:13:14 +02:00
, m_interface_index ( 0 )
2011-02-26 08:48:05 +01:00
, m_save_resume_flags ( 0 )
2010-10-30 10:36:18 +02:00
, m_graceful_pause_mode ( false )
2010-12-17 04:10:56 +01:00
, m_need_connect_boost ( true )
2011-02-16 11:16:52 +01:00
, m_lsd_seq ( 0 )
2011-02-26 08:48:05 +01:00
, m_magnet_link ( false )
2011-11-08 06:36:22 +01:00
, m_apply_ip_filter ( p . flags & add_torrent_params : : flag_apply_ip_filter )
, m_merge_resume_trackers ( p . flags & add_torrent_params : : flag_merge_resume_trackers )
2011-09-05 07:50:41 +02:00
, m_in_encrypted_list ( false )
2011-11-15 03:34:00 +01:00
, m_state_subscription ( p . flags & add_torrent_params : : flag_update_subscribe )
, m_in_state_updates ( false )
2003-10-23 01:00:57 +02:00
{
2011-07-05 06:05:12 +02:00
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
2011-06-05 22:48:00 +02:00
m_resume_data_loaded = false ;
# endif
2011-03-02 18:37:10 +01:00
if ( ! m_apply_ip_filter ) + + m_ses . m_non_filtered_torrents ;
2011-02-26 08:48:05 +01:00
if ( ! p . ti | | ! p . ti - > is_valid ( ) )
{
// we don't have metadata for this torrent. We'll download
// it either through the URL passed in, or through a metadata
// extension. Make sure that when we save resume data for this
// torrent, we also save the metadata
m_magnet_link = true ;
// did the user provide resume data?
// maybe the metadata is in there
if ( p . resume_data )
{
int pos ;
error_code ec ;
lazy_entry tmp ;
lazy_entry const * info = 0 ;
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " adding magnet link with resume data \n " ;
# endif
if ( lazy_bdecode ( & ( * p . resume_data ) [ 0 ] , & ( * p . resume_data ) [ 0 ]
+ p . resume_data - > size ( ) , tmp , ec , & pos ) = = 0
& & tmp . type ( ) = = lazy_entry : : dict_t
& & ( info = tmp . dict_find_dict ( " info " ) ) )
{
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " found metadata in resume data \n " ;
# endif
// verify the info-hash of the metadata stored in the resume file matches
// the torrent we're loading
std : : pair < char const * , int > buf = info - > data_section ( ) ;
sha1_hash resume_ih = hasher ( buf . first , buf . second ) . final ( ) ;
// if url is set, the info_hash is not actually the info-hash of the
// torrent, but the hash of the URL, until we have the full torrent
if ( resume_ih = = info_hash | | ! p . url . empty ( ) )
{
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " info-hash matched \n " ;
# endif
m_torrent_file = ( p . ti ? p . ti : new torrent_info ( resume_ih ) ) ;
if ( ! m_torrent_file - > parse_info_section ( * info , ec , 0 ) )
{
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " failed to load metadata from resume file: "
< < ec . message ( ) < < " \n " ;
# endif
}
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
else
{
( * m_ses . m_logger ) < < time_now_string ( ) < < " successfully loaded metadata from resume file \n " ;
}
# endif
}
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
else
{
( * m_ses . m_logger ) < < time_now_string ( ) < < " metadata info-hash failed \n " ;
}
# endif
}
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
else
{
( * m_ses . m_logger ) < < time_now_string ( ) < < " no metadata found \n " ;
}
# endif
}
}
if ( ! m_torrent_file )
m_torrent_file = ( p . ti ? p . ti : new torrent_info ( info_hash ) ) ;
m_trackers = m_torrent_file - > trackers ( ) ;
if ( m_torrent_file - > is_valid ( ) )
{
2011-11-08 06:36:22 +01:00
m_seed_mode = p . flags & add_torrent_params : : flag_seed_mode ;
2011-02-26 08:48:05 +01:00
m_connections_initialized = true ;
m_block_size_shift = root2 ( ( std : : min ) ( block_size , m_torrent_file - > piece_length ( ) ) ) ;
}
else
{
if ( p . name ) m_name . reset ( new std : : string ( p . name ) ) ;
}
2011-01-18 04:41:54 +01:00
if ( ! m_url . empty ( ) & & m_uuid . empty ( ) ) m_uuid = m_url ;
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-10-17 20:36:37 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " creating torrent: "
< < torrent_file ( ) . name ( ) < < " \n " ;
# endif
2010-07-17 20:32:06 +02:00
m_net_interfaces . push_back ( tcp : : endpoint ( net_interface . address ( ) , 0 ) ) ;
2010-07-17 09:13:14 +02:00
2010-07-15 03:14:36 +02:00
if ( p . file_priorities )
m_file_priority = * p . file_priorities ;
2009-02-03 08:46:24 +01:00
if ( m_seed_mode )
m_verified . resize ( m_torrent_file - > num_pieces ( ) , false ) ;
if ( p . resume_data ) m_resume_data . swap ( * p . resume_data ) ;
2008-08-21 01:05:12 +02:00
# ifndef TORRENT_DISABLE_ENCRYPTION
hasher h ;
h . update ( " req2 " , 4 ) ;
2009-02-03 08:46:24 +01:00
h . update ( ( char * ) & m_torrent_file - > info_hash ( ) [ 0 ] , 20 ) ;
2008-08-21 01:05:12 +02:00
m_obfuscated_hash = h . final ( ) ;
# endif
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2007-12-14 07:09:44 +01:00
m_files_checked = false ;
# endif
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2010-12-30 02:47:30 +01:00
if ( ! m_name & & ! m_url . empty ( ) ) m_name . reset ( new std : : string ( m_url ) ) ;
2006-11-14 01:08:16 +01:00
2009-04-26 21:16:55 +02:00
if ( p . tracker_url & & std : : strlen ( p . tracker_url ) > 0 )
2007-02-21 18:15:47 +01:00
{
2009-02-03 08:46:24 +01:00
m_trackers . push_back ( announce_entry ( p . tracker_url ) ) ;
2008-11-27 21:51:59 +01:00
m_trackers . back ( ) . fail_limit = 0 ;
2008-11-29 09:38:40 +01:00
m_trackers . back ( ) . source = announce_entry : : source_magnet_link ;
2009-02-03 08:46:24 +01:00
m_torrent_file - > add_tracker ( p . tracker_url ) ;
2007-02-21 18:15:47 +01:00
}
2011-03-07 04:51:52 +01:00
if ( settings ( ) . prefer_udp_trackers )
prioritize_udp_trackers ( ) ;
2007-04-11 19:44:15 +02:00
}
2007-04-11 19:22:19 +02:00
2011-01-18 04:41:54 +01:00
# if 1
// NON BOTTLED VERSION. SUPPORTS PROGRESS REPORTING
2010-12-30 02:47:30 +01:00
// since this download is not bottled, this callback will
// be called every time we receive another piece of the
// .torrent file
void torrent : : on_torrent_download ( error_code const & ec
, http_parser const & parser
, char const * data , int size )
{
2010-12-31 00:09:16 +01:00
if ( m_abort ) return ;
2010-12-30 02:47:30 +01:00
if ( ec & & ec ! = asio : : error : : eof )
{
set_error ( ec , m_url ) ;
pause ( ) ;
return ;
}
2010-12-31 00:09:16 +01:00
2010-12-30 02:47:30 +01:00
if ( size > 0 )
{
m_torrent_file_buf . insert ( m_torrent_file_buf . end ( ) , data , data + size ) ;
if ( parser . content_length ( ) > 0 )
set_progress_ppm ( boost : : int64_t ( m_torrent_file_buf . size ( ) )
* 1000000 / parser . content_length ( ) ) ;
}
2010-12-31 00:09:16 +01:00
if ( parser . header_finished ( ) & & parser . status_code ( ) ! = 200 )
{
2011-01-16 03:54:59 +01:00
set_error ( error_code ( parser . status_code ( ) , get_http_category ( ) ) , parser . message ( ) ) ;
2010-12-31 00:09:16 +01:00
pause ( ) ;
return ;
}
2010-12-30 02:47:30 +01:00
if ( ! ec ) return ;
std : : string const & encoding = parser . header ( " content-encoding " ) ;
if ( ( encoding = = " gzip " | | encoding = = " x-gzip " ) & & m_torrent_file_buf . size ( ) )
{
std : : vector < char > buf ;
std : : string error ;
if ( inflate_gzip ( & m_torrent_file_buf [ 0 ] , m_torrent_file_buf . size ( )
, buf , 4 * 1024 * 1024 , error ) )
{
set_error ( errors : : http_failed_decompress , m_url ) ;
pause ( ) ;
std : : vector < char > ( ) . swap ( m_torrent_file_buf ) ;
return ;
}
m_torrent_file_buf . swap ( buf ) ;
}
// we're done!
error_code e ;
intrusive_ptr < torrent_info > tf ( new torrent_info (
& m_torrent_file_buf [ 0 ] , m_torrent_file_buf . size ( ) , e ) ) ;
if ( e )
{
set_error ( e , m_url ) ;
pause ( ) ;
std : : vector < char > ( ) . swap ( m_torrent_file_buf ) ;
return ;
}
std : : vector < char > ( ) . swap ( m_torrent_file_buf ) ;
// update our torrent_info object and move the
// torrent from the old info-hash to the new one
// as we replace the torrent_info object
2011-05-08 11:04:59 +02:00
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
2010-12-30 02:47:30 +01:00
int num_torrents = m_ses . m_torrents . size ( ) ;
# endif
2011-03-23 03:46:22 +01:00
// we're about to erase the session's reference to this
// torrent, create another reference
boost : : shared_ptr < torrent > me ( shared_from_this ( ) ) ;
m_ses . remove_torrent_impl ( me , 0 ) ;
2010-12-30 02:47:30 +01:00
m_torrent_file = tf ;
2011-03-23 03:46:22 +01:00
// now, we might already have this torrent in the session.
session_impl : : torrent_map : : iterator i = m_ses . m_torrents . find ( m_torrent_file - > info_hash ( ) ) ;
if ( i ! = m_ses . m_torrents . end ( ) )
{
2011-06-09 07:46:47 +02:00
if ( ! m_uuid . empty ( ) & & i - > second - > uuid ( ) . empty ( ) )
i - > second - > set_uuid ( m_uuid ) ;
if ( ! m_url . empty ( ) & & i - > second - > url ( ) . empty ( ) )
i - > second - > set_url ( m_url ) ;
if ( ! m_source_feed_url . empty ( ) & & i - > second - > source_feed_url ( ) . empty ( ) )
i - > second - > set_source_feed_url ( m_source_feed_url ) ;
// insert this torrent in the uuid index
if ( ! m_uuid . empty ( ) | | ! m_url . empty ( ) )
{
m_ses . m_uuids . insert ( std : : make_pair ( m_uuid . empty ( )
? m_url : m_uuid , i - > second ) ) ;
}
set_error ( error_code ( errors : : duplicate_torrent , get_libtorrent_category ( ) ) , " " ) ;
abort ( ) ;
return ;
2011-03-23 03:46:22 +01:00
}
m_ses . m_torrents . insert ( std : : make_pair ( m_torrent_file - > info_hash ( ) , me ) ) ;
if ( ! m_uuid . empty ( ) ) m_ses . m_uuids . insert ( std : : make_pair ( m_uuid , me ) ) ;
2010-12-30 02:47:30 +01:00
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( num_torrents = = int ( m_ses . m_torrents . size ( ) ) ) ;
2010-12-30 02:47:30 +01:00
2011-01-18 04:41:54 +01:00
// if the user added any trackers while downloading the
// .torrent file, serge them into the new tracker list
std : : vector < announce_entry > new_trackers = m_torrent_file - > trackers ( ) ;
for ( std : : vector < announce_entry > : : iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
{
// if we already have this tracker, ignore it
if ( std : : find_if ( new_trackers . begin ( ) , new_trackers . end ( )
, boost : : bind ( & announce_entry : : url , _1 ) = = i - > url ) ! = new_trackers . end ( ) )
continue ;
// insert the tracker ordered by tier
new_trackers . insert ( std : : find_if ( new_trackers . begin ( ) , new_trackers . end ( )
, boost : : bind ( & announce_entry : : tier , _1 ) > = i - > tier ) , * i ) ;
}
m_trackers . swap ( new_trackers ) ;
# ifndef TORRENT_DISABLE_ENCRYPTION
hasher h ;
h . update ( " req2 " , 4 ) ;
h . update ( ( char * ) & m_torrent_file - > info_hash ( ) [ 0 ] , 20 ) ;
m_obfuscated_hash = h . final ( ) ;
# endif
if ( m_ses . m_alerts . should_post < metadata_received_alert > ( ) )
{
m_ses . m_alerts . post_alert ( metadata_received_alert (
get_handle ( ) ) ) ;
}
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2011-01-18 04:41:54 +01:00
set_state ( torrent_status : : downloading ) ;
m_override_resume_data = true ;
init ( ) ;
announce_with_tracker ( ) ;
}
# else
void torrent : : on_torrent_download ( error_code const & ec
, http_parser const & parser , char const * data , int size )
{
if ( m_abort ) return ;
if ( ec & & ec ! = asio : : error : : eof )
{
set_error ( ec , m_url ) ;
pause ( ) ;
return ;
}
if ( parser . status_code ( ) ! = 200 )
{
// #error there should really be an error code category for HTTP
set_error ( errors : : http_error , parser . message ( ) ) ;
pause ( ) ;
return ;
}
error_code e ;
intrusive_ptr < torrent_info > tf ( new torrent_info ( data , size , e ) ) ;
if ( e )
{
set_error ( e , m_url ) ;
pause ( ) ;
return ;
}
// update our torrent_info object and move the
// torrent from the old info-hash to the new one
// as we replace the torrent_info object
2011-05-08 11:04:59 +02:00
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
2011-01-18 04:41:54 +01:00
int num_torrents = m_ses . m_torrents . size ( ) ;
# endif
m_ses . m_torrents . erase ( m_torrent_file - > info_hash ( ) ) ;
m_torrent_file = tf ;
m_ses . m_torrents . insert ( std : : make_pair ( m_torrent_file - > info_hash ( ) , shared_from_this ( ) ) ) ;
TORRENT_ASSERT ( num_torrents = = m_ses . m_torrents . size ( ) ) ;
2010-12-30 02:47:30 +01:00
// TODO: if the user added any trackers while downloading the
// .torrent file, they are overwritten. Merge them into the
// new tracker list
m_trackers = m_torrent_file - > trackers ( ) ;
# ifndef TORRENT_DISABLE_ENCRYPTION
hasher h ;
h . update ( " req2 " , 4 ) ;
h . update ( ( char * ) & m_torrent_file - > info_hash ( ) [ 0 ] , 20 ) ;
m_obfuscated_hash = h . final ( ) ;
# endif
if ( m_ses . m_alerts . should_post < metadata_received_alert > ( ) )
{
m_ses . m_alerts . post_alert ( metadata_received_alert (
get_handle ( ) ) ) ;
}
set_state ( torrent_status : : downloading ) ;
m_override_resume_data = true ;
init ( ) ;
announce_with_tracker ( ) ;
}
2011-01-18 04:41:54 +01:00
# endif
2008-09-21 04:08:04 +02:00
void torrent : : start ( )
2008-07-01 01:14:31 +02:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-10-17 20:36:37 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " starting torrent: "
< < torrent_file ( ) . name ( ) < < " \n " ;
# endif
2008-11-12 04:30:19 +01:00
TORRENT_ASSERT ( ! m_picker ) ;
2009-02-03 08:46:24 +01:00
if ( ! m_seed_mode )
2008-07-01 01:14:31 +02:00
{
2009-02-03 08:46:24 +01:00
m_picker . reset ( new piece_picker ( ) ) ;
2009-07-04 06:58:24 +02:00
std : : fill ( m_file_progress . begin ( ) , m_file_progress . end ( ) , 0 ) ;
2009-02-03 08:46:24 +01:00
if ( ! m_resume_data . empty ( ) )
2008-07-01 01:14:31 +02:00
{
2010-10-28 06:01:59 +02:00
int pos ;
error_code ec ;
2009-02-03 08:46:24 +01:00
if ( lazy_bdecode ( & m_resume_data [ 0 ] , & m_resume_data [ 0 ]
2010-10-28 06:01:59 +02:00
+ m_resume_data . size ( ) , m_resume_entry , ec , & pos ) ! = 0 )
2008-09-21 04:08:04 +02:00
{
2009-02-03 08:46:24 +01:00
std : : vector < char > ( ) . swap ( m_resume_data ) ;
2010-10-28 06:01:59 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " fastresume data for "
< < torrent_file ( ) . name ( ) < < " rejected: " < < ec . message ( )
< < " pos: " < < pos < < " \n " ;
# endif
2009-02-03 08:46:24 +01:00
if ( m_ses . m_alerts . should_post < fastresume_rejected_alert > ( ) )
{
2009-06-12 18:40:38 +02:00
m_ses . m_alerts . post_alert ( fastresume_rejected_alert ( get_handle ( ) , ec ) ) ;
2009-02-03 08:46:24 +01:00
}
2008-09-21 04:08:04 +02:00
}
2008-07-01 01:14:31 +02:00
}
}
2010-12-30 02:47:30 +01:00
if ( ! m_torrent_file - > is_valid ( ) & & ! m_url . empty ( ) )
2008-11-10 05:17:16 +01:00
{
2010-12-30 02:47:30 +01:00
// we need to download the .torrent file from m_url
start_download_url ( ) ;
}
else if ( m_torrent_file - > is_valid ( ) )
{
2008-11-10 05:17:16 +01:00
init ( ) ;
}
2008-08-29 19:21:56 +02:00
else
{
2011-06-08 10:45:28 +02:00
// we need to start announcing since we don't have any
// metadata. To receive peers to ask for it.
2008-08-29 19:21:56 +02:00
set_state ( torrent_status : : downloading_metadata ) ;
2010-06-17 19:01:28 +02:00
start_announcing ( ) ;
2008-08-29 19:21:56 +02:00
}
2003-10-23 01:00:57 +02:00
}
2010-12-30 02:47:30 +01:00
void torrent : : start_download_url ( )
{
TORRENT_ASSERT ( ! m_url . empty ( ) ) ;
TORRENT_ASSERT ( ! m_torrent_file - > is_valid ( ) ) ;
boost : : shared_ptr < http_connection > conn (
new http_connection ( m_ses . m_io_service , m_ses . m_half_open
, boost : : bind ( & torrent : : on_torrent_download , shared_from_this ( )
, _1 , _2 , _3 , _4 ) , false ) ) ;
2010-12-31 00:09:16 +01:00
conn - > get ( m_url , seconds ( 30 ) , 0 , 0 , 5 , m_ses . m_settings . user_agent ) ;
2010-12-30 02:47:30 +01:00
set_state ( torrent_status : : downloading_metadata ) ;
}
2011-02-27 18:26:57 +01:00
void torrent : : set_apply_ip_filter ( bool b )
{
if ( b = = m_apply_ip_filter ) return ;
2011-03-02 18:37:10 +01:00
if ( b )
{
TORRENT_ASSERT ( m_ses . m_non_filtered_torrents > 0 ) ;
- - m_ses . m_non_filtered_torrents ;
}
else
{
+ + m_ses . m_non_filtered_torrents ;
}
2011-02-27 18:26:57 +01:00
m_apply_ip_filter = b ;
m_policy . ip_filter_updated ( ) ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2011-02-27 18:26:57 +01:00
}
2007-02-12 10:20:49 +01:00
# ifndef TORRENT_DISABLE_DHT
bool torrent : : should_announce_dht ( ) const
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-11-25 10:33:26 +01:00
if ( m_ses . m_listen_sockets . empty ( ) ) return false ;
if ( ! m_ses . m_dht ) return false ;
2008-08-30 00:58:47 +02:00
if ( m_torrent_file - > is_valid ( ) & & ! m_files_checked ) return false ;
2010-03-29 02:34:04 +02:00
if ( ! m_announce_to_dht ) return false ;
2011-01-16 03:56:57 +01:00
if ( ! m_allow_peers ) return false ;
// if we don't have the metadata, and we're waiting
// for a web server to serve it to us, no need to announce
// because the info-hash is just the URL hash
if ( ! m_torrent_file - > is_valid ( ) & & ! m_url . empty ( ) ) return false ;
2007-11-25 10:33:26 +01:00
2007-02-12 10:20:49 +01:00
// don't announce private torrents
2007-09-01 05:00:31 +02:00
if ( m_torrent_file - > is_valid ( ) & & m_torrent_file - > priv ( ) ) return false ;
2007-02-12 10:20:49 +01:00
if ( m_trackers . empty ( ) ) return true ;
2010-02-14 02:39:55 +01:00
if ( ! settings ( ) . use_dht_as_fallback ) return true ;
2008-11-29 09:38:40 +01:00
int verified_trackers = 0 ;
for ( std : : vector < announce_entry > : : const_iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
if ( i - > verified ) + + verified_trackers ;
2007-02-12 10:20:49 +01:00
2009-07-18 18:50:56 +02:00
return verified_trackers = = 0 ;
2007-02-12 10:20:49 +01:00
}
2009-10-25 03:37:45 +01:00
2007-02-12 10:20:49 +01:00
# endif
2003-12-14 06:56:12 +01:00
torrent : : ~ torrent ( )
{
2011-03-03 04:57:47 +01:00
if ( ! m_apply_ip_filter )
{
TORRENT_ASSERT ( m_ses . m_non_filtered_torrents > 0 ) ;
- - m_ses . m_non_filtered_torrents ;
m_apply_ip_filter = true ;
}
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-05-28 21:03:54 +02:00
// The invariant can't be maintained here, since the torrent
// is being destructed, all weak references to it have been
// reset, which means that all its peers already have an
// invalidated torrent pointer (so it cannot be verified to be correct)
// i.e. the invariant can only be maintained if all connections have
// been closed by the time the torrent is destructed. And they are
// supposed to be closed. So we can still do the invariant check.
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_connections . empty ( ) ) ;
2006-05-28 21:03:54 +02:00
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2010-08-18 19:14:40 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING
log_to_all_peers ( " DESTRUCTING TORRENT " ) ;
2007-08-16 14:41:46 +02:00
# endif
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_abort ) ;
2005-11-08 01:56:26 +01:00
if ( ! m_connections . empty ( ) )
2009-11-29 08:06:38 +01:00
disconnect_all ( errors : : torrent_aborted ) ;
2003-12-14 06:56:12 +01:00
}
2008-12-14 20:47:02 +01:00
void torrent : : read_piece ( int piece )
{
TORRENT_ASSERT ( piece > = 0 & & piece < m_torrent_file - > num_pieces ( ) ) ;
int piece_size = m_torrent_file - > piece_size ( piece ) ;
2010-02-14 02:39:55 +01:00
int blocks_in_piece = ( piece_size + block_size ( ) - 1 ) / block_size ( ) ;
2008-12-14 20:47:02 +01:00
2011-02-24 05:25:35 +01:00
// if blocks_in_piece is 0, rp will leak
TORRENT_ASSERT ( blocks_in_piece > 0 ) ;
TORRENT_ASSERT ( piece_size > 0 ) ;
2008-12-14 20:47:02 +01:00
read_piece_struct * rp = new read_piece_struct ;
rp - > piece_data . reset ( new ( std : : nothrow ) char [ piece_size ] ) ;
rp - > blocks_left = 0 ;
rp - > fail = false ;
peer_request r ;
r . piece = piece ;
r . start = 0 ;
2010-02-14 02:39:55 +01:00
for ( int i = 0 ; i < blocks_in_piece ; + + i , r . start + = block_size ( ) )
2008-12-14 20:47:02 +01:00
{
2010-02-14 02:39:55 +01:00
r . length = ( std : : min ) ( piece_size - r . start , block_size ( ) ) ;
2010-04-30 21:08:16 +02:00
filesystem ( ) . async_read ( r , boost : : bind ( & torrent : : on_disk_read_complete
2008-12-14 20:47:02 +01:00
, shared_from_this ( ) , _1 , _2 , r , rp ) ) ;
+ + rp - > blocks_left ;
}
}
2010-09-05 18:01:36 +02:00
void torrent : : send_share_mode ( )
{
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( std : : set < peer_connection * > : : iterator i = m_connections . begin ( )
, end ( m_connections . end ( ) ) ; i ! = end ; + + i )
{
if ( ( * i ) - > type ( ) ! = peer_connection : : bittorrent_connection ) continue ;
bt_peer_connection * p = ( bt_peer_connection * ) * i ;
p - > write_share_mode ( ) ;
}
# endif
}
2009-11-24 19:49:59 +01:00
void torrent : : send_upload_only ( )
{
# ifndef TORRENT_DISABLE_EXTENSIONS
2011-04-10 01:57:56 +02:00
if ( share_mode ( ) ) return ;
if ( super_seeding ( ) ) return ;
for ( std : : set < peer_connection * > : : iterator i = m_connections . begin ( ) ;
i ! = m_connections . end ( ) ; )
2009-11-24 19:49:59 +01:00
{
2011-04-10 01:57:56 +02:00
// since the call to disconnect_if_redundant() may
// delete the entry from this container, make sure
// to increment the iterator early
2009-11-27 22:04:26 +01:00
bt_peer_connection * p = ( bt_peer_connection * ) * i ;
2011-04-10 01:57:56 +02:00
+ + i ;
if ( p - > type ( ) = = peer_connection : : bittorrent_connection )
p - > write_upload_only ( ) ;
p - > disconnect_if_redundant ( ) ;
2009-11-24 19:49:59 +01:00
}
# endif
}
2010-09-05 18:01:36 +02:00
void torrent : : set_share_mode ( bool s )
{
if ( s = = m_share_mode ) return ;
m_share_mode = s ;
// in share mode, all pieces have their priorities initialized to 0
std : : fill ( m_file_priority . begin ( ) , m_file_priority . end ( ) , ! m_share_mode ) ;
update_piece_priorities ( ) ;
if ( m_share_mode ) recalc_share_mode ( ) ;
}
2009-06-19 00:32:55 +02:00
void torrent : : set_upload_mode ( bool b )
{
if ( b = = m_upload_mode ) return ;
m_upload_mode = b ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2009-11-24 19:49:59 +01:00
send_upload_only ( ) ;
2009-06-19 00:32:55 +02:00
if ( m_upload_mode )
{
// clear request queues of all peers
for ( std : : set < peer_connection * > : : iterator i = m_connections . begin ( )
, end ( m_connections . end ( ) ) ; i ! = end ; + + i )
{
peer_connection * p = ( * i ) ;
p - > cancel_all_requests ( ) ;
}
// this is used to try leaving upload only mode periodically
2010-02-14 02:39:55 +01:00
m_upload_mode_time = 0 ;
2009-06-19 00:32:55 +02:00
}
else
{
2011-03-25 06:14:14 +01:00
// reset last_connected, to force fast reconnect after leaving upload mode
for ( policy : : iterator i = m_policy . begin_peer ( )
, end ( m_policy . end_peer ( ) ) ; i ! = end ; + + i )
{
( * i ) - > last_connected = 0 ;
}
2009-06-19 00:32:55 +02:00
// send_block_requests on all peers
for ( std : : set < peer_connection * > : : iterator i = m_connections . begin ( )
, end ( m_connections . end ( ) ) ; i ! = end ; + + i )
{
peer_connection * p = ( * i ) ;
p - > send_block_requests ( ) ;
}
}
}
2009-06-01 00:41:53 +02:00
void torrent : : handle_disk_error ( disk_io_job const & j , peer_connection * c )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-06-01 00:41:53 +02:00
if ( ! j . error ) return ;
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2009-06-10 10:30:55 +02:00
( * m_ses . m_logger ) < < " disk error: ' " < < j . error . message ( )
< < " in file " < < j . error_file
< < " in torrent " < < torrent_file ( ) . name ( )
< < " \n " ;
2009-06-01 00:41:53 +02:00
# endif
2009-06-10 10:30:55 +02:00
TORRENT_ASSERT ( j . piece > = 0 ) ;
piece_block block_finished ( j . piece , j . offset / block_size ( ) ) ;
2009-06-13 19:40:18 +02:00
if ( j . action = = disk_io_job : : write )
2009-06-10 10:30:55 +02:00
{
// we failed to write j.piece to disk tell the piece picker
if ( has_picker ( ) & & j . piece > = 0 ) picker ( ) . write_failed ( block_finished ) ;
}
2009-06-03 09:46:50 +02:00
if ( j . error = =
2009-06-19 18:42:33 +02:00
# if BOOST_VERSION == 103500
error_code ( boost : : system : : posix_error : : not_enough_memory , get_posix_category ( ) )
# elif BOOST_VERSION > 103500
2009-06-03 09:46:50 +02:00
error_code ( boost : : system : : errc : : not_enough_memory , get_posix_category ( ) )
# else
asio : : error : : no_memory
# endif
)
2009-06-01 00:41:53 +02:00
{
if ( alerts ( ) . should_post < file_error_alert > ( ) )
2009-06-10 10:30:55 +02:00
alerts ( ) . post_alert ( file_error_alert ( j . error_file , get_handle ( ) , j . error ) ) ;
2009-11-29 08:06:38 +01:00
if ( c ) c - > disconnect ( errors : : no_memory ) ;
2009-06-01 00:41:53 +02:00
return ;
}
// notify the user of the error
if ( alerts ( ) . should_post < file_error_alert > ( ) )
2009-06-10 10:30:55 +02:00
alerts ( ) . post_alert ( file_error_alert ( j . error_file , get_handle ( ) , j . error ) ) ;
2009-06-01 00:41:53 +02:00
2011-05-16 09:47:21 +02:00
// put the torrent in an error-state
set_error ( j . error , j . error_file ) ;
2011-08-22 03:37:56 +02:00
if ( j . action = = disk_io_job : : write
& & ( j . error = = boost : : system : : errc : : read_only_file_system
| | j . error = = boost : : system : : errc : : permission_denied
| | j . error = = boost : : system : : errc : : operation_not_permitted
| | j . error = = boost : : system : : errc : : no_space_on_device
| | j . error = = boost : : system : : errc : : file_too_large ) )
2009-06-10 11:20:55 +02:00
{
// if we failed to write, stop downloading and just
// keep seeding.
// TODO: make this depend on the error and on the filesystem the
// files are being downloaded to. If the error is no_space_left_on_device
// and the filesystem doesn't support sparse files, only zero the priorities
// of the pieces that are at the tails of all files, leaving everything
// up to the highest written piece in each file
2009-06-19 00:32:55 +02:00
set_upload_mode ( true ) ;
return ;
2009-06-10 11:20:55 +02:00
}
2011-05-16 09:47:21 +02:00
// if the error appears to be more serious than a full disk, just pause the torrent
2009-06-01 00:41:53 +02:00
pause ( ) ;
}
2008-12-14 20:47:02 +01:00
void torrent : : on_disk_read_complete ( int ret , disk_io_job const & j , peer_request r , read_piece_struct * rp )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-12-14 20:47:02 +01:00
disk_buffer_holder buffer ( m_ses , j . buffer ) ;
- - rp - > blocks_left ;
if ( ret ! = r . length )
{
rp - > fail = true ;
2009-06-01 00:41:53 +02:00
handle_disk_error ( j ) ;
2008-12-14 20:47:02 +01:00
}
else
{
std : : memcpy ( rp - > piece_data . get ( ) + r . start , j . buffer , r . length ) ;
}
if ( rp - > blocks_left = = 0 )
{
int size = m_torrent_file - > piece_size ( r . piece ) ;
if ( rp - > fail )
{
rp - > piece_data . reset ( ) ;
size = 0 ;
}
if ( m_ses . m_alerts . should_post < read_piece_alert > ( ) )
{
m_ses . m_alerts . post_alert ( read_piece_alert (
get_handle ( ) , r . piece , rp - > piece_data , size ) ) ;
}
delete rp ;
}
}
2008-12-07 22:04:19 +01:00
void torrent : : add_piece ( int piece , char const * data , int flags )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-12-07 22:04:19 +01:00
TORRENT_ASSERT ( piece > = 0 & & piece < m_torrent_file - > num_pieces ( ) ) ;
int piece_size = m_torrent_file - > piece_size ( piece ) ;
2010-02-14 02:39:55 +01:00
int blocks_in_piece = ( piece_size + block_size ( ) - 1 ) / block_size ( ) ;
2008-12-07 22:04:19 +01:00
2011-02-09 03:56:00 +01:00
// avoid crash trying to access the picker when there is none
2010-01-27 07:06:57 +01:00
if ( is_seed ( ) ) return ;
2010-05-01 19:47:28 +02:00
if ( picker ( ) . have_piece ( piece )
& & ( flags & torrent : : overwrite_existing ) = = 0 )
return ;
2010-04-22 03:53:09 +02:00
2008-12-07 22:04:19 +01:00
peer_request p ;
p . piece = piece ;
p . start = 0 ;
picker ( ) . inc_refcount ( piece ) ;
2010-02-14 02:39:55 +01:00
for ( int i = 0 ; i < blocks_in_piece ; + + i , p . start + = block_size ( ) )
2008-12-07 22:04:19 +01:00
{
if ( picker ( ) . is_finished ( piece_block ( piece , i ) )
& & ( flags & torrent : : overwrite_existing ) = = 0 )
continue ;
2010-02-14 02:39:55 +01:00
p . length = ( std : : min ) ( piece_size - p . start , int ( block_size ( ) ) ) ;
2009-01-23 10:13:31 +01:00
char * buffer = m_ses . allocate_disk_buffer ( " add piece " ) ;
2008-12-07 22:04:19 +01:00
// out of memory
2008-12-14 20:47:02 +01:00
if ( buffer = = 0 )
{
picker ( ) . dec_refcount ( piece ) ;
return ;
}
2008-12-07 22:04:19 +01:00
disk_buffer_holder holder ( m_ses , buffer ) ;
std : : memcpy ( buffer , data + p . start , p . length ) ;
2010-04-30 21:08:16 +02:00
filesystem ( ) . async_write ( p , holder , boost : : bind ( & torrent : : on_disk_write_complete
2008-12-07 22:04:19 +01:00
, shared_from_this ( ) , _1 , _2 , p ) ) ;
piece_block block ( piece , i ) ;
picker ( ) . mark_as_downloading ( block , 0 , piece_picker : : fast ) ;
picker ( ) . mark_as_writing ( block , 0 ) ;
}
2010-04-30 21:08:16 +02:00
async_verify_piece ( piece , boost : : bind ( & torrent : : piece_finished
2010-02-01 01:44:31 +01:00
, shared_from_this ( ) , piece , _1 ) ) ;
2008-12-07 22:04:19 +01:00
picker ( ) . dec_refcount ( piece ) ;
}
void torrent : : on_disk_write_complete ( int ret , disk_io_job const & j
, peer_request p )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-12-07 22:04:19 +01:00
INVARIANT_CHECK ;
2010-04-12 02:36:31 +02:00
2010-01-27 07:06:57 +01:00
if ( is_seed ( ) ) return ;
2008-12-07 22:04:19 +01:00
if ( m_abort )
{
2010-02-14 02:39:55 +01:00
piece_block block_finished ( p . piece , p . start / block_size ( ) ) ;
2008-12-07 22:04:19 +01:00
return ;
}
2010-02-14 02:39:55 +01:00
piece_block block_finished ( p . piece , p . start / block_size ( ) ) ;
2008-12-07 22:04:19 +01:00
if ( ret = = - 1 )
{
2009-06-01 00:41:53 +02:00
handle_disk_error ( j ) ;
2008-12-07 22:04:19 +01:00
return ;
}
2010-01-27 07:06:57 +01:00
// if we already have this block, just ignore it.
// this can happen if the same block is passed in through
// add_piece() multiple times
if ( picker ( ) . is_finished ( block_finished ) ) return ;
2008-12-07 22:04:19 +01:00
picker ( ) . mark_as_finished ( block_finished , 0 ) ;
}
2010-01-15 17:45:42 +01:00
void torrent : : on_disk_cache_complete ( int ret , disk_io_job const & j )
{
// suggest this piece to all peers
for ( peer_iterator i = m_connections . begin ( ) ;
i ! = m_connections . end ( ) ; + + i )
( * i ) - > send_suggest ( j . piece ) ;
}
2003-12-14 06:56:12 +01:00
2009-03-13 07:09:39 +01:00
bool torrent : : add_merkle_nodes ( std : : map < int , sha1_hash > const & nodes , int piece )
{
return m_torrent_file - > add_merkle_nodes ( nodes , piece ) ;
}
2010-02-23 17:26:24 +01:00
peer_request torrent : : to_req ( piece_block const & p ) const
2007-10-22 22:58:42 +02:00
{
2010-02-14 02:39:55 +01:00
int block_offset = p . block_index * block_size ( ) ;
int block = ( std : : min ) ( torrent_file ( ) . piece_size (
p . piece_index ) - block_offset , int ( block_size ( ) ) ) ;
TORRENT_ASSERT ( block > 0 ) ;
TORRENT_ASSERT ( block < = block_size ( ) ) ;
2007-10-22 22:58:42 +02:00
peer_request r ;
r . piece = p . piece_index ;
r . start = block_offset ;
2010-02-14 02:39:55 +01:00
r . length = block ;
2007-10-22 22:58:42 +02:00
return r ;
}
2006-11-14 01:08:16 +01:00
std : : string torrent : : name ( ) const
{
2007-09-01 05:00:31 +02:00
if ( valid_metadata ( ) ) return m_torrent_file - > name ( ) ;
2006-11-14 01:08:16 +01:00
if ( m_name ) return * m_name ;
return " " ;
}
# ifndef TORRENT_DISABLE_EXTENSIONS
2007-11-08 02:45:35 +01:00
2006-11-14 01:08:16 +01:00
void torrent : : add_extension ( boost : : shared_ptr < torrent_plugin > ext )
{
m_extensions . push_back ( ext ) ;
}
2007-11-08 02:45:35 +01:00
void torrent : : add_extension ( boost : : function < boost : : shared_ptr < torrent_plugin > ( torrent * , void * ) > const & ext
, void * userdata )
{
boost : : shared_ptr < torrent_plugin > tp ( ext ( this , userdata ) ) ;
if ( ! tp ) return ;
add_extension ( tp ) ;
for ( peer_iterator i = m_connections . begin ( ) ;
i ! = m_connections . end ( ) ; + + i )
{
peer_connection * p = * i ;
boost : : shared_ptr < peer_plugin > pp ( tp - > new_connection ( p ) ) ;
if ( pp ) p - > add_extension ( pp ) ;
}
// if files are checked for this torrent, call the extension
// to let it initialize itself
if ( m_connections_initialized )
tp - > on_files_checked ( ) ;
}
2006-11-14 01:08:16 +01:00
# endif
2011-08-28 23:06:15 +02:00
# ifdef TORRENT_USE_OPENSSL
2011-09-12 05:51:49 +02:00
/*
2011-08-28 23:06:15 +02:00
bool verify_function ( bool preverified , boost : : asio : : ssl : : verify_context & ctx )
{
return false ;
}
*/
2011-09-12 05:51:49 +02:00
void torrent : : init_ssl ( std : : string const & cert )
2004-06-14 01:30:42 +02:00
{
2011-09-12 05:51:49 +02:00
using boost : : asio : : ssl : : context ;
2004-06-14 01:30:42 +02:00
2011-09-12 05:51:49 +02:00
// this is needed for openssl < 1.0 to decrypt keys created by openssl 1.0+
OpenSSL_add_all_algorithms ( ) ;
// TODO: come up with something better
RAND_seed ( & info_hash ( ) [ 0 ] , 20 ) ;
TORRENT_ASSERT ( RAND_status ( ) = = 1 ) ;
// create the SSL context for this torrent. We need to
// inject the root certificate, and no other, to
// verify other peers against
boost : : shared_ptr < context > ctx (
new ( std : : nothrow ) context ( m_ses . m_io_service , context : : sslv23 ) ) ;
if ( ! ctx )
2011-08-28 23:06:15 +02:00
{
2011-09-12 05:51:49 +02:00
set_error ( asio : : error : : no_memory , " SSL context " ) ;
pause ( ) ;
return ;
}
2011-08-28 23:06:15 +02:00
2011-09-12 05:51:49 +02:00
ctx - > set_options ( context : : default_workarounds
| boost : : asio : : ssl : : context : : no_sslv2
| boost : : asio : : ssl : : context : : single_dh_use ) ;
2011-08-28 23:06:15 +02:00
2011-09-12 05:51:49 +02:00
error_code ec ;
ctx - > set_verify_mode ( context : : verify_peer
| context : : verify_fail_if_no_peer_cert
| context : : verify_client_once , ec ) ;
if ( ec )
{
set_error ( ec , " SSL verify mode " ) ;
pause ( ) ;
return ;
}
// this is used for debugging
/*
# error there's a bug where the async_handshake on the ssl_stream always succeeds, regardless of the certificate failing. It's not a trivial bug in asio, that's been tested with a small repro program.
ctx - > set_verify_callback ( verify_function , ec ) ;
if ( ec )
{
set_error ( ec , " SSL verify callback " ) ;
pause ( ) ;
return ;
}
*/
SSL_CTX * ssl_ctx = ctx - > impl ( ) ;
// create a new x.509 certificate store
X509_STORE * cert_store = X509_STORE_new ( ) ;
if ( ! cert_store )
{
set_error ( asio : : error : : no_memory , " x.509 certificate store " ) ;
pause ( ) ;
return ;
}
// wrap the PEM certificate in a BIO, for openssl to read
BIO * bp = BIO_new_mem_buf ( ( void * ) cert . c_str ( ) , cert . size ( ) ) ;
// parse the certificate into OpenSSL's internal
// representation
X509 * certificate = PEM_read_bio_X509_AUX ( bp , 0 , 0 , 0 ) ;
BIO_free ( bp ) ;
if ( ! certificate )
{
X509_STORE_free ( cert_store ) ;
set_error ( asio : : error : : no_memory , " x.509 certificate " ) ;
pause ( ) ;
return ;
}
// add cert to cert_store
X509_STORE_add_cert ( cert_store , certificate ) ;
// and lastly, replace the default cert store with ours
SSL_CTX_set_cert_store ( ssl_ctx , cert_store ) ;
#if 0
char filename [ 100 ] ;
snprintf ( filename , sizeof ( filename ) , " /tmp/%d.pem " , rand ( ) ) ;
FILE * f = fopen ( filename , " w+ " ) ;
fwrite ( cert . c_str ( ) , cert . size ( ) , 1 , f ) ;
fclose ( f ) ;
ctx - > load_verify_file ( filename ) ;
# endif
// if all went well, set the torrent ssl context to this one
m_ssl_ctx = ctx ;
// tell the client we need a cert for this torrent
alerts ( ) . post_alert ( torrent_need_cert_alert ( get_handle ( ) ) ) ;
m_ssl_acceptor . reset ( new listen_socket_t ) ;
m_ses . setup_listener ( m_ssl_acceptor . get ( )
, tcp : : endpoint ( address_v4 : : any ( ) , m_ses . m_listen_interface . port ( ) )
, m_ses . m_listen_port_retries + 10 , false , 0 , ec ) ;
if ( ! m_ssl_acceptor - > sock )
{
set_error ( ec , " ssl listen port " ) ;
pause ( ) ;
return ;
}
// TODO: issue UPnP and NAT-PMP for this socket
async_accept ( m_ssl_acceptor - > sock ) ;
set_allow_peers ( false ) ;
}
void torrent : : async_accept ( boost : : shared_ptr < socket_acceptor > const & listener )
{
boost : : shared_ptr < socket_type > c ( new socket_type ( m_ses . m_io_service ) ) ;
c - > instantiate < ssl_stream < stream_socket > > ( m_ses . m_io_service , m_ssl_ctx . get ( ) ) ;
# if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async ( " torrent::on_accept_ssl_connection " ) ;
# endif
listener - > async_accept ( c - > get < ssl_stream < stream_socket > > ( ) - > next_layer ( )
, boost : : bind ( & torrent : : on_accept_ssl_connection , shared_from_this ( ) , c
, boost : : weak_ptr < socket_acceptor > ( listener ) , _1 ) ) ;
}
void torrent : : on_accept_ssl_connection ( boost : : shared_ptr < socket_type > const & s
, boost : : weak_ptr < socket_acceptor > listen_socket , error_code const & e )
{
# if defined TORRENT_ASIO_DEBUGGING
complete_async ( " torrent::on_accept_ssl_connection " ) ;
# endif
// TODO: there's some code duplication with session_impl::on_accept_connection
boost : : shared_ptr < socket_acceptor > listener = listen_socket . lock ( ) ;
if ( ! listener ) return ;
if ( e = = asio : : error : : operation_aborted ) return ;
if ( m_abort ) return ;
error_code ec ;
if ( e )
{
tcp : : endpoint ep = listener - > local_endpoint ( ec ) ;
# if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
std : : string msg = " error accepting connection on ' "
+ print_endpoint ( ep ) + " ' " + e . message ( ) ;
( * m_ses . m_logger ) < < msg < < " \n " ;
# endif
# ifdef TORRENT_WINDOWS
// Windows sometimes generates this error. It seems to be
// non-fatal and we have to do another async_accept.
if ( e . value ( ) = = ERROR_SEM_TIMEOUT )
2011-08-28 23:06:15 +02:00
{
2011-09-12 05:51:49 +02:00
async_accept ( listener ) ;
2011-08-28 23:06:15 +02:00
return ;
}
2011-09-12 05:51:49 +02:00
# endif
# ifdef TORRENT_BSD
// Leopard sometimes generates an "invalid argument" error. It seems to be
// non-fatal and we have to do another async_accept.
if ( e . value ( ) = = EINVAL )
2011-08-28 23:06:15 +02:00
{
2011-09-12 05:51:49 +02:00
async_accept ( listener ) ;
2011-08-28 23:06:15 +02:00
return ;
}
2011-09-12 05:51:49 +02:00
# endif
if ( alerts ( ) . should_post < listen_failed_alert > ( ) )
alerts ( ) . post_alert ( listen_failed_alert ( ep , e ) ) ;
return ;
}
async_accept ( listener ) ;
if ( is_paused ( ) ) return ;
// we got a connection request!
tcp : : endpoint endp = s - > remote_endpoint ( ec ) ;
if ( ec )
{
# if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
( * m_ses . m_logger ) < < endp < < " <== INCOMING CONNECTION FAILED, could "
" not retrieve remote endpoint " < < ec . message ( ) < < " \n " ;
# endif
return ;
}
2011-09-17 03:44:05 +02:00
if ( alerts ( ) . should_post < incoming_connection_alert > ( ) )
{
alerts ( ) . post_alert ( incoming_connection_alert ( s - > type ( ) , endp ) ) ;
}
2011-09-12 05:51:49 +02:00
if ( ! settings ( ) . enable_incoming_tcp )
{
if ( alerts ( ) . should_post < peer_blocked_alert > ( ) )
alerts ( ) . post_alert ( peer_blocked_alert ( torrent_handle ( ) , endp . address ( ) ) ) ;
return ;
}
2011-08-28 23:06:15 +02:00
2011-09-12 05:51:49 +02:00
if ( m_apply_ip_filter
& & m_ses . m_ip_filter . access ( endp . address ( ) ) & ip_filter : : blocked )
{
# if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
( * m_ses . m_logger ) < < " filtered blocked ip \n " ;
# endif
if ( alerts ( ) . should_post < peer_blocked_alert > ( ) )
alerts ( ) . post_alert ( peer_blocked_alert ( get_handle ( ) , endp . address ( ) ) ) ;
return ;
}
if ( m_connections . size ( ) > = m_max_connections )
{
if ( alerts ( ) . should_post < peer_disconnected_alert > ( ) )
2011-08-28 23:06:15 +02:00
{
2011-09-12 05:51:49 +02:00
alerts ( ) . post_alert (
peer_disconnected_alert ( get_handle ( ) , endp , peer_id ( )
, error_code ( errors : : too_many_connections , get_libtorrent_category ( ) ) ) ) ;
2011-08-28 23:06:15 +02:00
}
2011-09-12 05:51:49 +02:00
return ;
}
2011-08-28 23:06:15 +02:00
2011-09-12 05:51:49 +02:00
m_ses . setup_socket_buffers ( * s ) ;
2011-08-28 23:06:15 +02:00
2011-09-12 05:51:49 +02:00
s - > get < ssl_stream < stream_socket > > ( ) - > async_accept_handshake ( boost : : bind ( & torrent : : ssl_handshake
, shared_from_this ( ) , _1 , s ) ) ;
}
2011-08-28 23:06:15 +02:00
2011-09-12 05:51:49 +02:00
void torrent : : ssl_handshake ( error_code const & ec , boost : : shared_ptr < socket_type > s )
{
error_code e ;
tcp : : endpoint endp = s - > remote_endpoint ( e ) ;
if ( e ) return ;
2011-08-28 23:06:15 +02:00
2011-09-12 05:51:49 +02:00
# if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
( * m_ses . m_logger ) < < time_now_string ( ) < < " *** peer SSL handshake done [ ip: "
< < endp < < " ec: " < < ec . message ( ) < < " ] \n " ;
# endif
if ( ec )
{
if ( alerts ( ) . should_post < peer_error_alert > ( ) )
2011-08-28 23:06:15 +02:00
{
2011-09-12 05:51:49 +02:00
alerts ( ) . post_alert ( peer_error_alert ( get_handle ( ) , endp
, peer_id ( ) , ec ) ) ;
2011-08-28 23:06:15 +02:00
}
2011-09-12 05:51:49 +02:00
return ;
}
2011-08-28 23:06:15 +02:00
2011-09-12 05:51:49 +02:00
boost : : intrusive_ptr < peer_connection > c (
new bt_peer_connection ( m_ses , shared_from_this ( ) , s , endp , 0 , false ) ) ;
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
c - > m_in_constructor = false ;
# endif
2011-08-28 23:06:15 +02:00
2011-09-12 05:51:49 +02:00
if ( c - > is_disconnecting ( ) ) return ;
if ( ! m_policy . new_connection ( * c , m_ses . session_time ( ) ) )
{
# if defined TORRENT_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " CLOSING CONNECTION "
2011-09-26 01:42:56 +02:00
< < c - > remote ( ) < < " policy::new_connection returned false (i.e. peer list full) \n " ;
2011-08-28 23:06:15 +02:00
# endif
2011-09-12 05:51:49 +02:00
c - > disconnect ( errors : : too_many_connections ) ;
return ;
2011-08-28 23:06:15 +02:00
}
2011-09-12 05:51:49 +02:00
// add the newly connected peer to this torrent's peer list
m_connections . insert ( boost : : get_pointer ( c ) ) ;
m_ses . m_connections . insert ( c ) ;
c - > start ( ) ;
}
# endif
// this may not be called from a constructor because of the call to
// shared_from_this()
void torrent : : init ( )
{
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
TORRENT_ASSERT ( m_torrent_file - > is_valid ( ) ) ;
TORRENT_ASSERT ( m_torrent_file - > num_files ( ) > 0 ) ;
TORRENT_ASSERT ( m_torrent_file - > total_size ( ) > = 0 ) ;
# ifdef TORRENT_USE_OPENSSL
std : : string cert = m_torrent_file - > ssl_cert ( ) ;
if ( ! cert . empty ( ) ) init_ssl ( cert ) ;
2011-08-28 23:06:15 +02:00
# endif
2011-09-05 07:50:41 +02:00
# ifdef TORRENT_USE_OPENSSL
if ( m_torrent_file - > encryption_key ( ) . size ( ) = = 32 & & ! m_in_encrypted_list )
{
m_ses . m_encrypted_torrents . insert ( shared_from_this ( ) ) ;
m_in_encrypted_list = true ;
}
# endif
2008-07-20 18:00:08 +02:00
m_file_priority . resize ( m_torrent_file - > num_files ( ) , 1 ) ;
2009-07-04 06:58:24 +02:00
m_file_progress . resize ( m_torrent_file - > num_files ( ) , 0 ) ;
2008-07-20 18:00:08 +02:00
2010-02-14 02:39:55 +01:00
m_block_size_shift = root2 ( ( std : : min ) ( int ( block_size ( ) ) , m_torrent_file - > piece_length ( ) ) ) ;
2008-06-18 14:34:39 +02:00
2009-02-23 02:21:19 +01:00
if ( m_torrent_file - > num_pieces ( ) > piece_picker : : max_pieces )
2008-06-19 13:28:34 +02:00
{
2009-11-29 08:06:38 +01:00
set_error ( errors : : too_many_pieces_in_torrent , " " ) ;
2008-06-19 13:28:34 +02:00
pause ( ) ;
2010-02-22 02:51:25 +01:00
return ;
}
2010-03-02 08:08:29 +01:00
if ( m_torrent_file - > num_pieces ( ) = = 0 )
{
set_error ( errors : : torrent_invalid_length , " " ) ;
pause ( ) ;
return ;
}
2007-06-10 22:46:09 +02:00
// the shared_from_this() will create an intentional
// cycle of ownership, se the hpp file for description.
m_owning_storage = new piece_manager ( shared_from_this ( ) , m_torrent_file
2008-03-08 07:06:31 +01:00
, m_save_path , m_ses . m_files , m_ses . m_disk_thread , m_storage_constructor
2010-07-15 03:14:36 +02:00
, ( storage_mode_t ) m_storage_mode , m_file_priority ) ;
2007-06-10 22:46:09 +02:00
m_storage = m_owning_storage . get ( ) ;
2009-02-03 08:46:24 +01:00
if ( has_picker ( ) )
{
2010-02-23 17:26:24 +01:00
int blocks_per_piece = ( m_torrent_file - > piece_length ( ) + block_size ( ) - 1 ) / block_size ( ) ;
int blocks_in_last_piece = ( ( m_torrent_file - > total_size ( ) % m_torrent_file - > piece_length ( ) )
+ block_size ( ) - 1 ) / block_size ( ) ;
m_picker - > init ( blocks_per_piece , blocks_in_last_piece , m_torrent_file - > num_pieces ( ) ) ;
2009-02-03 08:46:24 +01:00
}
2006-04-25 23:04:48 +02:00
2010-09-05 18:01:36 +02:00
if ( m_share_mode )
{
// in share mode, all pieces have their priorities initialized to 0
std : : fill ( m_file_priority . begin ( ) , m_file_priority . end ( ) , 0 ) ;
}
// in case file priorities were passed in via the add_torrent_params
// ans also in the case of share mode, we need to update the priorities
update_piece_priorities ( ) ;
2010-10-10 20:43:58 +02:00
std : : vector < web_seed_entry > const & web_seeds = m_torrent_file - > web_seeds ( ) ;
m_web_seeds . insert ( m_web_seeds . end ( ) , web_seeds . begin ( ) , web_seeds . end ( ) ) ;
2008-03-08 07:06:31 +01:00
2009-02-03 08:46:24 +01:00
if ( m_seed_mode )
{
2010-07-14 06:16:38 +02:00
m_ses . m_io_service . post ( boost : : bind ( & torrent : : files_checked , shared_from_this ( ) ) ) ;
2009-02-03 08:46:24 +01:00
std : : vector < char > ( ) . swap ( m_resume_data ) ;
lazy_entry ( ) . swap ( m_resume_entry ) ;
2011-07-05 06:05:12 +02:00
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
2011-06-09 07:46:47 +02:00
m_resume_data_loaded = true ;
# endif
2009-02-03 08:46:24 +01:00
return ;
}
2008-11-19 01:46:48 +01:00
set_state ( torrent_status : : checking_resume_data ) ;
2008-03-08 07:06:31 +01:00
2008-07-01 01:14:31 +02:00
if ( m_resume_entry . type ( ) = = lazy_entry : : dict_t )
2008-05-28 10:44:40 +02:00
{
2009-06-12 18:40:38 +02:00
int ev = 0 ;
2008-07-01 01:14:31 +02:00
if ( m_resume_entry . dict_find_string_value ( " file-format " ) ! = " libtorrent resume file " )
2009-06-12 18:40:38 +02:00
ev = errors : : invalid_file_tag ;
2008-05-28 10:44:40 +02:00
2008-07-01 01:14:31 +02:00
std : : string info_hash = m_resume_entry . dict_find_string_value ( " info-hash " ) ;
2009-06-12 18:40:38 +02:00
if ( ! ev & & info_hash . empty ( ) )
ev = errors : : missing_info_hash ;
2008-05-28 10:44:40 +02:00
2009-06-12 18:40:38 +02:00
if ( ! ev & & sha1_hash ( info_hash ) ! = m_torrent_file - > info_hash ( ) )
ev = errors : : mismatching_info_hash ;
2008-05-28 10:44:40 +02:00
2009-06-12 18:40:38 +02:00
if ( ev & & m_ses . m_alerts . should_post < fastresume_rejected_alert > ( ) )
2008-05-28 10:44:40 +02:00
{
2009-06-12 18:40:38 +02:00
m_ses . m_alerts . post_alert ( fastresume_rejected_alert ( get_handle ( )
2009-11-29 08:06:38 +01:00
, error_code ( ev , get_libtorrent_category ( ) ) ) ) ;
2009-02-03 18:35:41 +01:00
}
2008-05-28 10:44:40 +02:00
2009-06-12 18:40:38 +02:00
if ( ev )
2008-07-01 01:14:31 +02:00
{
2009-02-08 01:05:27 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2010-10-17 20:36:37 +02:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " fastresume data for "
2009-02-08 01:05:27 +01:00
< < torrent_file ( ) . name ( ) < < " rejected: "
2009-12-03 18:44:11 +01:00
< < error_code ( ev , get_libtorrent_category ( ) ) . message ( ) < < " \n " ;
2009-02-08 01:05:27 +01:00
# endif
2008-07-01 01:14:31 +02:00
std : : vector < char > ( ) . swap ( m_resume_data ) ;
2008-07-02 23:23:02 +02:00
lazy_entry ( ) . swap ( m_resume_entry ) ;
2008-07-01 01:14:31 +02:00
}
else
{
read_resume_data ( m_resume_entry ) ;
}
2008-05-28 10:44:40 +02:00
}
2011-07-05 06:05:12 +02:00
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
2011-06-05 22:48:00 +02:00
m_resume_data_loaded = true ;
# endif
2010-02-14 02:39:55 +01:00
TORRENT_ASSERT ( block_size ( ) > 0 ) ;
2008-10-03 07:49:41 +02:00
int file = 0 ;
for ( file_storage : : iterator i = m_torrent_file - > files ( ) . begin ( )
, end ( m_torrent_file - > files ( ) . end ( ) ) ; i ! = end ; + + i , + + file )
{
2010-12-13 17:47:12 +01:00
if ( ! i - > pad_file | | i - > size = = 0 ) continue ;
2009-01-14 08:41:25 +01:00
m_padding + = i - > size ;
2008-10-03 07:49:41 +02:00
peer_request pr = m_torrent_file - > map_file ( file , 0 , m_torrent_file - > file_at ( file ) . size ) ;
2010-02-14 02:39:55 +01:00
int off = pr . start & ( block_size ( ) - 1 ) ;
if ( off ! = 0 ) { pr . length - = block_size ( ) - off ; pr . start + = block_size ( ) - off ; }
TORRENT_ASSERT ( ( pr . start & ( block_size ( ) - 1 ) ) = = 0 ) ;
int block = block_size ( ) ;
int blocks_per_piece = m_torrent_file - > piece_length ( ) / block ;
2010-12-13 17:47:12 +01:00
piece_block pb ( pr . piece , pr . start / block ) ;
2010-02-14 02:39:55 +01:00
for ( ; pr . length > = block ; pr . length - = block , + + pb . block_index )
2008-10-03 07:49:41 +02:00
{
2011-02-21 06:24:41 +01:00
if ( int ( pb . block_index ) = = blocks_per_piece ) { pb . block_index = 0 ; + + pb . piece_index ; }
2008-10-03 07:49:41 +02:00
m_picker - > mark_as_finished ( pb , 0 ) ;
}
2010-12-13 17:47:12 +01:00
// ugly edge case where padfiles are not used they way they're
// supposed to be. i.e. added back-to back or at the end
2011-02-21 06:24:41 +01:00
if ( int ( pb . block_index ) = = blocks_per_piece ) { pb . block_index = 0 ; + + pb . piece_index ; }
2011-01-22 20:47:11 +01:00
if ( pr . length > 0 & & ( ( boost : : next ( i ) ! = end & & boost : : next ( i ) - > pad_file )
| | boost : : next ( i ) = = end ) )
2010-12-13 17:47:12 +01:00
{
m_picker - > mark_as_finished ( pb , 0 ) ;
}
}
if ( m_padding > 0 )
{
// if we marked an entire piece as finished, we actually
// need to consider it finished
std : : vector < piece_picker : : downloading_piece > const & dq
= m_picker - > get_download_queue ( ) ;
std : : vector < int > have_pieces ;
for ( std : : vector < piece_picker : : downloading_piece > : : const_iterator i
= dq . begin ( ) ; i ! = dq . end ( ) ; + + i )
{
int num_blocks = m_picker - > blocks_in_piece ( i - > index ) ;
if ( i - > finished < num_blocks ) continue ;
have_pieces . push_back ( i - > index ) ;
}
for ( std : : vector < int > : : iterator i = have_pieces . begin ( ) ;
i ! = have_pieces . end ( ) ; + + i )
{
we_have ( * i ) ;
}
2008-10-03 07:49:41 +02:00
}
2008-07-01 01:14:31 +02:00
m_storage - > async_check_fastresume ( & m_resume_entry
2010-04-30 21:08:16 +02:00
, boost : : bind ( & torrent : : on_resume_data_checked
2008-03-08 07:06:31 +01:00
, shared_from_this ( ) , _1 , _2 ) ) ;
}
2010-11-29 02:33:05 +01:00
bt_peer_connection * torrent : : find_introducer ( tcp : : endpoint const & ep ) const
{
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( const_peer_iterator i = m_connections . begin ( ) ; i ! = m_connections . end ( ) ; + + i )
{
if ( ( * i ) - > type ( ) ! = peer_connection : : bittorrent_connection ) continue ;
bt_peer_connection * p = ( bt_peer_connection * ) ( * i ) ;
if ( ! p - > supports_holepunch ( ) ) continue ;
peer_plugin const * pp = p - > find_plugin ( " ut_pex " ) ;
if ( ! pp ) continue ;
if ( was_introduced_by ( pp , ep ) ) return ( bt_peer_connection * ) p ;
}
# endif
return 0 ;
}
bt_peer_connection * torrent : : find_peer ( tcp : : endpoint const & ep ) const
{
for ( const_peer_iterator i = m_connections . begin ( ) ; i ! = m_connections . end ( ) ; + + i )
{
peer_connection * p = * i ;
if ( p - > type ( ) ! = peer_connection : : bittorrent_connection ) continue ;
if ( p - > remote ( ) = = ep ) return ( bt_peer_connection * ) p ;
}
return 0 ;
}
2008-03-08 07:06:31 +01:00
void torrent : : on_resume_data_checked ( int ret , disk_io_job const & j )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-03-08 07:06:31 +01:00
if ( ret = = piece_manager : : fatal_disk_error )
{
2009-06-10 10:30:55 +02:00
handle_disk_error ( j ) ;
2008-11-19 01:46:48 +01:00
set_state ( torrent_status : : queued_for_checking ) ;
2008-07-02 23:23:02 +02:00
std : : vector < char > ( ) . swap ( m_resume_data ) ;
lazy_entry ( ) . swap ( m_resume_entry ) ;
2008-03-08 07:06:31 +01:00
return ;
}
2011-12-19 06:55:38 +01:00
state_updated ( ) ;
2008-07-01 01:14:31 +02:00
if ( m_resume_entry . type ( ) = = lazy_entry : : dict_t )
2008-03-08 07:06:31 +01:00
{
2009-05-07 00:36:24 +02:00
using namespace libtorrent : : detail ; // for read_*_endpoint()
peer_id id ( 0 ) ;
if ( lazy_entry const * peers_entry = m_resume_entry . dict_find_string ( " peers " ) )
{
int num_peers = peers_entry - > string_length ( ) / ( sizeof ( address_v4 : : bytes_type ) + 2 ) ;
char const * ptr = peers_entry - > string_ptr ( ) ;
for ( int i = 0 ; i < num_peers ; + + i )
{
2009-05-16 00:07:19 +02:00
m_policy . add_peer ( read_v4_endpoint < tcp : : endpoint > ( ptr )
2009-05-07 00:36:24 +02:00
, id , peer_info : : resume_data , 0 ) ;
}
}
if ( lazy_entry const * banned_peers_entry = m_resume_entry . dict_find_string ( " banned_peers " ) )
{
int num_peers = banned_peers_entry - > string_length ( ) / ( sizeof ( address_v4 : : bytes_type ) + 2 ) ;
char const * ptr = banned_peers_entry - > string_ptr ( ) ;
for ( int i = 0 ; i < num_peers ; + + i )
{
2009-05-16 00:07:19 +02:00
policy : : peer * p = m_policy . add_peer ( read_v4_endpoint < tcp : : endpoint > ( ptr )
2009-05-07 00:36:24 +02:00
, id , peer_info : : resume_data , 0 ) ;
2009-06-18 18:16:41 +02:00
if ( p ) m_policy . ban_peer ( p ) ;
2009-05-07 00:36:24 +02:00
}
}
# if TORRENT_USE_IPV6
if ( lazy_entry const * peers6_entry = m_resume_entry . dict_find_string ( " peers6 " ) )
{
int num_peers = peers6_entry - > string_length ( ) / ( sizeof ( address_v6 : : bytes_type ) + 2 ) ;
char const * ptr = peers6_entry - > string_ptr ( ) ;
for ( int i = 0 ; i < num_peers ; + + i )
{
2009-05-16 00:07:19 +02:00
m_policy . add_peer ( read_v6_endpoint < tcp : : endpoint > ( ptr )
2009-05-07 00:36:24 +02:00
, id , peer_info : : resume_data , 0 ) ;
}
}
if ( lazy_entry const * banned_peers6_entry = m_resume_entry . dict_find_string ( " banned_peers6 " ) )
{
int num_peers = banned_peers6_entry - > string_length ( ) / ( sizeof ( address_v6 : : bytes_type ) + 2 ) ;
char const * ptr = banned_peers6_entry - > string_ptr ( ) ;
for ( int i = 0 ; i < num_peers ; + + i )
{
2009-05-16 00:07:19 +02:00
policy : : peer * p = m_policy . add_peer ( read_v6_endpoint < tcp : : endpoint > ( ptr )
2009-05-07 00:36:24 +02:00
, id , peer_info : : resume_data , 0 ) ;
2009-06-18 18:16:41 +02:00
if ( p ) m_policy . ban_peer ( p ) ;
2009-05-07 00:36:24 +02:00
}
}
# endif
2008-07-01 01:14:31 +02:00
// parse out "peers" from the resume data and add them to the peer list
if ( lazy_entry const * peers_entry = m_resume_entry . dict_find_list ( " peers " ) )
2008-03-08 07:06:31 +01:00
{
2008-07-01 01:14:31 +02:00
for ( int i = 0 ; i < peers_entry - > list_size ( ) ; + + i )
{
lazy_entry const * e = peers_entry - > list_at ( i ) ;
if ( e - > type ( ) ! = lazy_entry : : dict_t ) continue ;
std : : string ip = e - > dict_find_string_value ( " ip " ) ;
int port = e - > dict_find_int_value ( " port " ) ;
if ( ip . empty ( ) | | port = = 0 ) continue ;
2008-11-05 06:39:18 +01:00
error_code ec ;
tcp : : endpoint a ( address : : from_string ( ip , ec ) , ( unsigned short ) port ) ;
if ( ec ) continue ;
2009-05-16 00:07:19 +02:00
m_policy . add_peer ( a , id , peer_info : : resume_data , 0 ) ;
2008-07-01 01:14:31 +02:00
}
}
2008-03-08 07:06:31 +01:00
2008-07-01 01:14:31 +02:00
// parse out "banned_peers" and add them as banned
if ( lazy_entry const * banned_peers_entry = m_resume_entry . dict_find_list ( " banned_peers " ) )
2009-05-07 00:36:24 +02:00
{
2008-07-01 01:14:31 +02:00
for ( int i = 0 ; i < banned_peers_entry - > list_size ( ) ; + + i )
{
lazy_entry const * e = banned_peers_entry - > list_at ( i ) ;
if ( e - > type ( ) ! = lazy_entry : : dict_t ) continue ;
std : : string ip = e - > dict_find_string_value ( " ip " ) ;
int port = e - > dict_find_int_value ( " port " ) ;
if ( ip . empty ( ) | | port = = 0 ) continue ;
2008-11-05 06:39:18 +01:00
error_code ec ;
tcp : : endpoint a ( address : : from_string ( ip , ec ) , ( unsigned short ) port ) ;
if ( ec ) continue ;
2009-05-16 00:07:19 +02:00
policy : : peer * p = m_policy . add_peer ( a , id , peer_info : : resume_data , 0 ) ;
2009-06-18 18:16:41 +02:00
if ( p ) m_policy . ban_peer ( p ) ;
2008-07-01 01:14:31 +02:00
}
2008-03-08 07:06:31 +01:00
}
}
2010-08-23 07:51:12 +02:00
// only report this error if the user actually provided resume data
if ( ( j . error | | ret ! = 0 ) & & ! m_resume_data . empty ( )
& & m_ses . m_alerts . should_post < fastresume_rejected_alert > ( ) )
2008-03-08 07:06:31 +01:00
{
2009-06-12 18:40:38 +02:00
m_ses . m_alerts . post_alert ( fastresume_rejected_alert ( get_handle ( ) , j . error ) ) ;
2009-02-03 18:35:41 +01:00
}
2010-08-23 07:51:12 +02:00
2008-03-08 07:06:31 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2010-10-17 20:36:37 +02:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " fastresume data for "
2009-02-03 18:35:41 +01:00
< < torrent_file ( ) . name ( ) < < " rejected: "
2010-08-19 18:10:31 +02:00
< < j . error . message ( ) < < " ret: " < < ret < < " \n " ;
2008-03-08 07:06:31 +01:00
# endif
2010-08-23 07:51:12 +02:00
// if ret != 0, it means we need a full check. We don't necessarily need
// that when the resume data check fails. For instance, if the resume data
// is incorrect, but we don't have any files, we skip the check and initialize
// the storage to not have anything.
if ( ret = = 0 )
2008-03-08 07:06:31 +01:00
{
// there are either no files for this torrent
// or the resume_data was accepted
2009-06-28 02:36:41 +02:00
if ( ! j . error & & m_resume_entry . type ( ) = = lazy_entry : : dict_t )
2008-03-08 07:06:31 +01:00
{
2008-04-13 20:54:36 +02:00
// parse have bitmask
2008-07-01 01:14:31 +02:00
lazy_entry const * pieces = m_resume_entry . dict_find ( " pieces " ) ;
if ( pieces & & pieces - > type ( ) = = lazy_entry : : string_t
& & int ( pieces - > string_length ( ) ) = = m_torrent_file - > num_pieces ( ) )
2008-03-08 07:06:31 +01:00
{
2008-07-01 01:14:31 +02:00
char const * pieces_str = pieces - > string_ptr ( ) ;
for ( int i = 0 , end ( pieces - > string_length ( ) ) ; i < end ; + + i )
2008-03-08 07:06:31 +01:00
{
2009-07-04 06:58:24 +02:00
if ( pieces_str [ i ] & 1 ) we_have ( i ) ;
2009-03-21 05:33:53 +01:00
if ( m_seed_mode & & ( pieces_str [ i ] & 2 ) ) m_verified . set_bit ( i ) ;
2008-03-08 07:06:31 +01:00
}
}
2009-06-27 23:47:30 +02:00
else
{
lazy_entry const * slots = m_resume_entry . dict_find ( " slots " ) ;
if ( slots & & slots - > type ( ) = = lazy_entry : : list_t )
{
for ( int i = 0 ; i < slots - > list_size ( ) ; + + i )
{
int piece = slots - > list_int_value_at ( i , - 1 ) ;
2009-07-04 06:58:24 +02:00
if ( piece > = 0 ) we_have ( piece ) ;
2009-06-27 23:47:30 +02:00
}
}
}
2008-03-08 07:06:31 +01:00
// parse unfinished pieces
int num_blocks_per_piece =
static_cast < int > ( torrent_file ( ) . piece_length ( ) ) / block_size ( ) ;
2008-07-01 01:14:31 +02:00
if ( lazy_entry const * unfinished_ent = m_resume_entry . dict_find_list ( " unfinished " ) )
2008-03-08 07:06:31 +01:00
{
2008-07-01 01:14:31 +02:00
for ( int i = 0 ; i < unfinished_ent - > list_size ( ) ; + + i )
2008-03-08 07:06:31 +01:00
{
2008-07-01 01:14:31 +02:00
lazy_entry const * e = unfinished_ent - > list_at ( i ) ;
if ( e - > type ( ) ! = lazy_entry : : dict_t ) continue ;
int piece = e - > dict_find_int_value ( " piece " , - 1 ) ;
if ( piece < 0 | | piece > torrent_file ( ) . num_pieces ( ) ) continue ;
2008-03-08 07:06:31 +01:00
2008-07-01 01:14:31 +02:00
if ( m_picker - > have_piece ( piece ) )
m_picker - > we_dont_have ( piece ) ;
2008-03-08 07:06:31 +01:00
2008-07-01 01:14:31 +02:00
std : : string bitmask = e - > dict_find_string_value ( " bitmask " ) ;
if ( bitmask . empty ( ) ) continue ;
2008-03-08 07:06:31 +01:00
const int num_bitmask_bytes = ( std : : max ) ( num_blocks_per_piece / 8 , 1 ) ;
if ( ( int ) bitmask . size ( ) ! = num_bitmask_bytes ) continue ;
2011-03-30 18:03:35 +02:00
for ( int k = 0 ; k < num_bitmask_bytes ; + + k )
2008-03-08 07:06:31 +01:00
{
2011-03-30 18:03:35 +02:00
unsigned char bits = bitmask [ k ] ;
int num_bits = ( std : : min ) ( num_blocks_per_piece - k * 8 , 8 ) ;
2011-04-02 21:54:30 +02:00
for ( int b = 0 ; b < num_bits ; + + b )
2008-03-08 07:06:31 +01:00
{
2011-04-02 21:54:30 +02:00
const int block = k * 8 + b ;
if ( bits & ( 1 < < b ) )
2008-03-08 07:06:31 +01:00
{
2011-04-02 21:54:30 +02:00
m_picker - > mark_as_finished ( piece_block ( piece , block ) , 0 ) ;
2008-07-01 01:14:31 +02:00
if ( m_picker - > is_piece_finished ( piece ) )
2010-04-30 21:08:16 +02:00
async_verify_piece ( piece , boost : : bind ( & torrent : : piece_finished
2008-07-01 01:14:31 +02:00
, shared_from_this ( ) , piece , _1 ) ) ;
2008-03-08 07:06:31 +01:00
}
}
}
}
}
}
2010-07-14 06:16:38 +02:00
files_checked ( ) ;
2008-03-08 07:06:31 +01:00
}
else
{
// either the fastresume data was rejected or there are
// some files
2008-11-19 01:46:48 +01:00
set_state ( torrent_status : : queued_for_checking ) ;
if ( should_check_files ( ) )
2009-02-08 02:29:09 +01:00
queue_torrent_check ( ) ;
2008-03-08 07:06:31 +01:00
}
2008-07-02 23:23:02 +02:00
std : : vector < char > ( ) . swap ( m_resume_data ) ;
lazy_entry ( ) . swap ( m_resume_entry ) ;
2008-03-08 07:06:31 +01:00
}
2009-02-08 02:29:09 +01:00
void torrent : : queue_torrent_check ( )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-02-08 02:29:09 +01:00
if ( m_queued_for_checking ) return ;
m_queued_for_checking = true ;
2010-01-17 22:42:14 +01:00
m_ses . queue_check_torrent ( shared_from_this ( ) ) ;
2009-02-08 02:29:09 +01:00
}
void torrent : : dequeue_torrent_check ( )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-02-08 02:29:09 +01:00
if ( ! m_queued_for_checking ) return ;
m_queued_for_checking = false ;
2010-01-17 22:42:14 +01:00
m_ses . dequeue_check_torrent ( shared_from_this ( ) ) ;
2009-02-08 02:29:09 +01:00
}
2008-06-07 18:24:56 +02:00
void torrent : : force_recheck ( )
{
2009-11-29 18:57:42 +01:00
if ( ! valid_metadata ( ) ) return ;
2008-11-19 01:46:48 +01:00
// if the torrent is already queued to check its files
// don't do anything
if ( should_check_files ( )
| | m_state = = torrent_status : : checking_resume_data )
2008-06-17 16:56:22 +02:00
return ;
2009-02-23 02:21:19 +01:00
clear_error ( ) ;
2008-11-19 01:46:48 +01:00
2009-11-29 08:06:38 +01:00
disconnect_all ( errors : : stopping_torrent ) ;
2010-02-18 04:53:16 +01:00
stop_announcing ( ) ;
2008-06-07 18:24:56 +02:00
m_owning_storage - > async_release_files ( ) ;
2008-08-26 23:35:33 +02:00
if ( ! m_picker ) m_picker . reset ( new piece_picker ( ) ) ;
2009-07-04 06:58:24 +02:00
std : : fill ( m_file_progress . begin ( ) , m_file_progress . end ( ) , 0 ) ;
2010-02-23 17:26:24 +01:00
int blocks_per_piece = ( m_torrent_file - > piece_length ( ) + block_size ( ) - 1 ) / block_size ( ) ;
int blocks_in_last_piece = ( ( m_torrent_file - > total_size ( ) % m_torrent_file - > piece_length ( ) )
+ block_size ( ) - 1 ) / block_size ( ) ;
m_picker - > init ( blocks_per_piece , blocks_in_last_piece , m_torrent_file - > num_pieces ( ) ) ;
2008-06-07 18:24:56 +02:00
// assume that we don't have anything
2009-06-10 10:30:55 +02:00
TORRENT_ASSERT ( m_picker - > num_have ( ) = = 0 ) ;
2008-06-07 18:24:56 +02:00
m_files_checked = false ;
2008-11-19 01:46:48 +01:00
set_state ( torrent_status : : checking_resume_data ) ;
2008-06-17 16:56:22 +02:00
2009-05-23 17:58:32 +02:00
m_policy . recalculate_connect_candidates ( ) ;
2009-06-10 10:30:55 +02:00
if ( m_auto_managed & & ! is_finished ( ) )
2008-06-17 16:56:22 +02:00
set_queue_position ( ( std : : numeric_limits < int > : : max ) ( ) ) ;
2008-06-07 18:24:56 +02:00
2008-07-01 01:14:31 +02:00
std : : vector < char > ( ) . swap ( m_resume_data ) ;
2008-07-02 23:23:02 +02:00
lazy_entry ( ) . swap ( m_resume_entry ) ;
2008-07-01 01:14:31 +02:00
m_storage - > async_check_fastresume ( & m_resume_entry
2010-04-30 21:08:16 +02:00
, boost : : bind ( & torrent : : on_force_recheck
2008-06-07 18:24:56 +02:00
, shared_from_this ( ) , _1 , _2 ) ) ;
}
void torrent : : on_force_recheck ( int ret , disk_io_job const & j )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-06-07 18:24:56 +02:00
2011-12-24 21:12:34 +01:00
state_updated ( ) ;
2008-06-07 18:24:56 +02:00
if ( ret = = piece_manager : : fatal_disk_error )
{
2009-06-10 10:30:55 +02:00
handle_disk_error ( j ) ;
2008-06-07 18:24:56 +02:00
return ;
}
2009-04-10 09:22:27 +02:00
if ( ret = = 0 )
{
// if there are no files, just start
2010-07-14 06:16:38 +02:00
files_checked ( ) ;
2009-04-10 09:22:27 +02:00
}
else
{
set_state ( torrent_status : : queued_for_checking ) ;
if ( should_check_files ( ) )
queue_torrent_check ( ) ;
}
2008-06-07 18:24:56 +02:00
}
2008-03-08 07:06:31 +01:00
void torrent : : start_checking ( )
{
2008-11-19 01:46:48 +01:00
TORRENT_ASSERT ( should_check_files ( ) ) ;
2008-07-03 12:05:51 +02:00
set_state ( torrent_status : : checking_files ) ;
2008-03-08 07:06:31 +01:00
2010-04-30 21:08:16 +02:00
m_storage - > async_check_files ( boost : : bind (
2008-03-08 07:06:31 +01:00
& torrent : : on_piece_checked
, shared_from_this ( ) , _1 , _2 ) ) ;
}
void torrent : : on_piece_checked ( int ret , disk_io_job const & j )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-01-17 20:00:09 +01:00
INVARIANT_CHECK ;
2011-12-25 13:16:04 +01:00
state_updated ( ) ;
2008-06-09 06:46:34 +02:00
if ( ret = = piece_manager : : disk_check_aborted )
{
2009-02-09 03:04:43 +01:00
dequeue_torrent_check ( ) ;
2009-04-19 21:49:33 +02:00
pause ( ) ;
2008-06-09 06:46:34 +02:00
return ;
}
2008-03-08 07:06:31 +01:00
if ( ret = = piece_manager : : fatal_disk_error )
{
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < file_error_alert > ( ) )
2008-03-08 07:06:31 +01:00
{
2009-06-10 10:30:55 +02:00
m_ses . m_alerts . post_alert ( file_error_alert ( j . error_file , get_handle ( ) , j . error ) ) ;
2009-02-03 18:35:41 +01:00
}
2008-03-08 07:06:31 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2009-02-03 18:35:41 +01:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " : fatal disk error [ "
2010-11-26 21:38:31 +01:00
" error: " < < j . error . message ( ) < <
2009-02-03 18:35:41 +01:00
" torrent: " < < torrent_file ( ) . name ( ) < <
" ] \n " ;
2008-03-08 07:06:31 +01:00
# endif
pause ( ) ;
2009-02-23 02:21:19 +01:00
set_error ( j . error , j . error_file ) ;
2008-03-08 07:06:31 +01:00
return ;
}
2009-09-09 19:59:01 +02:00
m_progress_ppm = size_type ( j . piece ) * 1000000 / torrent_file ( ) . num_pieces ( ) ;
2008-03-08 07:06:31 +01:00
2008-06-07 04:58:28 +02:00
TORRENT_ASSERT ( m_picker ) ;
if ( j . offset > = 0 & & ! m_picker - > have_piece ( j . offset ) )
2011-07-24 18:18:54 +02:00
{
2009-07-04 06:58:24 +02:00
we_have ( j . offset ) ;
2011-07-24 18:18:54 +02:00
remove_time_critical_piece ( j . offset ) ;
}
2010-02-06 08:31:43 +01:00
2008-03-08 07:06:31 +01:00
// we're not done checking yet
// this handler will be called repeatedly until
// we're done, or encounter a failure
if ( ret = = piece_manager : : need_full_check ) return ;
2009-02-09 03:04:43 +01:00
dequeue_torrent_check ( ) ;
2010-07-14 06:16:38 +02:00
files_checked ( ) ;
2004-06-14 01:30:42 +02:00
}
2010-07-17 09:13:14 +02:00
void torrent : : use_interface ( std : : string net_interfaces )
2004-02-26 01:27:06 +01:00
{
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2010-07-17 09:13:14 +02:00
m_net_interfaces . clear ( ) ;
char * str = & net_interfaces [ 0 ] ;
2006-04-25 23:04:48 +02:00
2010-07-17 09:13:14 +02:00
while ( str )
{
char * space = strchr ( str , ' , ' ) ;
if ( space ) * space + + = 0 ;
error_code ec ;
address a ( address : : from_string ( str , ec ) ) ;
str = space ;
if ( ec ) continue ;
m_net_interfaces . push_back ( tcp : : endpoint ( a , 0 ) ) ;
}
}
tcp : : endpoint torrent : : get_interface ( ) const
{
if ( m_net_interfaces . empty ( ) ) return tcp : : endpoint ( address_v4 ( ) , 0 ) ;
if ( m_interface_index > = m_net_interfaces . size ( ) ) m_interface_index = 0 ;
return m_net_interfaces [ m_interface_index + + ] ;
2004-02-26 01:27:06 +01:00
}
2008-07-12 10:25:19 +02:00
void torrent : : on_tracker_announce_disp ( boost : : weak_ptr < torrent > p
2008-05-03 18:05:42 +02:00
, error_code const & e )
2007-04-04 04:06:07 +02:00
{
2010-11-28 02:47:30 +01:00
# if defined TORRENT_ASIO_DEBUGGING
complete_async ( " tracker::on_tracker_announce_disp " ) ;
# endif
2007-04-04 04:06:07 +02:00
if ( e ) return ;
2007-04-11 19:22:19 +02:00
boost : : shared_ptr < torrent > t = p . lock ( ) ;
if ( ! t ) return ;
2008-07-12 10:25:19 +02:00
t - > on_tracker_announce ( ) ;
2007-04-11 19:22:19 +02:00
}
2008-07-12 10:25:19 +02:00
void torrent : : on_tracker_announce ( )
2007-04-11 19:22:19 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-12-27 08:22:57 +01:00
m_waiting_tracker = false ;
2007-11-11 20:09:29 +01:00
if ( m_abort ) return ;
2008-07-12 10:25:19 +02:00
announce_with_tracker ( ) ;
}
2010-02-05 09:23:17 +01:00
void torrent : : lsd_announce ( )
2008-07-12 10:25:19 +02:00
{
if ( m_abort ) return ;
2010-02-05 09:23:17 +01:00
// if the files haven't been checked yet, we're
// not ready for peers
if ( ! m_files_checked ) return ;
2010-03-29 02:34:04 +02:00
if ( ! m_announce_to_lsd ) return ;
2009-08-20 05:19:12 +02:00
if ( m_torrent_file - > is_valid ( )
& & ( m_torrent_file - > priv ( )
| | ( torrent_file ( ) . is_i2p ( )
2010-02-14 02:39:55 +01:00
& & ! settings ( ) . allow_i2p_mixed ) ) )
2008-07-12 10:25:19 +02:00
return ;
if ( is_paused ( ) ) return ;
2007-11-11 20:09:29 +01:00
2011-09-12 05:51:49 +02:00
# ifdef TORRENT_USE_OPENSSL
int port = is_ssl_torrent ( ) ? m_ssl_acceptor - > external_port : m_ses . listen_port ( ) ;
# else
int port = m_ses . listen_port ( ) ;
# endif
2008-07-12 10:25:19 +02:00
// announce with the local discovery service
2011-09-12 05:51:49 +02:00
m_ses . announce_lsd ( m_torrent_file - > info_hash ( ) , port
2011-02-16 11:16:52 +01:00
, m_ses . settings ( ) . broadcast_lsd & & m_lsd_seq = = 0 ) ;
+ + m_lsd_seq ;
2007-04-04 04:06:07 +02:00
}
2006-08-01 17:27:08 +02:00
# ifndef TORRENT_DISABLE_DHT
2010-02-14 02:39:55 +01:00
void torrent : : dht_announce ( )
2010-02-05 09:23:17 +01:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-02-05 09:23:17 +01:00
if ( ! m_ses . m_dht ) return ;
if ( ! should_announce_dht ( ) ) return ;
2010-03-29 02:34:04 +02:00
TORRENT_ASSERT ( m_allow_peers ) ;
2011-09-12 05:51:49 +02:00
# ifdef TORRENT_USE_OPENSSL
int port = is_ssl_torrent ( ) ? m_ssl_acceptor - > external_port : m_ses . listen_port ( ) ;
# else
int port = m_ses . listen_port ( ) ;
# endif
2010-02-05 09:23:17 +01:00
boost : : weak_ptr < torrent > self ( shared_from_this ( ) ) ;
m_ses . m_dht - > announce ( m_torrent_file - > info_hash ( )
2011-09-12 05:51:49 +02:00
, port , is_seed ( )
2010-04-30 21:08:16 +02:00
, boost : : bind ( & torrent : : on_dht_announce_response_disp , self , _1 ) ) ;
2010-02-14 02:39:55 +01:00
}
2006-08-29 03:15:24 +02:00
void torrent : : on_dht_announce_response_disp ( boost : : weak_ptr < libtorrent : : torrent > t
, std : : vector < tcp : : endpoint > const & peers )
{
boost : : shared_ptr < libtorrent : : torrent > tor = t . lock ( ) ;
if ( ! tor ) return ;
tor - > on_dht_announce_response ( peers ) ;
}
2006-08-01 17:27:08 +02:00
void torrent : : on_dht_announce_response ( std : : vector < tcp : : endpoint > const & peers )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-02-01 08:33:04 +01:00
if ( peers . empty ( ) ) return ;
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < dht_reply_alert > ( ) )
2007-02-01 08:33:04 +01:00
{
2008-07-06 14:22:56 +02:00
m_ses . m_alerts . post_alert ( dht_reply_alert (
get_handle ( ) , peers . size ( ) ) ) ;
2007-02-01 08:33:04 +01:00
}
2009-08-20 05:19:12 +02:00
if ( torrent_file ( ) . priv ( ) | | ( torrent_file ( ) . is_i2p ( )
2010-02-14 02:39:55 +01:00
& & ! settings ( ) . allow_i2p_mixed ) ) return ;
2009-08-20 05:19:12 +02:00
2010-04-30 21:08:16 +02:00
std : : for_each ( peers . begin ( ) , peers . end ( ) , boost : : bind (
2009-05-16 00:07:19 +02:00
& policy : : add_peer , boost : : ref ( m_policy ) , _1 , peer_id ( 0 )
2007-04-10 23:23:13 +02:00
, peer_info : : dht , 0 ) ) ;
2006-08-01 17:27:08 +02:00
}
# endif
2009-05-15 23:23:41 +02:00
void torrent : : announce_with_tracker ( tracker_request : : event_t e
, address const & bind_interface )
2008-07-12 10:25:19 +02:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-07-12 10:25:19 +02:00
INVARIANT_CHECK ;
2008-07-14 15:09:07 +02:00
if ( m_trackers . empty ( ) ) return ;
2008-07-12 10:25:19 +02:00
2008-08-11 16:31:58 +02:00
if ( m_abort ) e = tracker_request : : stopped ;
2010-03-29 02:34:04 +02:00
// if we're not announcing to trackers, only allow
// stopping
if ( e ! = tracker_request : : stopped & & ! m_announce_to_trackers ) return ;
TORRENT_ASSERT ( m_allow_peers | | e = = tracker_request : : stopped ) ;
2010-09-24 17:52:40 +02:00
if ( e = = tracker_request : : none & & is_finished ( ) & & ! is_seed ( ) )
2010-09-06 06:02:15 +02:00
e = tracker_request : : paused ;
2008-07-12 10:25:19 +02:00
tracker_request req ;
2011-03-04 07:55:39 +01:00
req . apply_ip_filter = m_apply_ip_filter & & m_ses . m_settings . apply_ip_filter_to_trackers ;
2008-07-12 10:25:19 +02:00
req . info_hash = m_torrent_file - > info_hash ( ) ;
req . pid = m_ses . get_peer_id ( ) ;
2010-10-26 18:39:20 +02:00
req . downloaded = m_stat . total_payload_download ( ) - m_total_failed_bytes ;
2008-07-12 10:25:19 +02:00
req . uploaded = m_stat . total_payload_upload ( ) ;
2010-02-18 07:45:07 +01:00
req . corrupt = m_total_failed_bytes ;
2010-10-26 18:39:20 +02:00
req . left = bytes_left ( ) ;
2008-07-12 10:25:19 +02:00
if ( req . left = = - 1 ) req . left = 16 * 1024 ;
2011-08-28 23:06:15 +02:00
# ifdef TORRENT_USE_OPENSSL
// if this torrent contains an SSL certificate, make sure
// any SSL tracker presents a certificate signed by it
req . ssl_ctx = m_ssl_ctx . get ( ) ;
# endif
2010-02-18 07:45:07 +01:00
2010-10-26 18:39:20 +02:00
// exclude redundant bytes if we should
if ( ! settings ( ) . report_true_downloaded )
req . downloaded - = m_total_redundant_bytes ;
if ( req . downloaded < 0 ) req . downloaded = 0 ;
2010-02-18 07:45:07 +01:00
2008-07-12 10:25:19 +02:00
req . event = e ;
2008-10-21 10:45:42 +02:00
error_code ec ;
2010-04-13 06:30:34 +02:00
if ( ! m_ses . m_settings . anonymous_mode )
{
tcp : : endpoint ep ;
ep = m_ses . get_ipv6_interface ( ) ;
if ( ep ! = tcp : : endpoint ( ) ) req . ipv6 = ep . address ( ) . to_string ( ec ) ;
ep = m_ses . get_ipv4_interface ( ) ;
if ( ep ! = tcp : : endpoint ( ) ) req . ipv4 = ep . address ( ) . to_string ( ec ) ;
}
2008-07-12 10:25:19 +02:00
// if we are aborting. we don't want any new peers
req . num_want = ( req . event = = tracker_request : : stopped )
2010-02-14 02:39:55 +01:00
? 0 : settings ( ) . num_want ;
2008-07-12 10:25:19 +02:00
2011-09-12 05:51:49 +02:00
// SSL torrents use their own listen socket
# ifdef TORRENT_USE_OPENSSL
// TODO: this pattern is repeated in a few places. Factor this into
// a function and generalize the concept of a torrent having a
// dedicated listen port
if ( is_ssl_torrent ( ) ) req . listen_port = m_ssl_acceptor - > external_port ;
else
# endif
2009-01-19 09:31:31 +01:00
req . listen_port = m_ses . listen_port ( ) ;
2008-07-12 10:25:19 +02:00
req . key = m_ses . m_key ;
2010-05-03 10:24:30 +02:00
ptime now = time_now_hires ( ) ;
2008-11-29 09:38:40 +01:00
2009-06-28 22:21:55 +02:00
// the tier is kept as INT_MAX until we find the first
// tracker that works, then it's set to that tracker's
// tier.
2008-11-29 09:38:40 +01:00
int tier = INT_MAX ;
2009-06-28 22:21:55 +02:00
// have we sent an announce in this tier yet?
bool sent_announce = false ;
2009-06-10 10:42:05 +02:00
for ( int i = 0 ; i < int ( m_trackers . size ( ) ) ; + + i )
2008-07-12 10:25:19 +02:00
{
2008-11-29 09:38:40 +01:00
announce_entry & ae = m_trackers [ i ] ;
2011-08-18 01:01:35 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
char msg [ 1000 ] ;
snprintf ( msg , sizeof ( msg ) , " *** announce with tracker: considering \" %s \" "
" [ announce_to_all_tiers: %d announce_to_all_trackers: %d "
" i->tier: %d tier: %d "
" is_working: %d fails: %d fail_limit: %d updating: %d "
" can_announce: %d sent_announce: %d ] "
, ae . url . c_str ( ) , settings ( ) . announce_to_all_tiers
, settings ( ) . announce_to_all_trackers
, ae . tier , tier , ae . is_working ( ) , ae . fails , ae . fail_limit
, ae . updating , ae . can_announce ( now , is_seed ( ) ) , sent_announce ) ;
debug_log ( msg ) ;
# endif
2010-11-18 06:51:52 +01:00
// if trackerid is not specified for tracker use default one, probably set explicitly
req . trackerid = ae . trackerid . empty ( ) ? m_trackerid : ae . trackerid ;
2010-02-14 02:39:55 +01:00
if ( settings ( ) . announce_to_all_tiers
2010-02-18 04:53:16 +01:00
& & ! settings ( ) . announce_to_all_trackers
2009-06-28 22:21:55 +02:00
& & sent_announce
& & ae . tier < = tier
& & tier ! = INT_MAX )
continue ;
2011-08-18 01:01:35 +02:00
if ( ae . tier > tier & & sent_announce & & ! settings ( ) . announce_to_all_tiers ) break ;
2009-06-28 22:21:55 +02:00
if ( ae . is_working ( ) ) { tier = ae . tier ; sent_announce = false ; }
2010-09-01 05:14:12 +02:00
if ( ! ae . can_announce ( now , is_seed ( ) ) )
2008-11-29 09:38:40 +01:00
{
2011-09-12 07:21:16 +02:00
// this counts
if ( ae . is_working ( ) ) sent_announce = true ;
2008-11-29 09:38:40 +01:00
continue ;
}
req . url = ae . url ;
req . event = e ;
if ( req . event = = tracker_request : : none )
{
if ( ! ae . start_sent ) req . event = tracker_request : : started ;
2010-02-18 04:53:16 +01:00
else if ( ! ae . complete_sent & & is_seed ( ) ) req . event = tracker_request : : completed ;
2008-11-29 09:38:40 +01:00
}
2009-05-15 23:23:41 +02:00
if ( ! is_any ( bind_interface ) ) req . bind_ip = bind_interface ;
else req . bind_ip = m_ses . m_listen_interface . address ( ) ;
2010-04-13 06:30:34 +02:00
if ( settings ( ) . anonymous_mode )
{
// in anonymous_mode we don't talk directly to trackers
// only if there is a proxy
std : : string protocol = req . url . substr ( 0 , req . url . find ( ' : ' ) ) ;
2010-08-23 08:27:18 +02:00
int proxy_type = m_ses . m_proxy . type ;
2010-04-13 06:30:34 +02:00
if ( ( protocol = = " http " | | protocol = = " https " )
& & proxy_type = = proxy_settings : : none )
{
2010-05-03 10:24:30 +02:00
ae . next_announce = now + minutes ( 10 ) ;
2010-04-13 06:30:34 +02:00
if ( m_ses . m_alerts . should_post < anonymous_mode_alert > ( ) )
{
m_ses . m_alerts . post_alert (
anonymous_mode_alert ( get_handle ( )
, anonymous_mode_alert : : tracker_not_anonymous , req . url ) ) ;
}
continue ;
}
if ( protocol = = " udp "
| | ( proxy_type ! = proxy_settings : : socks5
& & proxy_type ! = proxy_settings : : socks5_pw
& & proxy_type ! = proxy_settings : : i2p_proxy ) )
{
2010-05-03 10:24:30 +02:00
ae . next_announce = now + minutes ( 10 ) ;
2010-04-13 06:30:34 +02:00
if ( m_ses . m_alerts . should_post < anonymous_mode_alert > ( ) )
{
m_ses . m_alerts . post_alert (
anonymous_mode_alert ( get_handle ( )
, anonymous_mode_alert : : tracker_not_anonymous , req . url ) ) ;
}
continue ;
}
}
2008-12-30 09:20:25 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " ==> TACKER REQUEST " < < req . url
< < " event= " < < ( req . event = = tracker_request : : stopped ? " stopped "
: req . event = = tracker_request : : started ? " started " : " " )
< < " abort= " < < m_abort < < " \n " ;
2008-11-29 09:38:40 +01:00
if ( m_abort )
{
boost : : shared_ptr < aux : : tracker_logger > tl ( new aux : : tracker_logger ( m_ses ) ) ;
m_ses . m_tracker_manager . queue_request ( m_ses . m_io_service , m_ses . m_half_open , req
2009-05-15 23:23:41 +02:00
, tracker_login ( ) , tl ) ;
2008-11-29 09:38:40 +01:00
}
else
2008-07-12 10:25:19 +02:00
# endif
2011-09-12 07:21:16 +02:00
m_ses . m_tracker_manager . queue_request ( m_ses . m_io_service , m_ses . m_half_open , req
, tracker_login ( ) , shared_from_this ( ) ) ;
2008-11-29 09:38:40 +01:00
ae . updating = true ;
2010-07-18 01:32:17 +02:00
ae . next_announce = now + seconds ( 20 ) ;
ae . min_announce = now + seconds ( 10 ) ;
2008-07-12 10:25:19 +02:00
2008-11-29 09:38:40 +01:00
if ( m_ses . m_alerts . should_post < tracker_announce_alert > ( ) )
{
m_ses . m_alerts . post_alert (
tracker_announce_alert ( get_handle ( ) , req . url , req . event ) ) ;
}
2009-06-28 22:21:55 +02:00
sent_announce = true ;
if ( ae . is_working ( )
2010-02-14 02:39:55 +01:00
& & ! settings ( ) . announce_to_all_trackers
& & ! settings ( ) . announce_to_all_tiers )
2009-06-28 22:21:55 +02:00
break ;
2008-07-12 10:25:19 +02:00
}
2010-05-03 10:24:30 +02:00
update_tracker_timer ( now ) ;
2008-07-12 10:25:19 +02:00
}
2007-11-20 23:46:27 +01:00
void torrent : : scrape_tracker ( )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-02-14 02:39:55 +01:00
m_last_scrape = 0 ;
2009-12-02 05:05:24 +01:00
2007-11-20 23:46:27 +01:00
if ( m_trackers . empty ( ) ) return ;
2008-11-27 21:48:29 +01:00
int i = m_last_working_tracker ;
if ( i = = - 1 ) i = 0 ;
2007-11-20 23:46:27 +01:00
tracker_request req ;
2011-03-04 07:55:39 +01:00
req . apply_ip_filter = m_apply_ip_filter & & m_ses . m_settings . apply_ip_filter_to_trackers ;
2007-11-20 23:46:27 +01:00
req . info_hash = m_torrent_file - > info_hash ( ) ;
req . kind = tracker_request : : scrape_request ;
2008-11-27 21:48:29 +01:00
req . url = m_trackers [ i ] . url ;
2009-05-15 23:23:41 +02:00
req . bind_ip = m_ses . m_listen_interface . address ( ) ;
2008-01-08 06:47:43 +01:00
m_ses . m_tracker_manager . queue_request ( m_ses . m_io_service , m_ses . m_half_open , req
2009-05-15 23:23:41 +02:00
, tracker_login ( ) , shared_from_this ( ) ) ;
2007-11-20 23:46:27 +01:00
}
2008-04-23 03:54:21 +02:00
void torrent : : tracker_warning ( tracker_request const & req , std : : string const & msg )
2005-08-11 01:32:39 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-03-31 00:00:26 +02:00
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < tracker_warning_alert > ( ) )
2008-04-23 03:54:21 +02:00
m_ses . m_alerts . post_alert ( tracker_warning_alert ( get_handle ( ) , req . url , msg ) ) ;
2005-08-11 01:32:39 +02:00
}
2007-11-20 23:46:27 +01:00
void torrent : : tracker_scrape_response ( tracker_request const & req
2010-09-06 06:02:15 +02:00
, int complete , int incomplete , int downloaded , int downloaders )
2007-11-20 23:46:27 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-11-20 23:46:27 +01:00
INVARIANT_CHECK ;
TORRENT_ASSERT ( req . kind = = tracker_request : : scrape_request ) ;
2011-11-15 03:34:00 +01:00
if ( ( complete > = 0 & & m_complete ! = complete )
| | ( incomplete > = 0 & & m_incomplete ! = incomplete )
| | ( downloaders > = 0 & & m_downloaders ! = downloaders ) )
state_updated ( ) ;
if ( complete > = 0 ) m_complete = complete ;
if ( incomplete > = 0 ) m_incomplete = incomplete ;
if ( downloaders > = 0 ) m_downloaders = downloaders ;
if ( m_ses . m_alerts . should_post < scrape_reply_alert > ( ) )
{
m_ses . m_alerts . post_alert ( scrape_reply_alert (
get_handle ( ) , m_incomplete , m_complete , req . url ) ) ;
}
}
2007-11-20 23:46:27 +01:00
2004-01-21 14:16:11 +01:00
void torrent : : tracker_response (
2007-11-21 00:19:30 +01:00
tracker_request const & r
2009-05-15 23:23:41 +02:00
, address const & tracker_ip // this is the IP we connected to
, std : : list < address > const & tracker_ips // these are all the IPs it resolved to
2005-03-24 13:13:47 +01:00
, std : : vector < peer_entry > & peer_list
2005-02-21 14:59:24 +01:00
, int interval
2009-12-02 05:05:24 +01:00
, int min_interval
2005-02-21 14:59:24 +01:00
, int complete
2008-03-29 23:45:55 +01:00
, int incomplete
2010-11-18 06:51:52 +01:00
, address const & external_ip
, const std : : string & trackerid )
2003-10-23 01:00:57 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-04-25 23:04:48 +02:00
2007-03-31 00:00:26 +02:00
INVARIANT_CHECK ;
2007-11-20 23:46:27 +01:00
TORRENT_ASSERT ( r . kind = = tracker_request : : announce_request ) ;
2007-03-31 00:00:26 +02:00
2010-12-24 02:31:41 +01:00
TORRENT_ASSERT ( ! tracker_ips . empty ( ) ) ;
2008-03-29 23:45:55 +01:00
if ( external_ip ! = address ( ) )
2010-12-24 02:31:41 +01:00
m_ses . set_external_address ( external_ip , aux : : session_impl : : source_tracker
, * tracker_ips . begin ( ) ) ;
2008-03-29 23:45:55 +01:00
2008-11-29 09:38:40 +01:00
ptime now = time_now ( ) ;
2008-08-02 00:34:37 +02:00
2010-02-14 02:39:55 +01:00
if ( interval < settings ( ) . min_announce_interval )
interval = settings ( ) . min_announce_interval ;
2004-01-25 13:37:15 +01:00
2008-11-29 09:38:40 +01:00
announce_entry * ae = find_tracker ( r ) ;
if ( ae )
2008-11-27 21:48:29 +01:00
{
2008-11-29 09:38:40 +01:00
if ( ! ae - > start_sent & & r . event = = tracker_request : : started )
ae - > start_sent = true ;
if ( ! ae - > complete_sent & & r . event = = tracker_request : : completed )
ae - > complete_sent = true ;
ae - > verified = true ;
ae - > updating = false ;
ae - > fails = 0 ;
ae - > next_announce = now + seconds ( interval ) ;
2009-12-02 05:05:24 +01:00
ae - > min_announce = now + seconds ( min_interval ) ;
2008-11-29 09:38:40 +01:00
int tracker_index = ae - & m_trackers [ 0 ] ;
m_last_working_tracker = prioritize_tracker ( tracker_index ) ;
2010-11-18 06:51:52 +01:00
if ( ( ! trackerid . empty ( ) ) & & ( ae - > trackerid ! = trackerid ) )
{
ae - > trackerid = trackerid ;
if ( m_ses . m_alerts . should_post < trackerid_alert > ( ) )
m_ses . m_alerts . post_alert ( trackerid_alert ( get_handle ( ) , r . url , trackerid ) ) ;
}
2008-11-27 21:48:29 +01:00
}
2010-05-03 10:24:30 +02:00
update_tracker_timer ( now ) ;
2003-10-23 18:55:52 +02:00
2005-02-21 14:59:24 +01:00
if ( complete > = 0 ) m_complete = complete ;
if ( incomplete > = 0 ) m_incomplete = incomplete ;
2008-05-19 06:06:25 +02:00
if ( complete > = 0 & & incomplete > = 0 )
2010-02-14 02:39:55 +01:00
m_last_scrape = 0 ;
2006-04-25 23:04:48 +02:00
2009-04-04 11:52:25 +02:00
# if (defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING) && TORRENT_USE_IOSTREAM
2004-01-21 14:16:11 +01:00
std : : stringstream s ;
2004-01-22 23:45:52 +01:00
s < < " TRACKER RESPONSE: \n "
2008-11-29 09:38:40 +01:00
" interval: " < < interval < < " \n "
2004-01-22 23:45:52 +01:00
" peers: \n " ;
2004-01-21 14:16:11 +01:00
for ( std : : vector < peer_entry > : : const_iterator i = peer_list . begin ( ) ;
2005-07-06 02:58:23 +02:00
i ! = peer_list . end ( ) ; + + i )
2003-10-23 01:00:57 +02:00
{
2004-01-21 14:16:11 +01:00
s < < " " < < std : : setfill ( ' ' ) < < std : : setw ( 16 ) < < i - > ip
2004-01-22 23:45:52 +01:00
< < " " < < std : : setw ( 5 ) < < std : : dec < < i - > port < < " " ;
2006-04-25 23:04:48 +02:00
if ( ! i - > pid . is_all_zeros ( ) ) s < < " " < < i - > pid < < " " < < identify_client ( i - > pid ) ;
2004-01-22 23:45:52 +01:00
s < < " \n " ;
2003-10-23 01:00:57 +02:00
}
2008-03-29 23:45:55 +01:00
s < < " external ip: " < < external_ip < < " \n " ;
2009-05-15 23:23:41 +02:00
s < < " tracker ips: " ;
std : : copy ( tracker_ips . begin ( ) , tracker_ips . end ( ) , std : : ostream_iterator < address > ( s , " " ) ) ;
s < < " \n " ;
s < < " we connected to: " < < tracker_ip < < " \n " ;
2004-01-21 14:16:11 +01:00
debug_log ( s . str ( ) ) ;
# endif
// for each of the peers we got from the tracker
for ( std : : vector < peer_entry > : : iterator i = peer_list . begin ( ) ;
2005-07-06 02:58:23 +02:00
i ! = peer_list . end ( ) ; + + i )
2003-10-23 01:00:57 +02:00
{
2004-01-21 14:16:11 +01:00
// don't make connections to ourself
2006-04-25 23:04:48 +02:00
if ( i - > pid = = m_ses . get_peer_id ( ) )
2004-01-21 14:16:11 +01:00
continue ;
2008-05-03 18:05:42 +02:00
error_code ec ;
2008-04-07 04:51:21 +02:00
tcp : : endpoint a ( address : : from_string ( i - > ip , ec ) , i - > port ) ;
if ( ec )
2005-07-06 02:58:23 +02:00
{
2008-04-07 04:51:21 +02:00
// assume this is because we got a hostname instead of
// an ip address from the tracker
2007-03-07 19:50:38 +01:00
2009-08-20 05:19:12 +02:00
# if TORRENT_USE_I2P
char const * top_domain = strrchr ( i - > ip . c_str ( ) , ' . ' ) ;
if ( top_domain & & strcmp ( top_domain , " .i2p " ) = = 0 & & m_ses . m_i2p_conn . is_open ( ) )
{
// this is an i2p name, we need to use the sam connection
// to do the name lookup
/*
m_ses . m_i2p_conn . async_name_lookup ( i - > ip . c_str ( )
2010-04-30 21:08:16 +02:00
, boost : : bind ( & torrent : : on_i2p_resolve
2009-08-20 05:19:12 +02:00
, shared_from_this ( ) , _1 , _2 ) ) ;
*/
// it seems like you're not supposed to do a name lookup
// on the peers returned from the tracker, but just strip
// the .i2p and use it as a destination
i - > ip . resize ( i - > ip . size ( ) - 4 ) ;
m_policy . add_i2p_peer ( i - > ip . c_str ( ) , peer_info : : tracker , 0 ) ;
}
else
# endif
{
2010-11-28 02:47:30 +01:00
# if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async ( " torrent::on_peer_name_lookup " ) ;
# endif
2009-08-20 05:19:12 +02:00
tcp : : resolver : : query q ( i - > ip , to_string ( i - > port ) . elems ) ;
2010-02-14 02:39:55 +01:00
m_ses . m_host_resolver . async_resolve ( q ,
2010-04-30 21:08:16 +02:00
boost : : bind ( & torrent : : on_peer_name_lookup , shared_from_this ( ) , _1 , _2 , i - > pid ) ) ;
2009-08-20 05:19:12 +02:00
}
2008-04-07 04:51:21 +02:00
}
else
{
2008-12-01 09:48:54 +01:00
// ignore local addresses from the tracker (unless the tracker is local too)
2011-12-12 08:03:51 +01:00
// there are 2 reasons to allow this:
// 1. retrackers are popular in russia, where an ISP runs a tracker within
// the AS (but not on the local network) giving out peers only from the
// local network
// 2. it might make sense to have a tracker extension in the future where
// trackers records a peer's internal and external IP, and match up
// peers on the same local network
// if (is_local(a.address()) && !is_local(tracker_ip)) continue;
2009-05-16 00:07:19 +02:00
m_policy . add_peer ( a , i - > pid , peer_info : : tracker , 0 ) ;
2007-03-07 19:50:38 +01:00
}
2003-10-23 01:00:57 +02:00
}
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < tracker_reply_alert > ( ) )
2005-03-10 10:59:12 +01:00
{
m_ses . m_alerts . post_alert ( tracker_reply_alert (
2008-07-06 14:22:56 +02:00
get_handle ( ) , peer_list . size ( ) , r . url ) ) ;
2005-03-10 10:59:12 +01:00
}
2003-12-22 08:14:35 +01:00
m_got_tracker_response = true ;
2009-05-15 23:23:41 +02:00
// we're listening on an interface type that was not used
// when talking to the tracker. If there is a matching interface
// type in the tracker IP list, make another tracker request
// using that interface
// in order to avoid triggering this case over and over, don't
// do it if the bind IP for the tracker request that just completed
// matches one of the listen interfaces, since that means this
// announce was the second one
// don't connect twice just to tell it we're stopping
if ( ( ( ! is_any ( m_ses . m_ipv6_interface . address ( ) ) & & tracker_ip . is_v4 ( ) )
| | ( ! is_any ( m_ses . m_ipv4_interface . address ( ) ) & & tracker_ip . is_v6 ( ) ) )
& & r . bind_ip ! = m_ses . m_ipv4_interface . address ( )
& & r . bind_ip ! = m_ses . m_ipv6_interface . address ( )
& & r . event ! = tracker_request : : stopped )
{
std : : list < address > : : const_iterator i = std : : find_if ( tracker_ips . begin ( )
, tracker_ips . end ( ) , boost : : bind ( & address : : is_v4 , _1 ) ! = tracker_ip . is_v4 ( ) ) ;
if ( i ! = tracker_ips . end ( ) )
{
2010-08-03 11:08:37 +02:00
// the tracker did resolve to a different type of address, so announce
2009-05-15 23:23:41 +02:00
// to that as well
// tell the tracker to bind to the opposite protocol type
address bind_interface = tracker_ip . is_v4 ( )
? m_ses . m_ipv6_interface . address ( )
: m_ses . m_ipv4_interface . address ( ) ;
announce_with_tracker ( r . event , bind_interface ) ;
# if (defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING) && TORRENT_USE_IOSTREAM
debug_log ( " announce again using " + print_address ( bind_interface )
+ " as the bind interface " ) ;
# endif
}
}
2010-12-17 04:10:56 +01:00
if ( m_need_connect_boost )
{
m_need_connect_boost = false ;
// this is the first tracker response for this torrent
// instead of waiting one second for session_impl::on_tick()
// to be called, connect to a few peers immediately
2010-12-19 00:18:20 +01:00
int conns = ( std : : min ) ( ( std : : min ) ( ( std : : min ) ( m_ses . m_settings . torrent_connect_boost
2010-12-17 04:10:56 +01:00
, m_ses . m_settings . connections_limit - m_ses . num_connections ( ) )
2010-12-19 00:18:20 +01:00
, m_ses . m_half_open . free_slots ( ) )
, m_ses . m_boost_connections - m_ses . m_settings . connection_speed ) ;
2010-12-17 04:10:56 +01:00
while ( want_more_peers ( ) & & conns > 0 )
{
if ( ! m_policy . connect_one_peer ( m_ses . session_time ( ) ) ) break ;
// increase m_ses.m_boost_connections for each connection
// attempt. This will be deducted from the connect speed
// the next time session_impl::on_tick() is triggered
- - conns ;
+ + m_ses . m_boost_connections ;
}
}
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2003-10-23 01:00:57 +02:00
}
2009-12-13 17:36:45 +01:00
ptime torrent : : next_announce ( ) const
{
return m_waiting_tracker ? m_tracker_timer . expires_at ( ) : min_time ( ) ;
}
void torrent : : force_tracker_request ( )
{
2010-07-18 01:32:17 +02:00
force_tracker_request ( time_now_hires ( ) ) ;
2009-12-13 17:36:45 +01:00
}
void torrent : : force_tracker_request ( ptime t )
{
if ( is_paused ( ) ) return ;
for ( std : : vector < announce_entry > : : iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
2010-07-18 01:32:17 +02:00
i - > next_announce = ( std : : max ) ( t , i - > min_announce ) + seconds ( 1 ) ;
2010-07-15 07:16:06 +02:00
update_tracker_timer ( time_now_hires ( ) ) ;
2009-12-13 17:36:45 +01:00
}
void torrent : : set_tracker_login (
std : : string const & name
, std : : string const & pw )
{
m_username = name ;
m_password = pw ;
}
2009-08-20 05:19:12 +02:00
# if TORRENT_USE_I2P
void torrent : : on_i2p_resolve ( error_code const & ec , char const * dest )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-08-20 05:19:12 +02:00
INVARIANT_CHECK ;
2009-12-07 06:03:23 +01:00
# if defined TORRENT_LOGGING
if ( ec )
2010-02-05 09:23:17 +01:00
* m_ses . m_logger < < time_now_string ( ) < < " on_i2p_resolve: " < < ec . message ( ) < < " \n " ;
2009-12-07 06:03:23 +01:00
# endif
2009-08-20 05:19:12 +02:00
if ( ec | | m_ses . is_aborted ( ) ) return ;
m_policy . add_i2p_peer ( dest , peer_info : : tracker , 0 ) ;
}
# endif
2008-05-03 18:05:42 +02:00
void torrent : : on_peer_name_lookup ( error_code const & e , tcp : : resolver : : iterator host
2008-04-07 04:51:21 +02:00
, peer_id pid )
2007-03-07 19:50:38 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-03-07 19:50:38 +01:00
INVARIANT_CHECK ;
2010-11-28 02:47:30 +01:00
# if defined TORRENT_ASIO_DEBUGGING
complete_async ( " torrent::on_peer_name_lookup " ) ;
# endif
2009-12-07 06:03:23 +01:00
# if defined TORRENT_LOGGING
2010-02-05 09:23:17 +01:00
if ( e )
2009-12-07 06:03:23 +01:00
* m_ses . m_logger < < time_now_string ( ) < < " on_peer_name_lookup: " < < e . message ( ) < < " \n " ;
# endif
2007-03-07 19:50:38 +01:00
if ( e | | host = = tcp : : resolver : : iterator ( ) | |
m_ses . is_aborted ( ) ) return ;
2011-02-27 18:26:57 +01:00
if ( m_apply_ip_filter
& & m_ses . m_ip_filter . access ( host - > endpoint ( ) . address ( ) ) & ip_filter : : blocked )
2007-03-07 19:50:38 +01:00
{
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2008-10-23 06:10:23 +02:00
error_code ec ;
debug_log ( " blocked ip from tracker: " + host - > endpoint ( ) . address ( ) . to_string ( ec ) ) ;
2007-03-07 19:50:38 +01:00
# endif
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < peer_blocked_alert > ( ) )
2009-09-07 03:47:30 +02:00
m_ses . m_alerts . post_alert ( peer_blocked_alert ( get_handle ( ) , host - > endpoint ( ) . address ( ) ) ) ;
2007-03-07 19:50:38 +01:00
return ;
}
2009-05-16 00:07:19 +02:00
m_policy . add_peer ( * host , pid , peer_info : : tracker , 0 ) ;
2007-03-07 19:50:38 +01:00
}
2004-01-18 02:58:33 +01:00
size_type torrent : : bytes_left ( ) const
2003-12-07 06:53:04 +01:00
{
2004-06-14 01:30:42 +02:00
// if we don't have the metadata yet, we
// cannot tell how big the torrent is.
if ( ! valid_metadata ( ) ) return - 1 ;
2007-09-01 05:00:31 +02:00
return m_torrent_file - > total_size ( )
2006-09-24 02:48:31 +02:00
- quantized_bytes_done ( ) ;
}
size_type torrent : : quantized_bytes_done ( ) const
{
2006-12-11 13:48:33 +01:00
// INVARIANT_CHECK;
2006-09-24 02:48:31 +02:00
if ( ! valid_metadata ( ) ) return 0 ;
2007-09-01 05:00:31 +02:00
if ( m_torrent_file - > num_pieces ( ) = = 0 )
2006-09-24 02:48:31 +02:00
return 0 ;
2006-12-04 13:20:34 +01:00
2007-09-01 05:00:31 +02:00
if ( is_seed ( ) ) return m_torrent_file - > total_size ( ) ;
2006-12-04 13:20:34 +01:00
2007-09-01 05:00:31 +02:00
const int last_piece = m_torrent_file - > num_pieces ( ) - 1 ;
2006-09-24 02:48:31 +02:00
size_type total_done
2008-06-07 16:03:21 +02:00
= size_type ( num_have ( ) ) * m_torrent_file - > piece_length ( ) ;
2006-09-24 02:48:31 +02:00
// if we have the last piece, we have to correct
// the amount we have, since the first calculation
// assumed all pieces were of equal size
2008-06-07 04:58:28 +02:00
if ( m_picker - > have_piece ( last_piece ) )
2006-09-24 02:48:31 +02:00
{
2007-09-01 05:00:31 +02:00
int corr = m_torrent_file - > piece_size ( last_piece )
- m_torrent_file - > piece_length ( ) ;
2006-09-24 02:48:31 +02:00
total_done + = corr ;
}
return total_done ;
2004-01-15 17:45:34 +01:00
}
2009-01-14 08:41:25 +01:00
// returns the number of bytes we are interested
2010-02-14 02:39:55 +01:00
// in for the given block. This returns block_size()
2009-01-14 08:41:25 +01:00
// for all blocks except the last one (if it's smaller
2010-02-14 02:39:55 +01:00
// than block_size()) and blocks that overlap a padding
2009-01-14 08:41:25 +01:00
// file
int torrent : : block_bytes_wanted ( piece_block const & p ) const
{
file_storage const & fs = m_torrent_file - > files ( ) ;
int piece_size = m_torrent_file - > piece_size ( p . piece_index ) ;
2010-02-14 02:39:55 +01:00
int offset = p . block_index * block_size ( ) ;
if ( m_padding = = 0 ) return ( std : : min ) ( piece_size - offset , int ( block_size ( ) ) ) ;
2009-01-14 08:41:25 +01:00
std : : vector < file_slice > files = fs . map_block (
2010-02-14 02:39:55 +01:00
p . piece_index , offset , ( std : : min ) ( piece_size - offset , int ( block_size ( ) ) ) ) ;
2009-01-14 08:41:25 +01:00
int ret = 0 ;
for ( std : : vector < file_slice > : : iterator i = files . begin ( )
, end ( files . end ( ) ) ; i ! = end ; + + i )
{
file_entry const & fe = fs . at ( i - > file_index ) ;
if ( fe . pad_file ) continue ;
ret + = i - > size ;
}
2010-02-14 02:39:55 +01:00
TORRENT_ASSERT ( ret < = ( std : : min ) ( piece_size - offset , int ( block_size ( ) ) ) ) ;
2009-01-14 08:41:25 +01:00
return ret ;
}
// fills in total_wanted, total_wanted_done and total_done
2010-03-04 20:15:23 +01:00
void torrent : : bytes_done ( torrent_status & st , bool accurate ) const
2004-01-15 17:45:34 +01:00
{
2006-05-28 21:03:54 +02:00
INVARIANT_CHECK ;
2009-01-14 08:41:25 +01:00
st . total_done = 0 ;
st . total_wanted_done = 0 ;
st . total_wanted = m_torrent_file - > total_size ( ) ;
2009-01-19 10:52:08 +01:00
TORRENT_ASSERT ( st . total_wanted > = m_padding ) ;
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_wanted > = 0 ) ;
2007-09-01 05:00:31 +02:00
if ( ! valid_metadata ( ) | | m_torrent_file - > num_pieces ( ) = = 0 )
2009-01-14 08:41:25 +01:00
return ;
2007-03-17 00:28:26 +01:00
2011-12-30 22:32:27 +01:00
TORRENT_ASSERT ( st . total_wanted > = size_type ( m_torrent_file - > piece_length ( ) )
2009-01-24 19:11:06 +01:00
* ( m_torrent_file - > num_pieces ( ) - 1 ) ) ;
2007-09-01 05:00:31 +02:00
const int last_piece = m_torrent_file - > num_pieces ( ) - 1 ;
2007-11-27 00:08:59 +01:00
const int piece_size = m_torrent_file - > piece_length ( ) ;
2004-01-15 17:45:34 +01:00
2006-12-04 13:20:34 +01:00
if ( is_seed ( ) )
2009-01-14 08:41:25 +01:00
{
st . total_done = m_torrent_file - > total_size ( ) - m_padding ;
st . total_wanted_done = st . total_done ;
st . total_wanted = st . total_done ;
return ;
}
2006-12-04 13:20:34 +01:00
2008-06-07 16:03:21 +02:00
TORRENT_ASSERT ( num_have ( ) > = m_picker - > num_have_filtered ( ) ) ;
2009-01-14 08:41:25 +01:00
st . total_wanted_done = size_type ( num_have ( ) - m_picker - > num_have_filtered ( ) )
2007-11-27 00:08:59 +01:00
* piece_size ;
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_wanted_done > = 0 ) ;
2005-05-30 19:43:03 +02:00
2009-01-14 08:41:25 +01:00
st . total_done = size_type ( num_have ( ) ) * piece_size ;
2008-06-07 16:03:21 +02:00
TORRENT_ASSERT ( num_have ( ) < m_torrent_file - > num_pieces ( ) ) ;
2004-01-15 17:45:34 +01:00
2009-01-14 08:41:25 +01:00
int num_filtered_pieces = m_picker - > num_filtered ( )
+ m_picker - > num_have_filtered ( ) ;
int last_piece_index = m_torrent_file - > num_pieces ( ) - 1 ;
if ( m_picker - > piece_priority ( last_piece_index ) = = 0 )
{
st . total_wanted - = m_torrent_file - > piece_size ( last_piece_index ) ;
- - num_filtered_pieces ;
}
st . total_wanted - = size_type ( num_filtered_pieces ) * piece_size ;
2004-01-15 17:45:34 +01:00
// if we have the last piece, we have to correct
// the amount we have, since the first calculation
// assumed all pieces were of equal size
2008-06-07 04:58:28 +02:00
if ( m_picker - > have_piece ( last_piece ) )
2003-12-07 06:53:04 +01:00
{
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_done > = piece_size ) ;
2007-09-01 05:00:31 +02:00
int corr = m_torrent_file - > piece_size ( last_piece )
2007-11-27 00:08:59 +01:00
- piece_size ;
TORRENT_ASSERT ( corr < = 0 ) ;
TORRENT_ASSERT ( corr > - piece_size ) ;
2009-01-14 08:41:25 +01:00
st . total_done + = corr ;
2007-03-15 23:03:56 +01:00
if ( m_picker - > piece_priority ( last_piece ) ! = 0 )
2007-11-27 00:08:59 +01:00
{
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_wanted_done > = piece_size ) ;
st . total_wanted_done + = corr ;
2007-11-27 00:08:59 +01:00
}
2003-12-07 06:53:04 +01:00
}
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_wanted > = st . total_wanted_done ) ;
2003-12-07 06:53:04 +01:00
2009-01-14 08:41:25 +01:00
// subtract padding files
if ( m_padding > 0 )
{
file_storage const & files = m_torrent_file - > files ( ) ;
int fileno = 0 ;
for ( file_storage : : iterator i = files . begin ( )
, end ( files . end ( ) ) ; i ! = end ; + + i , + + fileno )
{
if ( ! i - > pad_file ) continue ;
peer_request p = files . map_file ( fileno , 0 , i - > size ) ;
for ( int j = p . piece ; p . length > 0 ; + + j , p . length - = piece_size )
{
int deduction = ( std : : min ) ( p . length , piece_size ) ;
2009-01-15 19:52:41 +01:00
bool done = m_picker - > have_piece ( j ) ;
bool wanted = m_picker - > piece_priority ( j ) > 0 ;
if ( done ) st . total_done - = deduction ;
if ( wanted ) st . total_wanted - = deduction ;
if ( wanted & & done ) st . total_wanted_done - = deduction ;
2009-01-14 08:41:25 +01:00
}
}
}
TORRENT_ASSERT ( st . total_done < = m_torrent_file - > total_size ( ) - m_padding ) ;
TORRENT_ASSERT ( st . total_wanted_done < = m_torrent_file - > total_size ( ) - m_padding ) ;
2009-01-15 19:52:41 +01:00
TORRENT_ASSERT ( st . total_wanted_done > = 0 ) ;
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_done > = st . total_wanted_done ) ;
2006-12-11 13:48:33 +01:00
2010-03-04 20:15:23 +01:00
// this is expensive, we might not want to do it all the time
if ( ! accurate ) return ;
2004-01-15 17:45:34 +01:00
const std : : vector < piece_picker : : downloading_piece > & dl_queue
2004-06-14 01:30:42 +02:00
= m_picker - > get_download_queue ( ) ;
2004-01-15 17:45:34 +01:00
2010-02-14 02:39:55 +01:00
const int blocks_per_piece = ( piece_size + block_size ( ) - 1 ) / block_size ( ) ;
2004-01-15 17:45:34 +01:00
2009-01-14 08:41:25 +01:00
// look at all unfinished pieces and add the completed
// blocks to our 'done' counter
2004-01-15 17:45:34 +01:00
for ( std : : vector < piece_picker : : downloading_piece > : : const_iterator i =
2005-05-30 19:43:03 +02:00
dl_queue . begin ( ) ; i ! = dl_queue . end ( ) ; + + i )
2004-01-15 17:45:34 +01:00
{
2005-05-30 19:43:03 +02:00
int corr = 0 ;
2006-12-31 15:48:18 +01:00
int index = i - > index ;
2009-01-14 08:41:25 +01:00
// completed pieces are already accounted for
2008-06-07 04:58:28 +02:00
if ( m_picker - > have_piece ( index ) ) continue ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( i - > finished < = m_picker - > blocks_in_piece ( index ) ) ;
2006-12-14 17:12:31 +01:00
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2006-12-14 17:12:31 +01:00
for ( std : : vector < piece_picker : : downloading_piece > : : const_iterator j = boost : : next ( i ) ;
j ! = dl_queue . end ( ) ; + + j )
{
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( j - > index ! = index ) ;
2006-12-14 17:12:31 +01:00
}
# endif
2004-01-15 17:45:34 +01:00
for ( int j = 0 ; j < blocks_per_piece ; + + j )
{
2009-09-09 18:34:50 +02:00
# ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( m_picker - > is_finished ( piece_block ( index , j ) )
= = ( i - > info [ j ] . state = = piece_picker : : block_info : : state_finished ) ) ;
2009-09-09 18:34:50 +02:00
# endif
2009-01-14 08:41:25 +01:00
if ( i - > info [ j ] . state = = piece_picker : : block_info : : state_finished )
{
corr + = block_bytes_wanted ( piece_block ( index , j ) ) ;
}
2007-11-27 00:08:59 +01:00
TORRENT_ASSERT ( corr > = 0 ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( index ! = last_piece | | j < m_picker - > blocks_in_last_piece ( )
2007-06-10 22:46:09 +02:00
| | i - > info [ j ] . state ! = piece_picker : : block_info : : state_finished ) ;
2004-01-15 17:45:34 +01:00
}
2009-01-14 08:41:25 +01:00
st . total_done + = corr ;
if ( m_picker - > piece_priority ( index ) > 0 )
st . total_wanted_done + = corr ;
2004-01-15 17:45:34 +01:00
}
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_wanted < = m_torrent_file - > total_size ( ) - m_padding ) ;
TORRENT_ASSERT ( st . total_done < = m_torrent_file - > total_size ( ) - m_padding ) ;
TORRENT_ASSERT ( st . total_wanted_done < = m_torrent_file - > total_size ( ) - m_padding ) ;
2009-01-15 19:52:41 +01:00
TORRENT_ASSERT ( st . total_wanted_done > = 0 ) ;
TORRENT_ASSERT ( st . total_done > = st . total_wanted_done ) ;
2006-12-15 13:29:47 +01:00
2004-09-16 03:14:16 +02:00
std : : map < piece_block , int > downloading_piece ;
for ( const_peer_iterator i = begin ( ) ; i ! = end ( ) ; + + i )
2004-01-15 17:45:34 +01:00
{
2007-10-31 10:48:20 +01:00
peer_connection * pc = * i ;
2004-01-15 17:45:34 +01:00
boost : : optional < piece_block_progress > p
2006-04-25 23:04:48 +02:00
= pc - > downloading_piece_progress ( ) ;
2009-01-14 08:41:25 +01:00
if ( ! p ) continue ;
2004-09-16 03:14:16 +02:00
2009-01-14 08:41:25 +01:00
if ( m_picker - > have_piece ( p - > piece_index ) )
continue ;
2003-12-07 06:53:04 +01:00
2009-01-14 08:41:25 +01:00
piece_block block ( p - > piece_index , p - > block_index ) ;
if ( m_picker - > is_finished ( block ) )
continue ;
std : : map < piece_block , int > : : iterator dp
= downloading_piece . find ( block ) ;
if ( dp ! = downloading_piece . end ( ) )
{
if ( dp - > second < p - > bytes_downloaded )
dp - > second = p - > bytes_downloaded ;
}
else
{
downloading_piece [ block ] = p - > bytes_downloaded ;
}
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( p - > bytes_downloaded < = p - > full_block_bytes ) ;
2010-02-23 17:26:24 +01:00
TORRENT_ASSERT ( p - > full_block_bytes = = to_req ( piece_block (
p - > piece_index , p - > block_index ) ) . length ) ;
2006-12-18 02:23:30 +01:00
# endif
2004-01-15 17:45:34 +01:00
}
2004-09-16 03:14:16 +02:00
for ( std : : map < piece_block , int > : : iterator i = downloading_piece . begin ( ) ;
i ! = downloading_piece . end ( ) ; + + i )
2005-05-30 19:43:03 +02:00
{
2009-01-14 08:41:25 +01:00
int done = ( std : : min ) ( block_bytes_wanted ( i - > first ) , i - > second ) ;
st . total_done + = done ;
2007-03-15 23:03:56 +01:00
if ( m_picker - > piece_priority ( i - > first . piece_index ) ! = 0 )
2009-01-14 08:41:25 +01:00
st . total_wanted_done + = done ;
2005-05-30 19:43:03 +02:00
}
2006-12-15 13:29:47 +01:00
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_done < = m_torrent_file - > total_size ( ) - m_padding ) ;
TORRENT_ASSERT ( st . total_wanted_done < = m_torrent_file - > total_size ( ) - m_padding ) ;
2008-06-07 04:58:28 +02:00
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2006-12-18 02:23:30 +01:00
2009-01-14 08:41:25 +01:00
if ( st . total_done > = m_torrent_file - > total_size ( ) )
2006-12-18 02:23:30 +01:00
{
2007-10-01 04:09:12 +02:00
// Thist happens when a piece has been downloaded completely
// but not yet verified against the hash
2009-10-28 20:55:20 +01:00
fprintf ( stderr , " num_have: %d \n unfinished: \n " , num_have ( ) ) ;
2006-12-18 02:23:30 +01:00
for ( std : : vector < piece_picker : : downloading_piece > : : const_iterator i =
dl_queue . begin ( ) ; i ! = dl_queue . end ( ) ; + + i )
{
2009-10-28 20:55:20 +01:00
fprintf ( stderr , " %d " , i - > index ) ;
2006-12-18 02:23:30 +01:00
for ( int j = 0 ; j < blocks_per_piece ; + + j )
{
2009-10-28 20:55:20 +01:00
char const * state = i - > info [ j ] . state = = piece_picker : : block_info : : state_finished ? " 1 " : " 0 " ;
fputs ( state , stderr ) ;
2006-12-18 02:23:30 +01:00
}
2009-10-28 20:55:20 +01:00
fputs ( " \n " , stderr ) ;
2006-12-18 02:23:30 +01:00
}
2009-10-28 20:55:20 +01:00
fputs ( " downloading pieces: \n " , stderr ) ;
2006-12-18 02:23:30 +01:00
for ( std : : map < piece_block , int > : : iterator i = downloading_piece . begin ( ) ;
i ! = downloading_piece . end ( ) ; + + i )
{
2011-07-20 07:14:25 +02:00
fprintf ( stderr , " %d:%d %d \n " , int ( i - > first . piece_index ) , int ( i - > first . block_index ) , i - > second ) ;
2006-12-18 02:23:30 +01:00
}
}
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_done < = m_torrent_file - > total_size ( ) ) ;
TORRENT_ASSERT ( st . total_wanted_done < = m_torrent_file - > total_size ( ) ) ;
2006-12-18 02:23:30 +01:00
# endif
2006-12-15 13:29:47 +01:00
2009-01-14 08:41:25 +01:00
TORRENT_ASSERT ( st . total_done > = st . total_wanted_done ) ;
2004-01-15 17:45:34 +01:00
}
2003-12-07 06:53:04 +01:00
2008-04-13 00:08:07 +02:00
// passed_hash_check
// 0: success, piece passed check
// -1: disk failure
// -2: piece failed check
void torrent : : piece_finished ( int index , int passed_hash_check )
2007-06-10 22:46:09 +02:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-12-30 09:20:25 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2007-10-18 02:32:16 +02:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " *** PIECE_FINISHED [ p: "
2008-04-20 19:17:58 +02:00
< < index < < " chk: " < < ( ( passed_hash_check = = 0 )
? " passed " : passed_hash_check = = - 1
2011-09-26 04:27:23 +02:00
? " disk failed " : " failed " ) < < " size: "
< < m_torrent_file - > piece_size ( index ) < < " ] \n " ;
2007-10-18 02:32:16 +02:00
# endif
2008-06-23 20:54:58 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2007-06-10 22:46:09 +02:00
2010-04-22 03:53:09 +02:00
TORRENT_ASSERT ( ! m_picker - > have_piece ( index ) ) ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2009-06-10 10:30:55 +02:00
// even though the piece passed the hash-check
// it might still have failed being written to disk
// if so, piece_picker::write_failed() has been
// called, and the piece is no longer finished.
// in this case, we have to ignore the fact that
// it passed the check
if ( ! m_picker - > is_piece_finished ( index ) ) return ;
2008-04-13 00:08:07 +02:00
if ( passed_hash_check = = 0 )
2007-06-10 22:46:09 +02:00
{
// the following call may cause picker to become invalid
// in case we just became a seed
2008-06-23 20:54:58 +02:00
piece_passed ( index ) ;
2009-02-03 08:46:24 +01:00
// if we're in seed mode, we just acquired this piece
// mark it as verified
if ( m_seed_mode ) verified ( index ) ;
2007-06-10 22:46:09 +02:00
}
2008-04-13 00:08:07 +02:00
else if ( passed_hash_check = = - 2 )
2007-06-10 22:46:09 +02:00
{
2008-06-22 22:28:03 +02:00
// piece_failed() will restore the piece
2007-06-10 22:46:09 +02:00
piece_failed ( index ) ;
}
2008-04-13 00:08:07 +02:00
else
{
TORRENT_ASSERT ( passed_hash_check = = - 1 ) ;
m_picker - > restore_piece ( index ) ;
2008-06-23 16:45:01 +02:00
restore_piece_state ( index ) ;
2008-04-13 00:08:07 +02:00
}
2007-06-10 22:46:09 +02:00
}
2009-01-05 02:08:09 +01:00
void torrent : : update_sparse_piece_prio ( int i , int start , int end )
{
TORRENT_ASSERT ( m_picker ) ;
if ( m_picker - > have_piece ( i ) | | m_picker - > piece_priority ( i ) = = 0 )
return ;
bool have_before = i = = 0 | | m_picker - > have_piece ( i - 1 ) ;
bool have_after = i = = end - 1 | | m_picker - > have_piece ( i + 1 ) ;
if ( have_after & & have_before )
m_picker - > set_piece_priority ( i , 7 ) ;
else if ( have_after | | have_before )
m_picker - > set_piece_priority ( i , 6 ) ;
}
2009-07-04 06:58:24 +02:00
void torrent : : we_have ( int index )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-07-04 06:58:24 +02:00
// update m_file_progress
TORRENT_ASSERT ( m_picker ) ;
TORRENT_ASSERT ( ! have_piece ( index ) ) ;
2010-04-24 21:24:27 +02:00
TORRENT_ASSERT ( ! m_picker - > have_piece ( index ) ) ;
2009-07-04 06:58:24 +02:00
const int piece_size = m_torrent_file - > piece_length ( ) ;
size_type off = size_type ( index ) * piece_size ;
file_storage : : iterator f = m_torrent_file - > files ( ) . file_at_offset ( off ) ;
int size = m_torrent_file - > piece_size ( index ) ;
int file_index = f - m_torrent_file - > files ( ) . begin ( ) ;
for ( ; size > 0 ; + + f , + + file_index )
{
size_type file_offset = off - f - > offset ;
TORRENT_ASSERT ( f ! = m_torrent_file - > files ( ) . end ( ) ) ;
2009-08-26 04:42:42 +02:00
TORRENT_ASSERT ( file_offset < = f - > size ) ;
2009-07-04 06:58:24 +02:00
int add = ( std : : min ) ( f - > size - file_offset , ( size_type ) size ) ;
m_file_progress [ file_index ] + = add ;
TORRENT_ASSERT ( m_file_progress [ file_index ]
< = m_torrent_file - > files ( ) . at ( file_index ) . size ) ;
if ( m_file_progress [ file_index ] > = m_torrent_file - > files ( ) . at ( file_index ) . size )
{
2010-03-21 19:19:59 +01:00
if ( ! m_torrent_file - > files ( ) . at ( file_index ) . pad_file )
2009-07-04 06:58:24 +02:00
{
2010-06-22 20:09:04 +02:00
if ( m_owning_storage . get ( ) )
m_storage - > async_finalize_file ( file_index ) ;
2010-03-21 19:19:59 +01:00
if ( m_ses . m_alerts . should_post < piece_finished_alert > ( ) )
{
// this file just completed, post alert
m_ses . m_alerts . post_alert ( file_completed_alert ( get_handle ( )
, file_index ) ) ;
}
2009-07-04 06:58:24 +02:00
}
}
size - = add ;
off + = add ;
TORRENT_ASSERT ( size > = 0 ) ;
}
m_picker - > we_have ( index ) ;
}
2008-06-23 20:54:58 +02:00
void torrent : : piece_passed ( int index )
{
// INVARIANT_CHECK;
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-06-23 20:54:58 +02:00
TORRENT_ASSERT ( index > = 0 ) ;
TORRENT_ASSERT ( index < m_torrent_file - > num_pieces ( ) ) ;
2010-04-24 21:24:27 +02:00
# ifdef TORRENT_DEBUG
// make sure all blocks were successfully written before we
2010-05-07 01:56:54 +02:00
// declare the piece as "we have".
2010-04-24 21:24:27 +02:00
piece_picker : : downloading_piece dp ;
m_picker - > piece_info ( index , dp ) ;
int blocks_in_piece = m_picker - > blocks_in_piece ( index ) ;
TORRENT_ASSERT ( dp . finished = = blocks_in_piece ) ;
TORRENT_ASSERT ( dp . writing = = 0 ) ;
TORRENT_ASSERT ( dp . requested = = 0 ) ;
TORRENT_ASSERT ( dp . index = = index ) ;
# endif
2008-06-23 20:54:58 +02:00
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < piece_finished_alert > ( ) )
2008-06-23 20:54:58 +02:00
{
m_ses . m_alerts . post_alert ( piece_finished_alert ( get_handle ( )
2008-07-06 14:22:56 +02:00
, index ) ) ;
2008-06-23 20:54:58 +02:00
}
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2010-05-17 01:12:37 +02:00
m_need_save_resume_data = true ;
2011-12-24 21:12:34 +01:00
state_updated ( ) ;
2010-05-17 01:12:37 +02:00
2009-03-17 10:34:44 +01:00
remove_time_critical_piece ( index , true ) ;
2008-06-23 20:54:58 +02:00
bool was_finished = m_picker - > num_filtered ( ) + num_have ( )
= = torrent_file ( ) . num_pieces ( ) ;
std : : vector < void * > downloaders ;
m_picker - > get_downloaders ( downloaders , index ) ;
// increase the trust point of all peers that sent
// parts of this piece.
std : : set < void * > peers ;
std : : copy ( downloaders . begin ( ) , downloaders . end ( ) , std : : inserter ( peers , peers . begin ( ) ) ) ;
2009-07-04 06:58:24 +02:00
we_have ( index ) ;
2008-07-18 12:03:42 +02:00
for ( peer_iterator i = m_connections . begin ( ) ; i ! = m_connections . end ( ) ; )
{
2011-05-25 18:06:51 +02:00
intrusive_ptr < peer_connection > p = * i ;
2008-07-18 12:03:42 +02:00
+ + i ;
p - > announce_piece ( index ) ;
}
2008-06-23 20:54:58 +02:00
for ( std : : set < void * > : : iterator i = peers . begin ( )
, end ( peers . end ( ) ) ; i ! = end ; + + i )
{
policy : : peer * p = static_cast < policy : : peer * > ( * i ) ;
if ( p = = 0 ) continue ;
p - > on_parole = false ;
2009-04-30 07:49:46 +02:00
int trust_points = p - > trust_points ;
+ + trust_points ;
if ( trust_points > 8 ) trust_points = 8 ;
p - > trust_points = trust_points ;
2008-06-23 20:54:58 +02:00
if ( p - > connection ) p - > connection - > received_valid_data ( index ) ;
}
2009-01-05 02:08:09 +01:00
if ( settings ( ) . max_sparse_regions > 0
& & m_picker - > sparse_regions ( ) > settings ( ) . max_sparse_regions )
{
// we have too many sparse regions. Prioritize pieces
// that won't introduce new sparse regions
// prioritize pieces that will reduce the number of sparse
// regions even higher
int start = m_picker - > cursor ( ) ;
int end = m_picker - > reverse_cursor ( ) ;
if ( index > start ) update_sparse_piece_prio ( index - 1 , start , end ) ;
if ( index < end - 1 ) update_sparse_piece_prio ( index + 1 , start , end ) ;
}
2008-06-23 20:54:58 +02:00
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
2011-02-25 18:00:36 +01:00
TORRENT_TRY {
2008-06-23 20:54:58 +02:00
( * i ) - > on_piece_pass ( index ) ;
2011-02-25 18:00:36 +01:00
} TORRENT_CATCH ( std : : exception & ) { }
2008-06-23 20:54:58 +02:00
}
# endif
// since this piece just passed, we might have
// become uninterested in some peers where this
// was the last piece we were interested in
2008-09-18 01:14:59 +02:00
for ( peer_iterator i = m_connections . begin ( ) ;
i ! = m_connections . end ( ) ; )
2008-06-23 20:54:58 +02:00
{
peer_connection * p = * i ;
2008-09-18 01:14:59 +02:00
// update_interest may disconnect the peer and
// invalidate the iterator
+ + i ;
2008-06-23 20:54:58 +02:00
// if we're not interested already, no need to check
if ( ! p - > is_interesting ( ) ) continue ;
// if the peer doesn't have the piece we just got, it
// wouldn't affect our interest
if ( ! p - > has_piece ( index ) ) continue ;
p - > update_interest ( ) ;
}
if ( ! was_finished & & is_finished ( ) )
{
// torrent finished
// i.e. all the pieces we're interested in have
// been downloaded. Release the files (they will open
// in read only mode if needed)
finished ( ) ;
// if we just became a seed, picker is now invalid, since it
// is deallocated by the torrent once it starts seeding
}
2010-07-08 21:29:38 +02:00
m_last_download = 0 ;
2010-09-05 18:01:36 +02:00
if ( m_share_mode )
recalc_share_mode ( ) ;
2008-06-23 20:54:58 +02:00
}
2003-12-01 22:27:27 +01:00
void torrent : : piece_failed ( int index )
{
2006-12-14 17:12:31 +01:00
// if the last piece fails the peer connection will still
// think that it has received all of it until this function
// resets the download queue. So, we cannot do the
// invariant check here since it assumes:
2007-09-01 05:00:31 +02:00
// (total_done == m_torrent_file->total_size()) => is_seed()
2007-10-31 10:48:20 +01:00
INVARIANT_CHECK ;
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-04-25 23:04:48 +02:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_storage ) ;
TORRENT_ASSERT ( m_storage - > refcount ( ) > 0 ) ;
TORRENT_ASSERT ( m_picker . get ( ) ) ;
TORRENT_ASSERT ( index > = 0 ) ;
TORRENT_ASSERT ( index < m_torrent_file - > num_pieces ( ) ) ;
2004-01-25 13:37:15 +01:00
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < hash_failed_alert > ( ) )
m_ses . m_alerts . post_alert ( hash_failed_alert ( get_handle ( ) , index ) ) ;
2004-04-18 14:28:02 +02:00
// increase the total amount of failed bytes
2008-07-11 09:30:04 +02:00
add_failed_bytes ( m_torrent_file - > piece_size ( index ) ) ;
2004-04-18 14:28:02 +02:00
2007-07-04 04:16:49 +02:00
std : : vector < void * > downloaders ;
2004-06-14 01:30:42 +02:00
m_picker - > get_downloaders ( downloaders , index ) ;
2003-12-01 22:27:27 +01:00
// decrease the trust point of all peers that sent
// parts of this piece.
2004-09-12 12:12:16 +02:00
// first, build a set of all peers that participated
2007-07-04 04:16:49 +02:00
std : : set < void * > peers ;
2004-09-12 12:12:16 +02:00
std : : copy ( downloaders . begin ( ) , downloaders . end ( ) , std : : inserter ( peers , peers . begin ( ) ) ) ;
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2007-12-18 07:04:54 +01:00
for ( std : : vector < void * > : : iterator i = downloaders . begin ( )
, end ( downloaders . end ( ) ) ; i ! = end ; + + i )
{
policy : : peer * p = ( policy : : peer * ) * i ;
if ( p & & p - > connection )
{
p - > connection - > piece_failed = true ;
}
}
# endif
2006-11-14 01:08:16 +01:00
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
2011-02-25 18:00:36 +01:00
TORRENT_TRY {
2008-04-07 04:51:21 +02:00
( * i ) - > on_piece_failed ( index ) ;
2011-02-25 18:00:36 +01:00
} TORRENT_CATCH ( std : : exception & ) { }
2006-11-14 01:08:16 +01:00
}
# endif
2007-07-04 04:16:49 +02:00
for ( std : : set < void * > : : iterator i = peers . begin ( )
2004-09-12 12:12:16 +02:00
, end ( peers . end ( ) ) ; i ! = end ; + + i )
2003-12-01 22:27:27 +01:00
{
2007-07-04 04:16:49 +02:00
policy : : peer * p = static_cast < policy : : peer * > ( * i ) ;
if ( p = = 0 ) continue ;
if ( p - > connection ) p - > connection - > received_invalid_data ( index ) ;
2003-12-14 06:56:12 +01:00
2004-09-12 12:12:16 +02:00
// either, we have received too many failed hashes
// or this was the only peer that sent us this piece.
2007-07-04 04:16:49 +02:00
if ( p - > trust_points < = - 7
2007-05-25 21:42:10 +02:00
| | peers . size ( ) = = 1 )
2003-12-01 22:27:27 +01:00
{
2003-12-14 06:56:12 +01:00
// we don't trust this peer anymore
// ban it.
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < peer_ban_alert > ( ) )
2004-03-21 03:03:37 +01:00
{
2008-08-19 16:53:50 +02:00
peer_id pid ( 0 ) ;
2008-07-08 11:30:10 +02:00
if ( p - > connection ) pid = p - > connection - > pid ( ) ;
2004-03-21 03:03:37 +01:00
m_ses . m_alerts . post_alert ( peer_ban_alert (
2008-07-14 13:15:35 +02:00
get_handle ( ) , p - > ip ( ) , pid ) ) ;
2004-03-21 03:03:37 +01:00
}
2007-04-13 03:53:25 +02:00
// mark the peer as banned
2009-06-18 18:16:41 +02:00
m_policy . ban_peer ( p ) ;
2011-03-17 06:31:06 +01:00
# ifdef TORRENT_STATS
+ + m_ses . m_banned_for_hash_failure ;
# endif
2005-09-01 23:04:21 +02:00
2007-07-04 04:16:49 +02:00
if ( p - > connection )
{
2007-12-19 22:36:54 +01:00
# ifdef TORRENT_LOGGING
2008-07-14 13:15:35 +02:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " *** BANNING PEER [ " < < p - > ip ( )
2007-12-19 22:36:54 +01:00
< < " ] 'too many corrupt pieces' \n " ;
2008-02-07 08:09:52 +01:00
# endif
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2008-07-14 13:15:35 +02:00
( * p - > connection - > m_logger ) < < " *** BANNING PEER [ " < < p - > ip ( )
2007-07-04 04:16:49 +02:00
< < " ] 'too many corrupt pieces' \n " ;
2005-09-01 23:04:21 +02:00
# endif
2009-11-29 08:06:38 +01:00
p - > connection - > disconnect ( errors : : too_many_corrupt_pieces ) ;
2007-07-04 04:16:49 +02:00
}
2003-12-01 22:27:27 +01:00
}
}
// we have to let the piece_picker know that
// this piece failed the check as it can restore it
// and mark it as being interesting for download
2004-06-14 01:30:42 +02:00
m_picker - > restore_piece ( index ) ;
2010-10-04 00:06:53 +02:00
// we might still have outstanding requests to this
// piece that hasn't been received yet. If this is the
// case, we need to re-open the piece and mark any
// blocks we're still waiting for as requested
2008-06-23 16:45:01 +02:00
restore_piece_state ( index ) ;
2010-10-04 00:06:53 +02:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_storage ) ;
2004-01-09 11:50:22 +01:00
2008-06-07 04:58:28 +02:00
TORRENT_ASSERT ( m_picker - > have_piece ( index ) = = false ) ;
2007-12-18 07:04:54 +01:00
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2007-12-18 07:04:54 +01:00
for ( std : : vector < void * > : : iterator i = downloaders . begin ( )
, end ( downloaders . end ( ) ) ; i ! = end ; + + i )
{
policy : : peer * p = ( policy : : peer * ) * i ;
if ( p & & p - > connection )
{
p - > connection - > piece_failed = false ;
}
}
# endif
2003-12-01 22:27:27 +01:00
}
2008-06-23 16:45:01 +02:00
void torrent : : restore_piece_state ( int index )
{
TORRENT_ASSERT ( has_picker ( ) ) ;
for ( peer_iterator i = m_connections . begin ( ) ;
i ! = m_connections . end ( ) ; + + i )
{
peer_connection * p = * i ;
2009-03-17 10:34:44 +01:00
std : : vector < pending_block > const & dq = p - > download_queue ( ) ;
2009-12-25 17:52:57 +01:00
std : : vector < pending_block > const & rq = p - > request_queue ( ) ;
2009-03-17 10:34:44 +01:00
for ( std : : vector < pending_block > : : const_iterator k = dq . begin ( )
2008-06-23 16:45:01 +02:00
, end ( dq . end ( ) ) ; k ! = end ; + + k )
{
2010-10-04 00:06:53 +02:00
if ( k - > timed_out | | k - > not_wanted ) continue ;
2011-02-21 06:24:41 +01:00
if ( int ( k - > block . piece_index ) ! = index ) continue ;
2008-07-07 14:04:06 +02:00
m_picker - > mark_as_downloading ( k - > block , p - > peer_info_struct ( )
2008-06-23 16:45:01 +02:00
, ( piece_picker : : piece_state_t ) p - > peer_speed ( ) ) ;
}
2009-12-25 17:52:57 +01:00
for ( std : : vector < pending_block > : : const_iterator k = rq . begin ( )
2008-06-23 16:45:01 +02:00
, end ( rq . end ( ) ) ; k ! = end ; + + k )
{
2011-02-21 06:24:41 +01:00
if ( int ( k - > block . piece_index ) ! = index ) continue ;
2009-12-25 17:52:57 +01:00
m_picker - > mark_as_downloading ( k - > block , p - > peer_info_struct ( )
2008-06-23 16:45:01 +02:00
, ( piece_picker : : piece_state_t ) p - > peer_speed ( ) ) ;
}
}
}
2005-03-05 15:17:17 +01:00
void torrent : : abort ( )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2009-02-09 03:04:43 +01:00
if ( m_abort ) return ;
2011-09-05 07:50:41 +02:00
# ifdef TORRENT_USE_OPENSSL
if ( m_torrent_file - > is_valid ( ) & & m_torrent_file - > encryption_key ( ) . size ( ) = = 32 & & m_in_encrypted_list )
{
m_ses . m_encrypted_torrents . erase ( shared_from_this ( ) ) ;
m_in_encrypted_list = false ;
}
2011-09-12 05:51:49 +02:00
if ( m_ssl_acceptor & & m_ssl_acceptor - > sock )
{
error_code ec ;
m_ssl_acceptor - > sock - > close ( ec ) ;
}
2011-09-05 07:50:41 +02:00
# endif
2005-03-05 15:17:17 +01:00
m_abort = true ;
2006-04-25 23:04:48 +02:00
// if the torrent is paused, it doesn't need
// to announce with even=stopped again.
2008-06-29 21:08:30 +02:00
if ( ! is_paused ( ) )
2008-07-12 10:25:19 +02:00
{
stop_announcing ( ) ;
}
2007-08-16 14:41:46 +02:00
2010-08-18 19:14:40 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING
log_to_all_peers ( " ABORTING TORRENT " ) ;
2007-08-16 14:41:46 +02:00
# endif
2008-07-12 10:25:19 +02:00
// disconnect all peers and close all
// files belonging to the torrents
2009-11-29 08:06:38 +01:00
disconnect_all ( errors : : torrent_aborted ) ;
2010-02-21 09:52:26 +01:00
// post a message to the main thread to destruct
// the torrent object from there
2007-10-02 20:34:34 +02:00
if ( m_owning_storage . get ( ) )
2008-11-17 02:19:46 +01:00
{
m_storage - > abort_disk_io ( ) ;
2010-02-21 09:52:26 +01:00
m_storage - > async_release_files (
2011-04-19 10:21:09 +02:00
boost : : bind ( & torrent : : on_cache_flushed , shared_from_this ( ) , _1 , _2 ) ) ;
2008-11-17 02:19:46 +01:00
}
2011-04-26 18:26:53 +02:00
else
{
if ( alerts ( ) . should_post < cache_flushed_alert > ( ) )
alerts ( ) . post_alert ( cache_flushed_alert ( get_handle ( ) ) ) ;
}
2008-10-26 10:23:00 +01:00
2009-02-09 03:04:43 +01:00
dequeue_torrent_check ( ) ;
2009-02-09 07:19:31 +01:00
if ( m_state = = torrent_status : : checking_files )
set_state ( torrent_status : : queued_for_checking ) ;
2007-06-10 22:46:09 +02:00
m_owning_storage = 0 ;
2010-02-14 02:39:55 +01:00
m_ses . m_host_resolver . cancel ( ) ;
2005-03-05 15:17:17 +01:00
}
2003-12-01 22:27:27 +01:00
2008-12-08 07:36:22 +01:00
void torrent : : super_seeding ( bool on )
{
if ( on = = m_super_seeding ) return ;
// don't turn on super seeding if we're not a seed
TORRENT_ASSERT ( ! on | | is_seed ( ) | | ! m_files_checked ) ;
if ( on & & ! is_seed ( ) & & m_files_checked ) return ;
m_super_seeding = on ;
if ( m_super_seeding ) return ;
// disable super seeding for all peers
for ( peer_iterator i = begin ( ) ; i ! = end ( ) ; + + i )
{
( * i ) - > superseed_piece ( - 1 ) ;
}
}
int torrent : : get_piece_to_super_seed ( bitfield const & bits )
{
// return a piece with low availability that is not in
// the bitfield and that is not currently being super
// seeded by any peer
TORRENT_ASSERT ( m_super_seeding ) ;
// do a linear search from the first piece
int min_availability = 9999 ;
std : : vector < int > avail_vec ;
for ( int i = 0 ; i < m_torrent_file - > num_pieces ( ) ; + + i )
{
if ( bits [ i ] ) continue ;
int availability = 0 ;
for ( const_peer_iterator j = begin ( ) ; j ! = end ( ) ; + + j )
{
if ( ( * j ) - > superseed_piece ( ) = = i )
{
// avoid superseeding the same piece to more than one
// peer if we can avoid it. Do this by artificially
// increase the availability
availability = 999 ;
break ;
}
if ( ( * j ) - > has_piece ( i ) ) + + availability ;
}
if ( availability > min_availability ) continue ;
if ( availability = = min_availability )
{
avail_vec . push_back ( i ) ;
continue ;
}
TORRENT_ASSERT ( availability < min_availability ) ;
min_availability = availability ;
avail_vec . clear ( ) ;
avail_vec . push_back ( i ) ;
}
if ( min_availability > 1 )
{
// if the minimum availability is 2 or more,
// we shouldn't be super seeding any more
super_seeding ( false ) ;
return - 1 ;
}
2011-02-26 08:55:51 +01:00
return avail_vec [ random ( ) % avail_vec . size ( ) ] ;
2008-12-08 07:36:22 +01:00
}
2007-10-13 05:33:33 +02:00
void torrent : : on_files_deleted ( int ret , disk_io_job const & j )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-13 05:33:33 +02:00
2008-07-06 14:22:56 +02:00
if ( ret ! = 0 )
2007-10-13 05:33:33 +02:00
{
2008-07-06 14:22:56 +02:00
if ( alerts ( ) . should_post < torrent_delete_failed_alert > ( ) )
2009-06-12 18:40:38 +02:00
alerts ( ) . post_alert ( torrent_delete_failed_alert ( get_handle ( ) , j . error ) ) ;
2008-07-06 14:22:56 +02:00
}
else
{
if ( alerts ( ) . should_post < torrent_deleted_alert > ( ) )
2010-01-23 23:42:48 +01:00
alerts ( ) . post_alert ( torrent_deleted_alert ( get_handle ( ) , m_torrent_file - > info_hash ( ) ) ) ;
2007-10-13 05:33:33 +02:00
}
}
2007-06-11 23:24:14 +02:00
void torrent : : on_files_released ( int ret , disk_io_job const & j )
2007-10-02 20:34:34 +02:00
{
/*
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-02 20:34:34 +02:00
2008-07-06 14:22:56 +02:00
if ( alerts ( ) . should_post < torrent_paused_alert > ( ) )
2007-10-02 20:34:34 +02:00
{
2008-07-06 14:22:56 +02:00
alerts ( ) . post_alert ( torrent_paused_alert ( get_handle ( ) ) ) ;
2007-10-02 20:34:34 +02:00
}
*/
}
2008-04-13 20:54:36 +02:00
void torrent : : on_save_resume_data ( int ret , disk_io_job const & j )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-04-13 20:54:36 +02:00
2009-09-23 20:44:21 +02:00
if ( ! j . resume_data )
2008-04-13 20:54:36 +02:00
{
2009-06-12 18:40:38 +02:00
alerts ( ) . post_alert ( save_resume_data_failed_alert ( get_handle ( ) , j . error ) ) ;
2008-07-06 14:22:56 +02:00
}
2009-09-23 20:44:21 +02:00
else
2008-07-06 14:22:56 +02:00
{
2010-04-12 02:36:31 +02:00
m_need_save_resume_data = false ;
2010-08-25 08:38:04 +02:00
m_last_saved_resume = time ( 0 ) ;
2008-07-06 14:22:56 +02:00
write_resume_data ( * j . resume_data ) ;
2008-04-13 20:54:36 +02:00
alerts ( ) . post_alert ( save_resume_data_alert ( j . resume_data
2008-07-06 14:22:56 +02:00
, get_handle ( ) ) ) ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2008-04-13 20:54:36 +02:00
}
}
2008-05-28 10:44:40 +02:00
void torrent : : on_file_renamed ( int ret , disk_io_job const & j )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-05-28 10:44:40 +02:00
2009-05-07 08:47:19 +02:00
if ( ret = = 0 )
2008-05-28 10:44:40 +02:00
{
2009-05-07 08:47:19 +02:00
if ( alerts ( ) . should_post < file_renamed_alert > ( ) )
alerts ( ) . post_alert ( file_renamed_alert ( get_handle ( ) , j . str , j . piece ) ) ;
m_torrent_file - > rename_file ( j . piece , j . str ) ;
}
else
{
if ( alerts ( ) . should_post < file_rename_failed_alert > ( ) )
alerts ( ) . post_alert ( file_rename_failed_alert ( get_handle ( )
, j . piece , j . error ) ) ;
2008-05-28 10:44:40 +02:00
}
}
2007-10-02 20:34:34 +02:00
void torrent : : on_torrent_paused ( int ret , disk_io_job const & j )
2007-06-11 23:24:14 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-06-11 23:24:14 +02:00
2008-07-06 14:22:56 +02:00
if ( alerts ( ) . should_post < torrent_paused_alert > ( ) )
alerts ( ) . post_alert ( torrent_paused_alert ( get_handle ( ) ) ) ;
2007-06-11 23:24:14 +02:00
}
2004-03-28 19:45:37 +02:00
std : : string torrent : : tracker_login ( ) const
2004-02-22 23:40:45 +01:00
{
if ( m_username . empty ( ) & & m_password . empty ( ) ) return " " ;
return m_username + " : " + m_password ;
}
2009-12-05 08:24:22 +01:00
void torrent : : set_piece_deadline ( int piece , int t , int flags )
2009-03-17 10:34:44 +01:00
{
2009-12-05 08:24:22 +01:00
ptime deadline = time_now ( ) + milliseconds ( t ) ;
2009-03-17 10:34:44 +01:00
if ( is_seed ( ) | | m_picker - > have_piece ( piece ) )
{
if ( flags & torrent_handle : : alert_when_available )
read_piece ( piece ) ;
return ;
}
for ( std : : list < time_critical_piece > : : iterator i = m_time_critical_pieces . begin ( )
, end ( m_time_critical_pieces . end ( ) ) ; i ! = end ; + + i )
{
if ( i - > piece ! = piece ) continue ;
i - > deadline = deadline ;
i - > flags = flags ;
// resort i since deadline might have changed
while ( boost : : next ( i ) ! = m_time_critical_pieces . end ( ) & & i - > deadline > boost : : next ( i ) - > deadline )
{
std : : iter_swap ( i , boost : : next ( i ) ) ;
+ + i ;
}
while ( i ! = m_time_critical_pieces . begin ( ) & & i - > deadline < boost : : prior ( i ) - > deadline )
{
std : : iter_swap ( i , boost : : next ( i ) ) ;
- - i ;
}
return ;
}
time_critical_piece p ;
p . first_requested = min_time ( ) ;
p . last_requested = min_time ( ) ;
p . flags = flags ;
p . deadline = deadline ;
p . peers = 0 ;
p . piece = piece ;
std : : list < time_critical_piece > : : iterator i = std : : upper_bound ( m_time_critical_pieces . begin ( )
, m_time_critical_pieces . end ( ) , p ) ;
m_time_critical_pieces . insert ( i , p ) ;
2011-08-06 12:57:32 +02:00
piece_picker : : downloading_piece pi ;
m_picker - > piece_info ( piece , pi ) ;
if ( pi . requested = = 0 ) return ;
// this means we have outstanding requests (or queued
// up requests that haven't been sent yet). Promote them
// to deadline pieces immediately
std : : vector < void * > downloaders ;
m_picker - > get_downloaders ( downloaders , piece ) ;
int block = 0 ;
for ( std : : vector < void * > : : iterator i = downloaders . begin ( )
, end ( downloaders . end ( ) ) ; i ! = end ; + + i , + + block )
{
policy : : peer * p = ( policy : : peer * ) * i ;
if ( p = = 0 | | p - > connection = = 0 ) continue ;
p - > connection - > make_time_critical ( piece_block ( piece , block ) ) ;
}
2009-03-17 10:34:44 +01:00
}
2011-08-05 08:31:46 +02:00
void torrent : : reset_piece_deadline ( int piece )
{
remove_time_critical_piece ( piece ) ;
}
2009-03-17 10:34:44 +01:00
void torrent : : remove_time_critical_piece ( int piece , bool finished )
{
for ( std : : list < time_critical_piece > : : iterator i = m_time_critical_pieces . begin ( )
, end ( m_time_critical_pieces . end ( ) ) ; i ! = end ; + + i )
{
if ( i - > piece ! = piece ) continue ;
if ( finished )
{
if ( i - > flags & torrent_handle : : alert_when_available )
{
read_piece ( i - > piece ) ;
}
// update the average download time and average
// download time deviation
2010-02-14 02:39:55 +01:00
int dl_time = total_milliseconds ( time_now ( ) - i - > first_requested ) ;
2009-03-17 10:34:44 +01:00
2010-02-14 02:39:55 +01:00
if ( m_average_piece_time = = 0 )
2009-03-17 10:34:44 +01:00
{
m_average_piece_time = dl_time ;
}
else
{
2010-02-15 06:49:10 +01:00
int diff = abs ( int ( dl_time - m_average_piece_time ) ) ;
2010-02-14 02:39:55 +01:00
if ( m_piece_time_deviation = = 0 ) m_piece_time_deviation = diff ;
2009-07-19 06:59:27 +02:00
else m_piece_time_deviation = ( m_piece_time_deviation * 6 + diff * 4 ) / 10 ;
2009-03-17 10:34:44 +01:00
2009-07-19 06:59:27 +02:00
m_average_piece_time = ( m_average_piece_time * 6 + dl_time * 4 ) / 10 ;
2009-03-17 10:34:44 +01:00
}
}
m_time_critical_pieces . erase ( i ) ;
return ;
}
}
// remove time critical pieces where priority is 0
void torrent : : remove_time_critical_pieces ( std : : vector < int > const & priority )
{
for ( std : : list < time_critical_piece > : : iterator i = m_time_critical_pieces . begin ( ) ;
i ! = m_time_critical_pieces . end ( ) ; )
{
if ( priority [ i - > piece ] = = 0 )
{
i = m_time_critical_pieces . erase ( i ) ;
continue ;
}
+ + i ;
}
}
2007-05-30 08:52:59 +02:00
void torrent : : piece_availability ( std : : vector < int > & avail ) const
{
INVARIANT_CHECK ;
2007-03-20 02:59:00 +01:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2007-05-30 08:52:59 +02:00
if ( is_seed ( ) )
{
avail . clear ( ) ;
return ;
}
m_picker - > get_availability ( avail ) ;
}
2007-03-20 02:59:00 +01:00
void torrent : : set_piece_priority ( int index , int priority )
{
2007-08-09 00:38:30 +02:00
// INVARIANT_CHECK;
2007-03-20 02:59:00 +01:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2007-03-20 02:59:00 +01:00
if ( is_seed ( ) ) return ;
// this call is only valid on torrents with metadata
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_picker . get ( ) ) ;
TORRENT_ASSERT ( index > = 0 ) ;
TORRENT_ASSERT ( index < m_torrent_file - > num_pieces ( ) ) ;
2011-01-22 20:01:44 +01:00
if ( index < 0 | | index > = m_torrent_file - > num_pieces ( ) ) return ;
2007-03-20 02:59:00 +01:00
2008-04-13 09:39:37 +02:00
bool was_finished = is_finished ( ) ;
2007-08-10 23:13:35 +02:00
bool filter_updated = m_picker - > set_piece_priority ( index , priority ) ;
2008-06-07 16:03:21 +02:00
TORRENT_ASSERT ( num_have ( ) > = m_picker - > num_have_filtered ( ) ) ;
2009-03-17 10:34:44 +01:00
if ( filter_updated )
{
update_peer_interest ( was_finished ) ;
if ( priority = = 0 ) remove_time_critical_piece ( index ) ;
}
2007-03-20 02:59:00 +01:00
}
int torrent : : piece_priority ( int index ) const
{
2007-08-09 00:38:30 +02:00
// INVARIANT_CHECK;
2007-03-20 02:59:00 +01:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2007-03-20 02:59:00 +01:00
if ( is_seed ( ) ) return 1 ;
// this call is only valid on torrents with metadata
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_picker . get ( ) ) ;
TORRENT_ASSERT ( index > = 0 ) ;
TORRENT_ASSERT ( index < m_torrent_file - > num_pieces ( ) ) ;
2011-01-22 20:01:44 +01:00
if ( index < 0 | | index > = m_torrent_file - > num_pieces ( ) ) return 0 ;
2007-03-20 02:59:00 +01:00
return m_picker - > piece_priority ( index ) ;
}
void torrent : : prioritize_pieces ( std : : vector < int > const & pieces )
{
INVARIANT_CHECK ;
// this call is only valid on torrents with metadata
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2007-03-20 02:59:00 +01:00
if ( is_seed ( ) ) return ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_picker . get ( ) ) ;
2007-03-20 02:59:00 +01:00
int index = 0 ;
2007-08-10 23:13:35 +02:00
bool filter_updated = false ;
2008-04-13 09:39:37 +02:00
bool was_finished = is_finished ( ) ;
2007-03-20 02:59:00 +01:00
for ( std : : vector < int > : : const_iterator i = pieces . begin ( )
, end ( pieces . end ( ) ) ; i ! = end ; + + i , + + index )
{
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( * i > = 0 ) ;
TORRENT_ASSERT ( * i < = 7 ) ;
2007-08-10 23:13:35 +02:00
filter_updated | = m_picker - > set_piece_priority ( index , * i ) ;
2008-06-07 16:03:21 +02:00
TORRENT_ASSERT ( num_have ( ) > = m_picker - > num_have_filtered ( ) ) ;
2007-03-20 02:59:00 +01:00
}
2009-03-17 10:34:44 +01:00
if ( filter_updated )
{
2011-06-05 22:48:00 +02:00
// we need to save this new state
m_need_save_resume_data = true ;
2009-03-17 10:34:44 +01:00
update_peer_interest ( was_finished ) ;
remove_time_critical_pieces ( pieces ) ;
}
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2007-03-20 02:59:00 +01:00
}
2011-05-01 19:43:15 +02:00
void torrent : : piece_priorities ( std : : vector < int > * pieces ) const
2007-03-20 02:59:00 +01:00
{
INVARIANT_CHECK ;
// this call is only valid on torrents with metadata
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2007-03-20 02:59:00 +01:00
if ( is_seed ( ) )
{
2011-05-01 19:43:15 +02:00
pieces - > clear ( ) ;
pieces - > resize ( m_torrent_file - > num_pieces ( ) , 1 ) ;
2007-03-20 02:59:00 +01:00
return ;
}
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_picker . get ( ) ) ;
2011-05-01 19:43:15 +02:00
m_picker - > piece_priorities ( * pieces ) ;
2007-03-20 02:59:00 +01:00
}
namespace
{
void set_if_greater ( int & piece_prio , int file_prio )
{
if ( file_prio > piece_prio ) piece_prio = file_prio ;
}
}
void torrent : : prioritize_files ( std : : vector < int > const & files )
{
INVARIANT_CHECK ;
// this call is only valid on torrents with metadata
if ( ! valid_metadata ( ) | | is_seed ( ) ) return ;
// the bitmask need to have exactly one bit for every file
// in the torrent
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( int ( files . size ( ) ) = = m_torrent_file - > num_files ( ) ) ;
2007-03-20 02:59:00 +01:00
2007-09-01 05:00:31 +02:00
if ( m_torrent_file - > num_pieces ( ) = = 0 ) return ;
2007-03-21 03:09:50 +01:00
2011-05-01 19:43:15 +02:00
int limit = int ( files . size ( ) ) ;
if ( valid_metadata ( ) & & limit > m_torrent_file - > num_files ( ) )
limit = m_torrent_file - > num_files ( ) ;
if ( m_file_priority . size ( ) < limit )
m_file_priority . resize ( limit ) ;
std : : copy ( files . begin ( ) , files . begin ( ) + limit , m_file_priority . begin ( ) ) ;
if ( valid_metadata ( ) & & m_torrent_file - > num_files ( ) > int ( m_file_priority . size ( ) ) )
m_file_priority . resize ( m_torrent_file - > num_files ( ) , 1 ) ;
2008-07-20 18:00:08 +02:00
update_piece_priorities ( ) ;
}
void torrent : : set_file_priority ( int index , int prio )
{
INVARIANT_CHECK ;
2009-11-26 01:09:49 +01:00
// this call is only valid on torrents with metadata
if ( ! valid_metadata ( ) | | is_seed ( ) ) return ;
2008-07-20 18:00:08 +02:00
TORRENT_ASSERT ( index < m_torrent_file - > num_files ( ) ) ;
TORRENT_ASSERT ( index > = 0 ) ;
2011-01-22 20:01:44 +01:00
if ( index < 0 | | index > = m_torrent_file - > num_files ( ) ) return ;
2008-07-20 18:00:08 +02:00
if ( m_file_priority [ index ] = = prio ) return ;
m_file_priority [ index ] = prio ;
update_piece_priorities ( ) ;
}
int torrent : : file_priority ( int index ) const
{
2009-11-26 01:09:49 +01:00
// this call is only valid on torrents with metadata
if ( ! valid_metadata ( ) ) return 1 ;
2008-07-20 18:00:08 +02:00
TORRENT_ASSERT ( index < m_torrent_file - > num_files ( ) ) ;
TORRENT_ASSERT ( index > = 0 ) ;
2011-01-22 20:01:44 +01:00
if ( index < 0 | | index > = m_torrent_file - > num_files ( ) ) return 0 ;
2008-07-20 18:00:08 +02:00
return m_file_priority [ index ] ;
}
2011-05-01 19:43:15 +02:00
void torrent : : file_priorities ( std : : vector < int > * files ) const
2008-07-20 18:00:08 +02:00
{
INVARIANT_CHECK ;
2011-05-01 19:43:15 +02:00
if ( ! valid_metadata ( ) )
{
files - > resize ( m_file_priority . size ( ) ) ;
std : : copy ( m_file_priority . begin ( ) , m_file_priority . end ( ) , files - > begin ( ) ) ;
return ;
}
files - > resize ( m_torrent_file - > num_files ( ) ) ;
std : : copy ( m_file_priority . begin ( ) , m_file_priority . end ( ) , files - > begin ( ) ) ;
if ( m_file_priority . size ( ) < m_torrent_file - > num_files ( ) )
std : : fill ( files - > begin ( ) + m_file_priority . size ( ) , files - > end ( ) , 1 ) ;
2008-07-20 18:00:08 +02:00
}
void torrent : : update_piece_priorities ( )
{
INVARIANT_CHECK ;
if ( m_torrent_file - > num_pieces ( ) = = 0 ) return ;
2008-04-13 09:39:37 +02:00
2008-07-20 18:00:08 +02:00
size_type position = 0 ;
2007-09-01 05:00:31 +02:00
int piece_length = m_torrent_file - > piece_length ( ) ;
2007-03-21 03:09:50 +01:00
// initialize the piece priorities to 0, then only allow
// setting higher priorities
2007-09-01 05:00:31 +02:00
std : : vector < int > pieces ( m_torrent_file - > num_pieces ( ) , 0 ) ;
2011-10-12 12:27:17 +02:00
int index = 0 ;
for ( file_storage : : iterator i = m_torrent_file - > files ( ) . begin ( )
, end ( m_torrent_file - > files ( ) . end ( ) ) ; i ! = end ; + + i , + + index )
2007-03-20 02:59:00 +01:00
{
2007-03-21 03:09:50 +01:00
size_type start = position ;
2011-10-12 12:27:17 +02:00
size_type size = m_torrent_file - > files ( ) . file_size ( * i ) ;
2007-04-18 00:56:14 +02:00
if ( size = = 0 ) continue ;
position + = size ;
2011-10-12 12:27:17 +02:00
if ( m_file_priority [ index ] = = 0 ) continue ;
2008-09-19 21:46:04 +02:00
2007-03-21 03:09:50 +01:00
// mark all pieces of the file with this file's priority
// but only if the priority is higher than the pieces
// already set (to avoid problems with overlapping pieces)
int start_piece = int ( start / piece_length ) ;
2007-04-18 00:56:14 +02:00
int last_piece = int ( ( position - 1 ) / piece_length ) ;
2008-07-20 18:00:08 +02:00
TORRENT_ASSERT ( last_piece < int ( pieces . size ( ) ) ) ;
2007-03-21 03:09:50 +01:00
// if one piece spans several files, we might
// come here several times with the same start_piece, end_piece
std : : for_each ( pieces . begin ( ) + start_piece
, pieces . begin ( ) + last_piece + 1
2011-10-12 12:27:17 +02:00
, boost : : bind ( & set_if_greater , _1 , m_file_priority [ index ] ) ) ;
2007-03-20 02:59:00 +01:00
}
2007-03-21 03:09:50 +01:00
prioritize_pieces ( pieces ) ;
2007-03-20 02:59:00 +01:00
}
2008-04-13 09:39:37 +02:00
// this is called when piece priorities have been updated
2007-03-21 03:09:50 +01:00
// updates the interested flag in peers
2008-04-13 09:39:37 +02:00
void torrent : : update_peer_interest ( bool was_finished )
2007-03-21 03:09:50 +01:00
{
2008-09-18 01:14:59 +02:00
for ( peer_iterator i = begin ( ) ; i ! = end ( ) ; )
{
peer_connection * p = * i ;
// update_interest may disconnect the peer and
// invalidate the iterator
+ + i ;
2008-09-18 19:53:44 +02:00
p - > update_interest ( ) ;
2008-09-18 01:14:59 +02:00
}
2008-03-29 19:47:24 +01:00
2008-04-13 09:39:37 +02:00
// the torrent just became finished
if ( is_finished ( ) & & ! was_finished )
2008-08-18 22:02:50 +02:00
{
2008-04-13 09:39:37 +02:00
finished ( ) ;
2008-08-18 22:02:50 +02:00
}
2008-05-20 05:21:45 +02:00
else if ( ! is_finished ( ) & & was_finished )
2008-08-18 22:02:50 +02:00
{
// if we used to be finished, but we aren't anymore
// we may need to connect to peers again
2008-05-20 05:21:45 +02:00
resume_download ( ) ;
2008-08-18 22:02:50 +02:00
}
2007-03-21 03:09:50 +01:00
}
2007-03-20 02:59:00 +01:00
2005-05-25 12:01:01 +02:00
void torrent : : filter_piece ( int index , bool filter )
{
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2006-12-11 13:48:33 +01:00
if ( is_seed ( ) ) return ;
2005-05-25 12:01:01 +02:00
// this call is only valid on torrents with metadata
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_picker . get ( ) ) ;
TORRENT_ASSERT ( index > = 0 ) ;
TORRENT_ASSERT ( index < m_torrent_file - > num_pieces ( ) ) ;
2005-05-25 12:01:01 +02:00
2011-01-22 20:01:44 +01:00
if ( index < 0 | | index > = m_torrent_file - > num_pieces ( ) ) return ;
2008-04-13 09:39:37 +02:00
bool was_finished = is_finished ( ) ;
2007-03-15 23:03:56 +01:00
m_picker - > set_piece_priority ( index , filter ? 1 : 0 ) ;
2008-04-13 09:39:37 +02:00
update_peer_interest ( was_finished ) ;
2005-05-25 12:01:01 +02:00
}
2005-06-23 01:04:37 +02:00
void torrent : : filter_pieces ( std : : vector < bool > const & bitmask )
{
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2005-06-23 01:04:37 +02:00
// this call is only valid on torrents with metadata
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2006-12-11 13:48:33 +01:00
if ( is_seed ( ) ) return ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_picker . get ( ) ) ;
2005-06-23 01:04:37 +02:00
2008-04-13 09:39:37 +02:00
bool was_finished = is_finished ( ) ;
2005-06-23 01:04:37 +02:00
int index = 0 ;
for ( std : : vector < bool > : : const_iterator i = bitmask . begin ( )
, end ( bitmask . end ( ) ) ; i ! = end ; + + i , + + index )
{
2007-03-15 23:03:56 +01:00
if ( ( m_picker - > piece_priority ( index ) = = 0 ) = = * i ) continue ;
2005-09-01 23:04:21 +02:00
if ( * i )
2007-03-15 23:03:56 +01:00
m_picker - > set_piece_priority ( index , 0 ) ;
2005-09-01 23:04:21 +02:00
else
2007-03-15 23:03:56 +01:00
m_picker - > set_piece_priority ( index , 1 ) ;
2005-06-23 01:04:37 +02:00
}
2008-04-13 09:39:37 +02:00
update_peer_interest ( was_finished ) ;
2005-06-23 01:04:37 +02:00
}
2005-05-25 12:01:01 +02:00
bool torrent : : is_piece_filtered ( int index ) const
{
// this call is only valid on torrents with metadata
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2006-12-11 13:48:33 +01:00
if ( is_seed ( ) ) return false ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_picker . get ( ) ) ;
TORRENT_ASSERT ( index > = 0 ) ;
TORRENT_ASSERT ( index < m_torrent_file - > num_pieces ( ) ) ;
2005-05-25 12:01:01 +02:00
2011-01-22 20:01:44 +01:00
if ( index < 0 | | index > = m_torrent_file - > num_pieces ( ) ) return true ;
2007-03-15 23:03:56 +01:00
return m_picker - > piece_priority ( index ) = = 0 ;
2005-05-25 12:01:01 +02:00
}
void torrent : : filtered_pieces ( std : : vector < bool > & bitmask ) const
{
2006-05-28 21:03:54 +02:00
INVARIANT_CHECK ;
2005-05-25 12:01:01 +02:00
// this call is only valid on torrents with metadata
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2006-12-11 13:48:33 +01:00
if ( is_seed ( ) )
{
bitmask . clear ( ) ;
2007-09-01 05:00:31 +02:00
bitmask . resize ( m_torrent_file - > num_pieces ( ) , false ) ;
2006-12-11 13:48:33 +01:00
return ;
}
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_picker . get ( ) ) ;
2005-05-25 12:01:01 +02:00
m_picker - > filtered_pieces ( bitmask ) ;
}
2005-07-04 01:33:47 +02:00
void torrent : : filter_files ( std : : vector < bool > const & bitmask )
{
2006-05-28 21:03:54 +02:00
INVARIANT_CHECK ;
2005-07-04 01:33:47 +02:00
// this call is only valid on torrents with metadata
2006-12-11 13:48:33 +01:00
if ( ! valid_metadata ( ) | | is_seed ( ) ) return ;
2005-07-04 18:27:14 +02:00
2005-07-04 18:33:54 +02:00
// the bitmask need to have exactly one bit for every file
// in the torrent
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( ( int ) bitmask . size ( ) = = m_torrent_file - > num_files ( ) ) ;
2011-01-22 20:01:44 +01:00
2011-02-21 06:24:41 +01:00
if ( int ( bitmask . size ( ) ) ! = m_torrent_file - > num_files ( ) ) return ;
2005-07-04 18:33:54 +02:00
2005-07-08 16:04:14 +02:00
size_type position = 0 ;
2005-07-04 18:27:14 +02:00
2007-09-01 05:00:31 +02:00
if ( m_torrent_file - > num_pieces ( ) )
2005-07-04 18:33:54 +02:00
{
2007-09-01 05:00:31 +02:00
int piece_length = m_torrent_file - > piece_length ( ) ;
2005-07-04 18:33:54 +02:00
// mark all pieces as filtered, then clear the bits for files
// that should be downloaded
2007-09-01 05:00:31 +02:00
std : : vector < bool > piece_filter ( m_torrent_file - > num_pieces ( ) , true ) ;
2005-07-06 02:58:23 +02:00
for ( int i = 0 ; i < ( int ) bitmask . size ( ) ; + + i )
2005-07-04 18:27:14 +02:00
{
2005-07-08 16:04:14 +02:00
size_type start = position ;
2008-05-28 10:44:40 +02:00
position + = m_torrent_file - > files ( ) . at ( i ) . size ;
2005-07-04 18:33:54 +02:00
// is the file selected for download?
if ( ! bitmask [ i ] )
{
// mark all pieces of the file as downloadable
int start_piece = int ( start / piece_length ) ;
int last_piece = int ( position / piece_length ) ;
// if one piece spans several files, we might
// come here several times with the same start_piece, end_piece
std : : fill ( piece_filter . begin ( ) + start_piece , piece_filter . begin ( )
+ last_piece + 1 , false ) ;
2005-07-04 18:27:14 +02:00
}
}
2005-07-04 18:33:54 +02:00
filter_pieces ( piece_filter ) ;
2005-07-04 18:27:14 +02:00
}
2005-07-04 01:33:47 +02:00
}
2004-09-12 12:12:16 +02:00
void torrent : : replace_trackers ( std : : vector < announce_entry > const & urls )
{
2009-04-26 10:05:42 +02:00
m_trackers . clear ( ) ;
std : : remove_copy_if ( urls . begin ( ) , urls . end ( ) , back_inserter ( m_trackers )
, boost : : bind ( & std : : string : : empty , boost : : bind ( & announce_entry : : url , _1 ) ) ) ;
2004-09-12 12:12:16 +02:00
m_last_working_tracker = - 1 ;
2008-11-29 09:38:40 +01:00
for ( std : : vector < announce_entry > : : iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
if ( i - > source = = 0 ) i - > source = announce_entry : : source_client ;
2010-02-14 02:39:55 +01:00
if ( settings ( ) . prefer_udp_trackers )
2008-12-08 10:13:21 +01:00
prioritize_udp_trackers ( ) ;
2010-06-17 19:01:28 +02:00
if ( ! m_trackers . empty ( ) ) announce_with_tracker ( ) ;
2004-09-12 12:12:16 +02:00
}
2008-12-08 10:13:21 +01:00
void torrent : : prioritize_udp_trackers ( )
{
// look for udp-trackers
for ( std : : vector < announce_entry > : : iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
{
if ( i - > url . substr ( 0 , 6 ) ! = " udp:// " ) continue ;
// now, look for trackers with the same hostname
// that is has higher priority than this one
// if we find one, swap with the udp-tracker
2009-06-12 18:40:38 +02:00
error_code ec ;
2008-12-08 10:13:21 +01:00
std : : string udp_hostname ;
using boost : : tuples : : ignore ;
2009-06-12 18:40:38 +02:00
boost : : tie ( ignore , ignore , udp_hostname , ignore , ignore )
= parse_url_components ( i - > url , ec ) ;
2008-12-08 10:13:21 +01:00
for ( std : : vector < announce_entry > : : iterator j = m_trackers . begin ( ) ;
j ! = i ; + + j )
{
std : : string hostname ;
2009-06-12 18:40:38 +02:00
boost : : tie ( ignore , ignore , hostname , ignore , ignore )
= parse_url_components ( j - > url , ec ) ;
2008-12-08 10:13:21 +01:00
if ( hostname ! = udp_hostname ) continue ;
if ( j - > url . substr ( 0 , 6 ) = = " udp:// " ) continue ;
using std : : swap ;
using std : : iter_swap ;
swap ( i - > tier , j - > tier ) ;
iter_swap ( i , j ) ;
break ;
}
}
}
2008-11-26 02:42:14 +01:00
void torrent : : add_tracker ( announce_entry const & url )
{
std : : vector < announce_entry > : : iterator k = std : : find_if ( m_trackers . begin ( )
, m_trackers . end ( ) , boost : : bind ( & announce_entry : : url , _1 ) = = url . url ) ;
2008-11-29 09:38:40 +01:00
if ( k ! = m_trackers . end ( ) )
{
k - > source | = url . source ;
return ;
}
2008-11-26 02:42:14 +01:00
k = std : : upper_bound ( m_trackers . begin ( ) , m_trackers . end ( ) , url
, boost : : bind ( & announce_entry : : tier , _1 ) < boost : : bind ( & announce_entry : : tier , _2 ) ) ;
if ( k - m_trackers . begin ( ) < m_last_working_tracker ) + + m_last_working_tracker ;
2008-11-29 09:38:40 +01:00
k = m_trackers . insert ( k , url ) ;
if ( k - > source = = 0 ) k - > source = announce_entry : : source_client ;
2010-06-17 19:01:28 +02:00
if ( ! m_trackers . empty ( ) ) announce_with_tracker ( ) ;
2008-11-26 02:42:14 +01:00
}
2009-07-23 06:38:52 +02:00
bool torrent : : choke_peer ( peer_connection & c )
2007-08-17 09:37:08 +02:00
{
INVARIANT_CHECK ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( ! c . is_choked ( ) ) ;
2009-01-28 07:14:21 +01:00
TORRENT_ASSERT ( ! c . ignore_unchoke_slots ( ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_num_uploads > 0 ) ;
2009-07-23 06:38:52 +02:00
if ( ! c . send_choke ( ) ) return false ;
2007-08-17 09:37:08 +02:00
- - m_num_uploads ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2009-07-23 06:38:52 +02:00
return true ;
2007-08-17 09:37:08 +02:00
}
2010-10-04 06:06:14 +02:00
bool torrent : : unchoke_peer ( peer_connection & c , bool optimistic )
2007-08-17 09:37:08 +02:00
{
INVARIANT_CHECK ;
2010-10-30 10:36:18 +02:00
TORRENT_ASSERT ( ! m_graceful_pause_mode ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( c . is_choked ( ) ) ;
2009-01-28 07:14:21 +01:00
TORRENT_ASSERT ( ! c . ignore_unchoke_slots ( ) ) ;
2010-10-04 06:06:14 +02:00
// when we're unchoking the optimistic slots, we might
// exceed the limit temporarily while we're iterating
// over the peers
if ( m_num_uploads > = m_max_uploads & & ! optimistic ) return false ;
2008-08-29 19:21:56 +02:00
if ( ! c . send_unchoke ( ) ) return false ;
2007-08-17 09:37:08 +02:00
+ + m_num_uploads ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2007-08-17 09:37:08 +02:00
return true ;
}
2007-07-06 19:15:35 +02:00
void torrent : : cancel_block ( piece_block block )
{
2008-03-14 11:17:27 +01:00
INVARIANT_CHECK ;
2007-07-06 19:15:35 +02:00
for ( peer_iterator i = m_connections . begin ( )
, end ( m_connections . end ( ) ) ; i ! = end ; + + i )
{
2007-10-31 10:48:20 +01:00
( * i ) - > cancel_request ( block ) ;
2007-07-06 19:15:35 +02:00
}
}
2011-09-10 07:52:07 +02:00
# ifdef TORRENT_USE_OPENSSL
2011-09-12 05:51:49 +02:00
std : : string password_callback ( int length , boost : : asio : : ssl : : context : : password_purpose p
, std : : string pw )
{
if ( p ! = boost : : asio : : ssl : : context : : for_reading ) return " " ;
return pw ;
}
2011-09-10 07:52:07 +02:00
// certificate is a filename to a .pem file which is our
2011-09-12 05:51:49 +02:00
// certificate. The certificate must be signed by the root
// cert of the torrent file. any peer we connect to or that
// connect to use must present a valid certificate signed
// by the torrent root cert as well
void torrent : : set_ssl_cert ( std : : string const & certificate
, std : : string const & private_key
, std : : string const & dh_params
, std : : string const & passphrase )
2011-09-10 07:52:07 +02:00
{
2011-09-12 05:51:49 +02:00
if ( ! m_ssl_ctx ) return ;
using boost : : asio : : ssl : : context ;
error_code ec ;
m_ssl_ctx - > set_password_callback ( boost : : bind ( & password_callback , _1 , _2 , passphrase ) , ec ) ;
if ( ec )
2011-09-10 07:52:07 +02:00
{
2011-09-12 05:51:49 +02:00
if ( alerts ( ) . should_post < torrent_error_alert > ( ) )
alerts ( ) . post_alert ( torrent_error_alert ( get_handle ( ) , ec ) ) ;
2011-09-10 07:52:07 +02:00
}
m_ssl_ctx - > use_certificate_file ( certificate , context : : pem , ec ) ;
2011-09-12 05:51:49 +02:00
if ( ec )
{
if ( alerts ( ) . should_post < torrent_error_alert > ( ) )
alerts ( ) . post_alert ( torrent_error_alert ( get_handle ( ) , ec ) ) ;
}
m_ssl_ctx - > use_private_key_file ( private_key , context : : pem , ec ) ;
if ( ec )
{
if ( alerts ( ) . should_post < torrent_error_alert > ( ) )
alerts ( ) . post_alert ( torrent_error_alert ( get_handle ( ) , ec ) ) ;
}
m_ssl_ctx - > use_tmp_dh_file ( dh_params , ec ) ;
if ( ec )
{
if ( alerts ( ) . should_post < torrent_error_alert > ( ) )
alerts ( ) . post_alert ( torrent_error_alert ( get_handle ( ) , ec ) ) ;
}
2011-09-10 07:52:07 +02:00
}
# endif
2008-04-07 04:51:21 +02:00
void torrent : : remove_peer ( peer_connection * p )
2003-10-23 01:00:57 +02:00
{
2007-08-17 04:15:01 +02:00
// INVARIANT_CHECK;
2006-04-25 23:04:48 +02:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( p ! = 0 ) ;
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2004-01-25 13:37:15 +01:00
2007-10-31 10:48:20 +01:00
peer_iterator i = m_connections . find ( p ) ;
2007-04-12 12:21:55 +02:00
if ( i = = m_connections . end ( ) )
{
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( false ) ;
2007-04-12 12:21:55 +02:00
return ;
}
2003-10-23 01:00:57 +02:00
2005-10-16 23:14:08 +02:00
if ( ready_for_connections ( ) )
2003-10-23 01:00:57 +02:00
{
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( p - > associated_torrent ( ) . lock ( ) . get ( ) = = this ) ;
2003-10-23 01:00:57 +02:00
2007-04-15 04:14:02 +02:00
if ( p - > is_seed ( ) )
{
if ( m_picker . get ( ) )
{
m_picker - > dec_refcount_all ( ) ;
}
}
else
2004-06-14 01:30:42 +02:00
{
2008-01-31 18:52:29 +01:00
if ( m_picker . get ( ) )
2007-04-15 04:14:02 +02:00
{
2008-05-28 04:35:02 +02:00
bitfield const & pieces = p - > get_bitfield ( ) ;
2011-09-12 05:51:49 +02:00
TORRENT_ASSERT ( pieces . count ( ) < = int ( pieces . size ( ) ) ) ;
2008-01-31 18:52:29 +01:00
m_picker - > dec_refcount ( pieces ) ;
2007-04-15 04:14:02 +02:00
}
2004-06-14 01:30:42 +02:00
}
2003-10-23 01:00:57 +02:00
}
2009-01-28 07:14:21 +01:00
if ( ! p - > is_choked ( ) & & ! p - > ignore_unchoke_slots ( ) )
2008-10-14 03:00:05 +02:00
{
2007-08-17 09:37:08 +02:00
- - m_num_uploads ;
2008-10-14 03:00:05 +02:00
m_ses . m_unchoke_time_scaler = 0 ;
}
2009-07-23 06:38:52 +02:00
policy : : peer * pp = p - > peer_info_struct ( ) ;
if ( pp )
2008-10-14 03:00:05 +02:00
{
2009-07-23 06:38:52 +02:00
if ( pp - > optimistically_unchoked )
m_ses . m_optimistic_unchoke_time_scaler = 0 ;
// if the share ratio is 0 (infinite), the
// m_available_free_upload isn't used,
// because it isn't necessary.
if ( ratio ( ) ! = 0.f )
{
TORRENT_ASSERT ( p - > associated_torrent ( ) . lock ( ) . get ( ) = = this ) ;
TORRENT_ASSERT ( p - > share_diff ( ) < ( std : : numeric_limits < size_type > : : max ) ( ) ) ;
2011-02-21 06:24:41 +01:00
add_free_upload ( p - > share_diff ( ) ) ;
2009-07-23 06:38:52 +02:00
}
TORRENT_ASSERT ( pp - > prev_amount_upload = = 0 ) ;
TORRENT_ASSERT ( pp - > prev_amount_download = = 0 ) ;
2011-06-01 08:47:57 +02:00
pp - > prev_amount_download + = p - > statistics ( ) . total_payload_download ( ) > > 10 ;
pp - > prev_amount_upload + = p - > statistics ( ) . total_payload_upload ( ) > > 10 ;
2008-10-14 03:00:05 +02:00
}
2007-08-17 09:37:08 +02:00
2009-04-30 07:49:46 +02:00
m_policy . connection_closed ( * p , m_ses . session_time ( ) ) ;
2007-04-12 12:21:55 +02:00
p - > set_peer_info ( 0 ) ;
2007-10-31 10:48:20 +01:00
TORRENT_ASSERT ( i ! = m_connections . end ( ) ) ;
2003-10-23 01:00:57 +02:00
m_connections . erase ( i ) ;
}
2006-04-25 23:04:48 +02:00
2011-04-29 10:09:03 +02:00
void torrent : : remove_web_seed ( std : : list < web_seed_entry > : : iterator web )
{
if ( web - > resolving )
{
web - > removed = true ;
return ;
}
m_web_seeds . erase ( web ) ;
}
2010-02-12 07:10:20 +01:00
void torrent : : connect_to_url_seed ( std : : list < web_seed_entry > : : iterator web )
2006-04-25 23:04:48 +02:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2010-02-12 07:10:20 +01:00
TORRENT_ASSERT ( ! web - > resolving ) ;
if ( web - > resolving ) return ;
2011-04-30 22:05:23 +02:00
if ( int ( m_connections . size ( ) ) > = m_max_connections
2011-05-01 21:28:13 +02:00
| | m_ses . num_connections ( ) > = m_ses . settings ( ) . connections_limit )
2011-04-30 22:05:23 +02:00
return ;
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2010-02-12 07:10:20 +01:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " resolving web seed: " < < web - > url < < " \n " ;
2006-06-29 01:27:44 +02:00
# endif
2008-04-09 09:51:41 +02:00
std : : string protocol ;
std : : string auth ;
std : : string hostname ;
int port ;
std : : string path ;
2009-06-12 18:40:38 +02:00
error_code ec ;
boost : : tie ( protocol , auth , hostname , port , path )
2010-02-12 07:10:20 +01:00
= parse_url_components ( web - > url , ec ) ;
2008-04-09 09:51:41 +02:00
2009-06-12 18:40:38 +02:00
if ( ec )
2008-05-17 16:19:34 +02:00
{
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2009-06-12 18:40:38 +02:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " failed to parse web seed url: " < < ec . message ( ) < < " \n " ;
2008-05-17 16:19:34 +02:00
# endif
2010-10-17 18:15:32 +02:00
if ( m_ses . m_alerts . should_post < url_seed_alert > ( ) )
{
m_ses . m_alerts . post_alert (
url_seed_alert ( get_handle ( ) , web - > url , ec ) ) ;
}
2008-05-17 16:19:34 +02:00
// never try it again
2011-04-29 10:09:03 +02:00
remove_web_seed ( web ) ;
2008-05-17 16:19:34 +02:00
return ;
}
2008-04-09 09:51:41 +02:00
# ifdef TORRENT_USE_OPENSSL
if ( protocol ! = " http " & & protocol ! = " https " )
# else
if ( protocol ! = " http " )
# endif
{
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < url_seed_alert > ( ) )
2008-04-09 09:51:41 +02:00
{
m_ses . m_alerts . post_alert (
2010-02-12 07:10:20 +01:00
url_seed_alert ( get_handle ( ) , web - > url , errors : : unsupported_url_protocol ) ) ;
2008-04-09 09:51:41 +02:00
}
// never try it again
2011-04-29 10:09:03 +02:00
remove_web_seed ( web ) ;
2008-04-09 09:51:41 +02:00
return ;
}
if ( hostname . empty ( ) )
{
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < url_seed_alert > ( ) )
2008-04-09 09:51:41 +02:00
{
m_ses . m_alerts . post_alert (
2010-02-12 07:10:20 +01:00
url_seed_alert ( get_handle ( ) , web - > url , errors : : invalid_hostname ) ) ;
2008-04-09 09:51:41 +02:00
}
// never try it again
2011-04-29 10:09:03 +02:00
remove_web_seed ( web ) ;
2008-04-09 09:51:41 +02:00
return ;
}
if ( port = = 0 )
{
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < url_seed_alert > ( ) )
2008-04-09 09:51:41 +02:00
{
m_ses . m_alerts . post_alert (
2010-02-12 07:10:20 +01:00
url_seed_alert ( get_handle ( ) , web - > url , errors : : invalid_port ) ) ;
2008-04-09 09:51:41 +02:00
}
// never try it again
2011-04-29 10:09:03 +02:00
remove_web_seed ( web ) ;
2008-04-09 09:51:41 +02:00
return ;
}
2010-08-03 11:08:37 +02:00
if ( m_ses . m_port_filter . access ( port ) & port_filter : : blocked )
{
if ( m_ses . m_alerts . should_post < url_seed_alert > ( ) )
{
m_ses . m_alerts . post_alert (
url_seed_alert ( get_handle ( ) , web - > url , errors : : port_blocked ) ) ;
}
// never try it again
2011-04-29 10:09:03 +02:00
remove_web_seed ( web ) ;
2010-08-03 11:08:37 +02:00
return ;
}
2010-10-30 09:11:04 +02:00
if ( web - > endpoint . port ( ) ! = 0 )
{
connect_web_seed ( web , web - > endpoint ) ;
return ;
}
2010-08-23 08:27:18 +02:00
proxy_settings const & ps = m_ses . proxy ( ) ;
2007-04-25 20:26:35 +02:00
if ( ps . type = = proxy_settings : : http
| | ps . type = = proxy_settings : : http_pw )
{
// use proxy
2011-09-30 11:09:33 +02:00
web - > resolving = true ;
2009-01-27 07:17:55 +01:00
tcp : : resolver : : query q ( ps . hostname , to_string ( ps . port ) . elems ) ;
2010-02-14 02:39:55 +01:00
m_ses . m_host_resolver . async_resolve ( q ,
2010-05-02 08:29:52 +02:00
boost : : bind ( & torrent : : on_proxy_name_lookup , shared_from_this ( ) , _1 , _2 , web ) ) ;
2007-04-25 20:26:35 +02:00
}
2010-08-03 11:08:37 +02:00
else if ( ps . proxy_hostnames
& & ( ps . type = = proxy_settings : : socks5
| | ps . type = = proxy_settings : : socks5_pw ) )
{
connect_web_seed ( web , tcp : : endpoint ( address ( ) , port ) ) ;
}
2007-04-25 20:26:35 +02:00
else
2006-07-27 20:07:51 +02:00
{
2010-10-30 21:45:50 +02:00
web - > resolving = true ;
2009-01-27 07:17:55 +01:00
tcp : : resolver : : query q ( hostname , to_string ( port ) . elems ) ;
2010-02-14 02:39:55 +01:00
m_ses . m_host_resolver . async_resolve ( q ,
2010-05-02 08:29:52 +02:00
boost : : bind ( & torrent : : on_name_lookup , shared_from_this ( ) , _1 , _2 , web
2008-01-08 06:47:43 +01:00
, tcp : : endpoint ( ) ) ) ;
2006-07-27 20:07:51 +02:00
}
2007-02-12 06:46:29 +01:00
}
2008-05-03 18:05:42 +02:00
void torrent : : on_proxy_name_lookup ( error_code const & e , tcp : : resolver : : iterator host
2010-02-12 07:10:20 +01:00
, std : : list < web_seed_entry > : : iterator web )
2007-02-12 06:46:29 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-02-12 06:46:29 +01:00
INVARIANT_CHECK ;
2011-09-30 11:09:33 +02:00
TORRENT_ASSERT ( web - > resolving = = true ) ;
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2010-02-12 07:10:20 +01:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " completed resolve proxy hostname for: " < < web - > url < < " \n " ;
2009-12-28 21:59:34 +01:00
if ( e )
2009-12-07 06:03:23 +01:00
* m_ses . m_logger < < time_now_string ( ) < < " on_proxy_name_lookup: " < < e . message ( ) < < " \n " ;
2007-02-12 06:46:29 +01:00
# endif
2011-09-30 11:09:33 +02:00
web - > resolving = false ;
if ( web - > removed )
{
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " removed web seed \n " ;
# endif
remove_web_seed ( web ) ;
return ;
}
2007-02-12 06:46:29 +01:00
2008-12-20 19:27:09 +01:00
if ( m_abort ) return ;
2007-02-12 06:46:29 +01:00
if ( e | | host = = tcp : : resolver : : iterator ( ) )
{
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < url_seed_alert > ( ) )
2007-02-12 06:46:29 +01:00
{
m_ses . m_alerts . post_alert (
2010-02-12 07:10:20 +01:00
url_seed_alert ( get_handle ( ) , web - > url , e ) ) ;
2007-02-12 06:46:29 +01:00
}
// the name lookup failed for the http host. Don't try
// this host again
2011-04-29 10:09:03 +02:00
remove_web_seed ( web ) ;
2007-02-12 06:46:29 +01:00
return ;
}
if ( m_ses . is_aborted ( ) ) return ;
2011-04-30 22:05:23 +02:00
if ( int ( m_connections . size ( ) ) > = m_max_connections
2011-05-01 21:28:13 +02:00
| | m_ses . num_connections ( ) > = m_ses . settings ( ) . connections_limit )
2011-04-30 22:05:23 +02:00
return ;
2007-02-12 06:46:29 +01:00
tcp : : endpoint a ( host - > endpoint ( ) ) ;
2007-05-22 22:44:18 +02:00
using boost : : tuples : : ignore ;
2007-02-12 06:46:29 +01:00
std : : string hostname ;
int port ;
2009-06-12 18:40:38 +02:00
error_code ec ;
boost : : tie ( ignore , ignore , hostname , port , ignore )
2010-02-12 07:10:20 +01:00
= parse_url_components ( web - > url , ec ) ;
2007-02-12 06:46:29 +01:00
2009-06-12 18:40:38 +02:00
if ( ec )
2008-05-17 16:19:34 +02:00
{
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < url_seed_alert > ( ) )
2008-05-17 16:19:34 +02:00
{
m_ses . m_alerts . post_alert (
2010-02-12 07:10:20 +01:00
url_seed_alert ( get_handle ( ) , web - > url , ec ) ) ;
2008-05-17 16:19:34 +02:00
}
2011-04-29 10:09:03 +02:00
remove_web_seed ( web ) ;
2008-05-17 16:19:34 +02:00
return ;
}
2011-02-27 18:26:57 +01:00
if ( m_apply_ip_filter
& & m_ses . m_ip_filter . access ( a . address ( ) ) & ip_filter : : blocked )
2007-04-17 07:56:43 +02:00
{
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < peer_blocked_alert > ( ) )
2009-09-07 03:47:30 +02:00
m_ses . m_alerts . post_alert ( peer_blocked_alert ( get_handle ( ) , a . address ( ) ) ) ;
2007-04-17 07:56:43 +02:00
return ;
}
2010-10-30 21:45:50 +02:00
web - > resolving = true ;
2009-01-27 07:17:55 +01:00
tcp : : resolver : : query q ( hostname , to_string ( port ) . elems ) ;
2010-02-14 02:39:55 +01:00
m_ses . m_host_resolver . async_resolve ( q ,
2010-05-02 08:29:52 +02:00
boost : : bind ( & torrent : : on_name_lookup , shared_from_this ( ) , _1 , _2 , web , a ) ) ;
2007-02-12 06:46:29 +01:00
}
2008-05-03 18:05:42 +02:00
void torrent : : on_name_lookup ( error_code const & e , tcp : : resolver : : iterator host
2010-02-12 07:10:20 +01:00
, std : : list < web_seed_entry > : : iterator web , tcp : : endpoint proxy )
2007-02-12 06:46:29 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-02-12 06:46:29 +01:00
INVARIANT_CHECK ;
2010-10-30 09:11:04 +02:00
TORRENT_ASSERT ( web - > resolving = = true ) ;
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2010-02-12 07:10:20 +01:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " completed resolve: " < < web - > url < < " \n " ;
2007-02-12 06:46:29 +01:00
# endif
2010-02-12 07:10:20 +01:00
web - > resolving = false ;
2011-04-29 10:09:03 +02:00
if ( web - > removed )
{
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " removed web seed \n " ;
# endif
remove_web_seed ( web ) ;
return ;
}
2007-02-12 06:46:29 +01:00
2008-12-20 19:27:09 +01:00
if ( m_abort ) return ;
2007-02-12 06:46:29 +01:00
if ( e | | host = = tcp : : resolver : : iterator ( ) )
{
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < url_seed_alert > ( ) )
2010-02-12 07:10:20 +01:00
m_ses . m_alerts . post_alert ( url_seed_alert ( get_handle ( ) , web - > url , e ) ) ;
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2010-02-12 07:10:20 +01:00
( * m_ses . m_logger ) < < " ** HOSTNAME LOOKUP FAILED!**: " < < web - > url
2009-06-12 18:40:38 +02:00
< < " " < < e . message ( ) < < " \n " ;
2007-02-12 06:46:29 +01:00
# endif
2009-05-25 09:04:14 +02:00
// unavailable, retry in 30 minutes
2010-02-12 07:10:20 +01:00
web - > retry = time_now ( ) + minutes ( 30 ) ;
2007-02-12 06:46:29 +01:00
return ;
}
2011-04-30 22:05:23 +02:00
if ( int ( m_connections . size ( ) ) > = m_max_connections
2011-05-01 21:28:13 +02:00
| | m_ses . num_connections ( ) > = m_ses . settings ( ) . connections_limit )
2011-04-30 22:05:23 +02:00
return ;
2007-02-12 06:46:29 +01:00
tcp : : endpoint a ( host - > endpoint ( ) ) ;
2010-08-03 11:08:37 +02:00
connect_web_seed ( web , a ) ;
}
2007-02-12 06:46:29 +01:00
2010-12-25 10:13:50 +01:00
void torrent : : connect_web_seed ( std : : list < web_seed_entry > : : iterator web , tcp : : endpoint a )
2010-08-03 11:08:37 +02:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2011-02-27 18:26:57 +01:00
if ( m_apply_ip_filter
& & m_ses . m_ip_filter . access ( a . address ( ) ) & ip_filter : : blocked )
2007-02-12 06:46:29 +01:00
{
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < peer_blocked_alert > ( ) )
2009-09-07 03:47:30 +02:00
m_ses . m_alerts . post_alert ( peer_blocked_alert ( get_handle ( ) , a . address ( ) ) ) ;
2007-02-12 06:46:29 +01:00
return ;
}
2010-10-30 09:11:04 +02:00
TORRENT_ASSERT ( web - > resolving = = false ) ;
TORRENT_ASSERT ( web - > connection = = 0 ) ;
2010-02-12 07:10:20 +01:00
web - > endpoint = a ;
if ( is_paused ( ) ) return ;
if ( m_ses . is_aborted ( ) ) return ;
2008-04-07 04:51:21 +02:00
boost : : shared_ptr < socket_type > s ( new ( std : : nothrow ) socket_type ( m_ses . m_io_service ) ) ;
if ( ! s ) return ;
2007-10-22 06:17:26 +02:00
2010-10-12 10:57:43 +02:00
bool ssl = string_begins_no_case ( " https:// " , web - > url . c_str ( ) ) ;
void * userdata = 0 ;
# ifdef TORRENT_USE_OPENSSL
2011-09-10 07:52:07 +02:00
if ( ssl )
{
userdata = m_ssl_ctx . get ( ) ;
if ( ! userdata ) userdata = & m_ses . m_ssl_ctx ;
}
2010-10-12 10:57:43 +02:00
# endif
2011-01-24 04:24:28 +01:00
bool ret = instantiate_connection ( m_ses . m_io_service , m_ses . proxy ( ) , * s , userdata , 0 , true ) ;
2008-08-19 16:53:50 +02:00
( void ) ret ;
2007-10-22 06:17:26 +02:00
TORRENT_ASSERT ( ret ) ;
2010-08-23 08:27:18 +02:00
proxy_settings const & ps = m_ses . proxy ( ) ;
2010-10-12 10:57:43 +02:00
if ( ( ps . type = = proxy_settings : : http
2010-08-03 11:08:37 +02:00
| | ps . type = = proxy_settings : : http_pw )
2010-10-12 10:57:43 +02:00
& & ! ssl )
2007-04-25 20:26:35 +02:00
{
// the web seed connection will talk immediately to
// the proxy, without requiring CONNECT support
2008-10-18 09:12:04 +02:00
s - > get < http_stream > ( ) - > set_no_connect ( true ) ;
2007-04-25 20:26:35 +02:00
}
2008-02-28 08:34:07 +01:00
2010-08-03 11:08:37 +02:00
if ( ps . proxy_hostnames
& & ( ps . type = = proxy_settings : : socks5
| | ps . type = = proxy_settings : : socks5_pw ) )
{
// we're using a socks proxy and we're resolving
// hostnames through it
2011-09-10 07:52:07 +02:00
socks5_stream * str =
2010-10-12 10:57:43 +02:00
# ifdef TORRENT_USE_OPENSSL
2011-09-10 07:52:07 +02:00
ssl ? & s - > get < ssl_stream < socks5_stream > > ( ) - > next_layer ( ) :
2010-10-12 10:57:43 +02:00
# endif
2011-09-10 07:52:07 +02:00
s - > get < socks5_stream > ( ) ;
2010-10-12 10:57:43 +02:00
TORRENT_ASSERT ( str ) ;
2010-08-03 11:08:37 +02:00
using boost : : tuples : : ignore ;
std : : string hostname ;
error_code ec ;
boost : : tie ( ignore , ignore , hostname , ignore , ignore )
= parse_url_components ( web - > url , ec ) ;
2010-10-12 10:57:43 +02:00
str - > set_dst_name ( hostname ) ;
2010-08-03 11:08:37 +02:00
}
2008-12-30 04:54:07 +01:00
boost : : intrusive_ptr < peer_connection > c ;
2010-02-12 07:10:20 +01:00
if ( web - > type = = web_seed_entry : : url_seed )
2008-12-30 04:54:07 +01:00
{
2009-01-17 19:47:35 +01:00
c = new ( std : : nothrow ) web_peer_connection (
2010-10-10 20:43:58 +02:00
m_ses , shared_from_this ( ) , s , a , web - > url , 0 , // TODO: pass in web
web - > auth , web - > extra_headers ) ;
2008-12-30 04:54:07 +01:00
}
2010-02-12 07:10:20 +01:00
else if ( web - > type = = web_seed_entry : : http_seed )
2008-12-30 04:54:07 +01:00
{
2009-01-17 19:47:35 +01:00
c = new ( std : : nothrow ) http_seed_connection (
2010-10-10 20:43:58 +02:00
m_ses , shared_from_this ( ) , s , a , web - > url , 0 , // TODO: pass in web
web - > auth , web - > extra_headers ) ;
2008-12-30 04:54:07 +01:00
}
2008-04-07 04:51:21 +02:00
if ( ! c ) return ;
2010-02-12 07:10:20 +01:00
2011-09-17 07:16:05 +02:00
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
2007-02-12 06:46:29 +01:00
c - > m_in_constructor = false ;
# endif
2007-04-02 22:00:24 +02:00
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
2009-04-30 07:49:46 +02:00
boost : : shared_ptr < peer_plugin >
pp ( ( * i ) - > new_connection ( c . get ( ) ) ) ;
2007-04-02 22:00:24 +02:00
if ( pp ) c - > add_extension ( pp ) ;
}
# endif
2011-02-25 18:00:36 +01:00
TORRENT_TRY
2007-02-12 06:46:29 +01:00
{
// add the newly connected peer to this torrent's peer list
2007-10-31 10:48:20 +01:00
m_connections . insert ( boost : : get_pointer ( c ) ) ;
m_ses . m_connections . insert ( c ) ;
2010-02-12 07:10:20 +01:00
2010-10-17 18:15:32 +02:00
TORRENT_ASSERT ( ! web - > connection ) ;
2010-02-12 07:10:20 +01:00
web - > connection = c . get ( ) ;
2010-10-17 18:15:32 +02:00
# if defined TORRENT_VERBOSE_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " web seed connection started " < < web - > url < < " \n " ;
# endif
2010-10-30 09:11:04 +02:00
c - > start ( ) ;
2007-05-05 02:29:33 +02:00
m_ses . m_half_open . enqueue (
2010-05-02 08:29:52 +02:00
boost : : bind ( & peer_connection : : on_connect , c , _1 )
, boost : : bind ( & peer_connection : : on_timeout , c )
2007-05-05 02:29:33 +02:00
, seconds ( settings ( ) . peer_connect_timeout ) ) ;
2006-07-27 20:07:51 +02:00
}
2011-02-25 18:00:36 +01:00
TORRENT_CATCH ( std : : exception & e )
2007-02-12 06:46:29 +01:00
{
2011-03-10 06:01:36 +01:00
TORRENT_DECLARE_DUMMY ( std : : exception , e ) ;
2011-02-25 18:00:36 +01:00
( void ) e ;
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2007-02-12 06:46:29 +01:00
( * m_ses . m_logger ) < < " ** HOSTNAME LOOKUP FAILED!**: " < < e . what ( ) < < " \n " ;
# endif
2009-11-29 08:06:38 +01:00
c - > disconnect ( errors : : no_error , 1 ) ;
2007-02-12 06:46:29 +01:00
}
2008-04-07 04:51:21 +02:00
}
2003-10-23 01:00:57 +02:00
2007-05-02 21:47:38 +02:00
# ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
2007-08-07 09:17:13 +02:00
namespace
{
unsigned long swap_bytes ( unsigned long a )
{
2009-04-24 19:29:57 +02:00
return ( a > > 24 ) | ( ( a & 0xff0000 ) > > 8 ) | ( ( a & 0xff00 ) < < 8 ) | ( ( a & 0xff ) < < 24 ) ;
2007-08-07 09:17:13 +02:00
}
}
2007-01-29 08:39:33 +01:00
void torrent : : resolve_peer_country ( boost : : intrusive_ptr < peer_connection > const & p ) const
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-01-29 08:39:33 +01:00
if ( m_resolving_country
2010-02-15 08:52:32 +01:00
| | is_local ( p - > remote ( ) . address ( ) )
2007-01-29 08:39:33 +01:00
| | p - > has_country ( )
| | p - > is_connecting ( )
| | p - > is_queued ( )
2007-08-07 09:17:13 +02:00
| | p - > in_handshake ( )
| | p - > remote ( ) . address ( ) . is_v6 ( ) ) return ;
2007-01-29 08:39:33 +01:00
2007-08-07 09:17:13 +02:00
asio : : ip : : address_v4 reversed ( swap_bytes ( p - > remote ( ) . address ( ) . to_v4 ( ) . to_ulong ( ) ) ) ;
2008-10-21 10:45:42 +02:00
error_code ec ;
tcp : : resolver : : query q ( reversed . to_string ( ec ) + " .zz.countries.nerd.dk " , " 0 " ) ;
if ( ec )
{
p - > set_country ( " !! " ) ;
return ;
}
m_resolving_country = true ;
2010-02-14 02:39:55 +01:00
m_ses . m_host_resolver . async_resolve ( q ,
2010-05-02 08:29:52 +02:00
boost : : bind ( & torrent : : on_country_lookup , shared_from_this ( ) , _1 , _2 , p ) ) ;
2007-01-29 08:39:33 +01:00
}
namespace
{
2007-05-06 00:55:34 +02:00
struct country_entry
2007-01-29 08:39:33 +01:00
{
2007-05-06 00:55:34 +02:00
int code ;
char const * name ;
} ;
2007-01-29 08:39:33 +01:00
}
2008-05-03 18:05:42 +02:00
void torrent : : on_country_lookup ( error_code const & error , tcp : : resolver : : iterator i
2007-01-29 08:39:33 +01:00
, intrusive_ptr < peer_connection > p ) const
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-01-29 08:39:33 +01:00
INVARIANT_CHECK ;
m_resolving_country = false ;
2008-12-20 19:27:09 +01:00
if ( m_abort ) return ;
2007-01-29 08:39:33 +01:00
// must be ordered in increasing order
2007-09-26 02:03:22 +02:00
static const country_entry country_map [ ] =
2007-01-29 08:39:33 +01:00
{
2007-05-06 00:55:34 +02:00
{ 4 , " AF " } , { 8 , " AL " } , { 10 , " AQ " } , { 12 , " DZ " } , { 16 , " AS " }
, { 20 , " AD " } , { 24 , " AO " } , { 28 , " AG " } , { 31 , " AZ " } , { 32 , " AR " }
, { 36 , " AU " } , { 40 , " AT " } , { 44 , " BS " } , { 48 , " BH " } , { 50 , " BD " }
, { 51 , " AM " } , { 52 , " BB " } , { 56 , " BE " } , { 60 , " BM " } , { 64 , " BT " }
, { 68 , " BO " } , { 70 , " BA " } , { 72 , " BW " } , { 74 , " BV " } , { 76 , " BR " }
, { 84 , " BZ " } , { 86 , " IO " } , { 90 , " SB " } , { 92 , " VG " } , { 96 , " BN " }
, { 100 , " BG " } , { 104 , " MM " } , { 108 , " BI " } , { 112 , " BY " } , { 116 , " KH " }
, { 120 , " CM " } , { 124 , " CA " } , { 132 , " CV " } , { 136 , " KY " } , { 140 , " CF " }
, { 144 , " LK " } , { 148 , " TD " } , { 152 , " CL " } , { 156 , " CN " } , { 158 , " TW " }
, { 162 , " CX " } , { 166 , " CC " } , { 170 , " CO " } , { 174 , " KM " } , { 175 , " YT " }
, { 178 , " CG " } , { 180 , " CD " } , { 184 , " CK " } , { 188 , " CR " } , { 191 , " HR " }
, { 192 , " CU " } , { 203 , " CZ " } , { 204 , " BJ " } , { 208 , " DK " } , { 212 , " DM " }
, { 214 , " DO " } , { 218 , " EC " } , { 222 , " SV " } , { 226 , " GQ " } , { 231 , " ET " }
, { 232 , " ER " } , { 233 , " EE " } , { 234 , " FO " } , { 238 , " FK " } , { 239 , " GS " }
, { 242 , " FJ " } , { 246 , " FI " } , { 248 , " AX " } , { 250 , " FR " } , { 254 , " GF " }
, { 258 , " PF " } , { 260 , " TF " } , { 262 , " DJ " } , { 266 , " GA " } , { 268 , " GE " }
, { 270 , " GM " } , { 275 , " PS " } , { 276 , " DE " } , { 288 , " GH " } , { 292 , " GI " }
, { 296 , " KI " } , { 300 , " GR " } , { 304 , " GL " } , { 308 , " GD " } , { 312 , " GP " }
, { 316 , " GU " } , { 320 , " GT " } , { 324 , " GN " } , { 328 , " GY " } , { 332 , " HT " }
, { 334 , " HM " } , { 336 , " VA " } , { 340 , " HN " } , { 344 , " HK " } , { 348 , " HU " }
, { 352 , " IS " } , { 356 , " IN " } , { 360 , " ID " } , { 364 , " IR " } , { 368 , " IQ " }
, { 372 , " IE " } , { 376 , " IL " } , { 380 , " IT " } , { 384 , " CI " } , { 388 , " JM " }
, { 392 , " JP " } , { 398 , " KZ " } , { 400 , " JO " } , { 404 , " KE " } , { 408 , " KP " }
, { 410 , " KR " } , { 414 , " KW " } , { 417 , " KG " } , { 418 , " LA " } , { 422 , " LB " }
, { 426 , " LS " } , { 428 , " LV " } , { 430 , " LR " } , { 434 , " LY " } , { 438 , " LI " }
, { 440 , " LT " } , { 442 , " LU " } , { 446 , " MO " } , { 450 , " MG " } , { 454 , " MW " }
, { 458 , " MY " } , { 462 , " MV " } , { 466 , " ML " } , { 470 , " MT " } , { 474 , " MQ " }
, { 478 , " MR " } , { 480 , " MU " } , { 484 , " MX " } , { 492 , " MC " } , { 496 , " MN " }
, { 498 , " MD " } , { 500 , " MS " } , { 504 , " MA " } , { 508 , " MZ " } , { 512 , " OM " }
, { 516 , " NA " } , { 520 , " NR " } , { 524 , " NP " } , { 528 , " NL " } , { 530 , " AN " }
, { 533 , " AW " } , { 540 , " NC " } , { 548 , " VU " } , { 554 , " NZ " } , { 558 , " NI " }
, { 562 , " NE " } , { 566 , " NG " } , { 570 , " NU " } , { 574 , " NF " } , { 578 , " NO " }
, { 580 , " MP " } , { 581 , " UM " } , { 583 , " FM " } , { 584 , " MH " } , { 585 , " PW " }
, { 586 , " PK " } , { 591 , " PA " } , { 598 , " PG " } , { 600 , " PY " } , { 604 , " PE " }
, { 608 , " PH " } , { 612 , " PN " } , { 616 , " PL " } , { 620 , " PT " } , { 624 , " GW " }
, { 626 , " TL " } , { 630 , " PR " } , { 634 , " QA " } , { 634 , " QA " } , { 638 , " RE " }
, { 642 , " RO " } , { 643 , " RU " } , { 646 , " RW " } , { 654 , " SH " } , { 659 , " KN " }
, { 660 , " AI " } , { 662 , " LC " } , { 666 , " PM " } , { 670 , " VC " } , { 674 , " SM " }
, { 678 , " ST " } , { 682 , " SA " } , { 686 , " SN " } , { 690 , " SC " } , { 694 , " SL " }
, { 702 , " SG " } , { 703 , " SK " } , { 704 , " VN " } , { 705 , " SI " } , { 706 , " SO " }
, { 710 , " ZA " } , { 716 , " ZW " } , { 724 , " ES " } , { 732 , " EH " } , { 736 , " SD " }
, { 740 , " SR " } , { 744 , " SJ " } , { 748 , " SZ " } , { 752 , " SE " } , { 756 , " CH " }
, { 760 , " SY " } , { 762 , " TJ " } , { 764 , " TH " } , { 768 , " TG " } , { 772 , " TK " }
, { 776 , " TO " } , { 780 , " TT " } , { 784 , " AE " } , { 788 , " TN " } , { 792 , " TR " }
, { 795 , " TM " } , { 796 , " TC " } , { 798 , " TV " } , { 800 , " UG " } , { 804 , " UA " }
, { 807 , " MK " } , { 818 , " EG " } , { 826 , " GB " } , { 834 , " TZ " } , { 840 , " US " }
, { 850 , " VI " } , { 854 , " BF " } , { 858 , " UY " } , { 860 , " UZ " } , { 862 , " VE " }
, { 876 , " WF " } , { 882 , " WS " } , { 887 , " YE " } , { 891 , " CS " } , { 894 , " ZM " }
2007-01-29 08:39:33 +01:00
} ;
if ( error | | i = = tcp : : resolver : : iterator ( ) )
{
// this is used to indicate that we shouldn't
// try to resolve it again
p - > set_country ( " -- " ) ;
return ;
}
while ( i ! = tcp : : resolver : : iterator ( )
& & ! i - > endpoint ( ) . address ( ) . is_v4 ( ) ) + + i ;
if ( i ! = tcp : : resolver : : iterator ( ) )
{
// country is an ISO 3166 country code
int country = i - > endpoint ( ) . address ( ) . to_v4 ( ) . to_ulong ( ) & 0xffff ;
// look up the country code in the map
const int size = sizeof ( country_map ) / sizeof ( country_map [ 0 ] ) ;
2007-05-06 00:55:34 +02:00
country_entry tmp = { country , " " } ;
2011-03-30 18:03:35 +02:00
country_entry const * j =
2007-05-06 00:55:34 +02:00
std : : lower_bound ( country_map , country_map + size , tmp
2010-05-02 08:29:52 +02:00
, boost : : bind ( & country_entry : : code , _1 ) < boost : : bind ( & country_entry : : code , _2 ) ) ;
2011-03-30 18:03:35 +02:00
if ( j = = country_map + size
| | j - > code ! = country )
2007-01-29 08:39:33 +01:00
{
// unknown country!
p - > set_country ( " !! " ) ;
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2007-01-29 08:39:33 +01:00
( * m_ses . m_logger ) < < " IP " < < p - > remote ( ) . address ( ) < < " was mapped to unknown country: " < < country < < " \n " ;
# endif
return ;
}
2011-03-30 18:03:35 +02:00
p - > set_country ( j - > name ) ;
2007-01-29 08:39:33 +01:00
}
}
2007-05-02 21:47:38 +02:00
# endif
2007-01-29 08:39:33 +01:00
2008-07-01 01:14:31 +02:00
void torrent : : read_resume_data ( lazy_entry const & rd )
2008-04-16 08:31:05 +02:00
{
2008-07-01 01:14:31 +02:00
m_total_uploaded = rd . dict_find_int_value ( " total_uploaded " ) ;
m_total_downloaded = rd . dict_find_int_value ( " total_downloaded " ) ;
2010-02-14 02:39:55 +01:00
m_active_time = rd . dict_find_int_value ( " active_time " ) ;
m_finished_time = rd . dict_find_int_value ( " finished_time " ) ;
m_seeding_time = rd . dict_find_int_value ( " seeding_time " ) ;
2010-03-19 19:39:51 +01:00
m_last_seen_complete = rd . dict_find_int_value ( " last_seen_complete " ) ;
2010-03-21 19:15:04 +01:00
m_complete = rd . dict_find_int_value ( " num_seeds " , 0xffffff ) ;
2010-09-06 06:02:15 +02:00
m_incomplete = rd . dict_find_int_value ( " num_incomplete " , 0xffffff ) ;
m_downloaders = rd . dict_find_int_value ( " num_downloaders " , 0xffffff ) ;
2008-07-19 13:12:40 +02:00
set_upload_limit ( rd . dict_find_int_value ( " upload_rate_limit " , - 1 ) ) ;
set_download_limit ( rd . dict_find_int_value ( " download_rate_limit " , - 1 ) ) ;
set_max_connections ( rd . dict_find_int_value ( " max_connections " , - 1 ) ) ;
set_max_uploads ( rd . dict_find_int_value ( " max_uploads " , - 1 ) ) ;
2009-03-21 05:33:53 +01:00
m_seed_mode = rd . dict_find_int_value ( " seed_mode " , 0 ) & & m_torrent_file - > is_valid ( ) ;
if ( m_seed_mode ) m_verified . resize ( m_torrent_file - > num_pieces ( ) , false ) ;
2009-11-18 18:40:38 +01:00
super_seeding ( rd . dict_find_int_value ( " super_seeding " , 0 ) ) ;
2008-07-19 13:12:40 +02:00
2010-07-17 09:25:28 +02:00
m_last_scrape = rd . dict_find_int_value ( " last_scrape " , 0 ) ;
m_last_download = rd . dict_find_int_value ( " last_download " , 0 ) ;
m_last_upload = rd . dict_find_int_value ( " last_upload " , 0 ) ;
2011-01-18 04:41:54 +01:00
m_url = rd . dict_find_string_value ( " url " ) ;
m_uuid = rd . dict_find_string_value ( " uuid " ) ;
2011-03-23 03:46:22 +01:00
m_source_feed_url = rd . dict_find_string_value ( " feed " ) ;
if ( ! m_uuid . empty ( ) | | ! m_url . empty ( ) )
{
boost : : shared_ptr < torrent > me ( shared_from_this ( ) ) ;
// insert this torrent in the uuid index
m_ses . m_uuids . insert ( std : : make_pair ( m_uuid . empty ( )
? m_url : m_uuid , me ) ) ;
}
2011-01-18 04:41:54 +01:00
2010-03-09 04:21:35 +01:00
m_added_time = rd . dict_find_int_value ( " added_time " , m_added_time ) ;
m_completed_time = rd . dict_find_int_value ( " completed_time " , m_completed_time ) ;
if ( m_completed_time ! = 0 & & m_completed_time < m_added_time )
m_completed_time = m_added_time ;
2008-07-20 18:00:08 +02:00
lazy_entry const * file_priority = rd . dict_find_list ( " file_priority " ) ;
if ( file_priority & & file_priority - > list_size ( )
= = m_torrent_file - > num_files ( ) )
{
for ( int i = 0 ; i < file_priority - > list_size ( ) ; + + i )
m_file_priority [ i ] = file_priority - > list_int_value_at ( i , 1 ) ;
update_piece_priorities ( ) ;
}
2010-09-05 18:01:36 +02:00
2008-07-19 13:12:40 +02:00
lazy_entry const * piece_priority = rd . dict_find_string ( " piece_priority " ) ;
if ( piece_priority & & piece_priority - > string_length ( )
= = m_torrent_file - > num_pieces ( ) )
{
char const * p = piece_priority - > string_ptr ( ) ;
for ( int i = 0 ; i < piece_priority - > string_length ( ) ; + + i )
m_picker - > set_piece_priority ( i , p [ i ] ) ;
2010-09-05 06:31:13 +02:00
m_policy . recalculate_connect_candidates ( ) ;
2008-07-19 13:12:40 +02:00
}
2009-03-21 05:33:53 +01:00
if ( ! m_override_resume_data )
{
int auto_managed_ = rd . dict_find_int_value ( " auto_managed " , - 1 ) ;
if ( auto_managed_ ! = - 1 ) m_auto_managed = auto_managed_ ;
}
2008-09-23 05:52:49 +02:00
int sequential_ = rd . dict_find_int_value ( " sequential_download " , - 1 ) ;
if ( sequential_ ! = - 1 ) set_sequential_download ( sequential_ ) ;
2009-03-21 05:33:53 +01:00
if ( ! m_override_resume_data )
{
int paused_ = rd . dict_find_int_value ( " paused " , - 1 ) ;
2010-03-29 02:34:04 +02:00
if ( paused_ ! = - 1 )
{
m_allow_peers = ! paused_ ;
m_announce_to_dht = ! paused_ ;
m_announce_to_trackers = ! paused_ ;
m_announce_to_lsd = ! paused_ ;
}
int dht_ = rd . dict_find_int_value ( " announce_to_dht " , - 1 ) ;
if ( dht_ ! = - 1 ) m_announce_to_dht = dht_ ;
int lsd_ = rd . dict_find_int_value ( " announce_to_lsd " , - 1 ) ;
if ( lsd_ ! = - 1 ) m_announce_to_lsd = lsd_ ;
int track_ = rd . dict_find_int_value ( " announce_to_trackers " , - 1 ) ;
if ( track_ ! = - 1 ) m_announce_to_trackers = track_ ;
2009-03-21 05:33:53 +01:00
}
2008-09-22 19:39:18 +02:00
lazy_entry const * trackers = rd . dict_find_list ( " trackers " ) ;
if ( trackers )
{
2011-04-10 23:33:29 +02:00
if ( ! m_merge_resume_trackers ) m_trackers . clear ( ) ;
2008-09-22 19:39:18 +02:00
int tier = 0 ;
for ( int i = 0 ; i < trackers - > list_size ( ) ; + + i )
{
lazy_entry const * tier_list = trackers - > list_at ( i ) ;
if ( tier_list = = 0 | | tier_list - > type ( ) ! = lazy_entry : : list_t )
continue ;
for ( int j = 0 ; j < tier_list - > list_size ( ) ; + + j )
{
announce_entry e ( tier_list - > list_string_value_at ( j ) ) ;
if ( std : : find_if ( m_trackers . begin ( ) , m_trackers . end ( )
, boost : : bind ( & announce_entry : : url , _1 ) = = e . url ) ! = m_trackers . end ( ) )
continue ;
e . tier = tier ;
2010-05-03 10:24:30 +02:00
e . fail_limit = 0 ;
2008-09-22 19:39:18 +02:00
m_trackers . push_back ( e ) ;
}
+ + tier ;
}
std : : sort ( m_trackers . begin ( ) , m_trackers . end ( ) , boost : : bind ( & announce_entry : : tier , _1 )
< boost : : bind ( & announce_entry : : tier , _2 ) ) ;
2008-12-08 10:13:21 +01:00
2010-02-14 02:39:55 +01:00
if ( settings ( ) . prefer_udp_trackers )
2008-12-08 10:13:21 +01:00
prioritize_udp_trackers ( ) ;
2008-09-22 19:39:18 +02:00
}
lazy_entry const * url_list = rd . dict_find_list ( " url-list " ) ;
if ( url_list )
{
for ( int i = 0 ; i < url_list - > list_size ( ) ; + + i )
{
std : : string url = url_list - > list_string_value_at ( i ) ;
if ( url . empty ( ) ) continue ;
2008-12-30 04:54:07 +01:00
add_web_seed ( url , web_seed_entry : : url_seed ) ;
}
}
lazy_entry const * httpseeds = rd . dict_find_list ( " httpseeds " ) ;
if ( httpseeds )
{
for ( int i = 0 ; i < httpseeds - > list_size ( ) ; + + i )
{
std : : string url = httpseeds - > list_string_value_at ( i ) ;
if ( url . empty ( ) ) continue ;
add_web_seed ( url , web_seed_entry : : http_seed ) ;
2008-09-22 19:39:18 +02:00
}
}
2009-03-13 07:09:39 +01:00
if ( m_torrent_file - > is_merkle_torrent ( ) )
{
lazy_entry const * mt = rd . dict_find_string ( " merkle tree " ) ;
if ( mt )
{
std : : vector < sha1_hash > tree ;
tree . resize ( m_torrent_file - > merkle_tree ( ) . size ( ) ) ;
std : : memcpy ( & tree [ 0 ] , mt - > string_ptr ( )
, ( std : : min ) ( mt - > string_length ( ) , int ( tree . size ( ) ) * 20 ) ) ;
2009-06-10 10:42:05 +02:00
if ( mt - > string_length ( ) < int ( tree . size ( ) ) * 20 )
2009-03-13 07:09:39 +01:00
std : : memset ( & tree [ 0 ] + mt - > string_length ( ) / 20 , 0
, tree . size ( ) - mt - > string_length ( ) / 20 ) ;
m_torrent_file - > set_merkle_tree ( tree ) ;
}
else
{
// TODO: if this is a merkle torrent and we can't
// restore the tree, we need to wipe all the
2009-08-08 17:23:12 +02:00
// bits in the have array, but not necessarily
// we might want to do a full check to see if we have
// all the pieces
2009-03-13 07:09:39 +01:00
TORRENT_ASSERT ( false ) ;
}
}
2008-04-16 08:31:05 +02:00
}
2008-04-13 20:54:36 +02:00
void torrent : : write_resume_data ( entry & ret ) const
{
2009-05-07 00:36:24 +02:00
using namespace libtorrent : : detail ; // for write_*_endpoint()
2008-04-13 20:54:36 +02:00
ret [ " file-format " ] = " libtorrent resume file " ;
ret [ " file-version " ] = 1 ;
2009-06-27 23:47:30 +02:00
ret [ " libtorrent-version " ] = LIBTORRENT_VERSION ;
2008-04-13 20:54:36 +02:00
2008-04-16 08:31:05 +02:00
ret [ " total_uploaded " ] = m_total_uploaded ;
ret [ " total_downloaded " ] = m_total_downloaded ;
2010-02-14 02:39:55 +01:00
ret [ " active_time " ] = m_active_time ;
ret [ " finished_time " ] = m_finished_time ;
ret [ " seeding_time " ] = m_seeding_time ;
2010-03-19 19:39:51 +01:00
ret [ " last_seen_complete " ] = m_last_seen_complete ;
2008-05-18 21:31:06 +02:00
2010-09-06 06:02:15 +02:00
ret [ " num_seeds " ] = m_complete ;
ret [ " num_incomplete " ] = m_incomplete ;
ret [ " num_downloaders " ] = m_downloaders ;
2008-09-23 05:52:49 +02:00
ret [ " sequential_download " ] = m_sequential_download ;
2009-03-21 05:33:53 +01:00
ret [ " seed_mode " ] = m_seed_mode ;
2009-11-18 18:40:38 +01:00
ret [ " super_seeding " ] = m_super_seeding ;
2010-03-09 04:21:35 +01:00
ret [ " added_time " ] = m_added_time ;
ret [ " completed_time " ] = m_completed_time ;
2010-07-17 09:25:28 +02:00
ret [ " last_scrape " ] = m_last_scrape ;
ret [ " last_download " ] = m_last_download ;
ret [ " last_upload " ] = m_last_upload ;
2011-01-18 04:41:54 +01:00
if ( ! m_url . empty ( ) ) ret [ " url " ] = m_url ;
if ( ! m_uuid . empty ( ) ) ret [ " uuid " ] = m_uuid ;
2011-03-23 03:46:22 +01:00
if ( ! m_source_feed_url . empty ( ) ) ret [ " feed " ] = m_source_feed_url ;
2008-04-16 08:31:05 +02:00
2008-04-13 20:54:36 +02:00
const sha1_hash & info_hash = torrent_file ( ) . info_hash ( ) ;
ret [ " info-hash " ] = std : : string ( ( char * ) info_hash . begin ( ) , ( char * ) info_hash . end ( ) ) ;
2011-02-26 08:48:05 +01:00
if ( valid_metadata ( ) )
{
if ( m_magnet_link | | ( m_save_resume_flags & torrent_handle : : save_info_dict ) )
ret [ " info " ] = bdecode ( & torrent_file ( ) . metadata ( ) [ 0 ]
, & torrent_file ( ) . metadata ( ) [ 0 ] + torrent_file ( ) . metadata_size ( ) ) ;
}
2008-04-13 20:54:36 +02:00
// blocks per piece
int num_blocks_per_piece =
static_cast < int > ( torrent_file ( ) . piece_length ( ) ) / block_size ( ) ;
ret [ " blocks per piece " ] = num_blocks_per_piece ;
2009-03-13 07:09:39 +01:00
if ( m_torrent_file - > is_merkle_torrent ( ) )
{
// we need to save the whole merkle hash tree
// in order to resume
std : : string & tree_str = ret [ " merkle tree " ] . string ( ) ;
std : : vector < sha1_hash > const & tree = m_torrent_file - > merkle_tree ( ) ;
tree_str . resize ( tree . size ( ) * 20 ) ;
std : : memcpy ( & tree_str [ 0 ] , & tree [ 0 ] , tree . size ( ) * 20 ) ;
}
2008-04-13 20:54:36 +02:00
// if this torrent is a seed, we won't have a piece picker
// and there will be no half-finished pieces.
if ( ! is_seed ( ) )
{
const std : : vector < piece_picker : : downloading_piece > & q
= m_picker - > get_download_queue ( ) ;
// unfinished pieces
ret [ " unfinished " ] = entry : : list_type ( ) ;
entry : : list_type & up = ret [ " unfinished " ] . list ( ) ;
// info for each unfinished piece
for ( std : : vector < piece_picker : : downloading_piece > : : const_iterator i
= q . begin ( ) ; i ! = q . end ( ) ; + + i )
{
if ( i - > finished = = 0 ) continue ;
entry piece_struct ( entry : : dictionary_t ) ;
// the unfinished piece's index
piece_struct [ " piece " ] = i - > index ;
std : : string bitmask ;
const int num_bitmask_bytes
= ( std : : max ) ( num_blocks_per_piece / 8 , 1 ) ;
for ( int j = 0 ; j < num_bitmask_bytes ; + + j )
{
unsigned char v = 0 ;
int bits = ( std : : min ) ( num_blocks_per_piece - j * 8 , 8 ) ;
for ( int k = 0 ; k < bits ; + + k )
v | = ( i - > info [ j * 8 + k ] . state = = piece_picker : : block_info : : state_finished )
? ( 1 < < k ) : 0 ;
2009-10-28 20:55:20 +01:00
bitmask . append ( 1 , v ) ;
2008-04-13 20:54:36 +02:00
TORRENT_ASSERT ( bits = = 8 | | j = = num_bitmask_bytes - 1 ) ;
}
piece_struct [ " bitmask " ] = bitmask ;
// push the struct onto the unfinished-piece list
up . push_back ( piece_struct ) ;
}
}
2008-09-22 19:39:18 +02:00
// save trackers
if ( ! m_trackers . empty ( ) )
{
entry : : list_type & tr_list = ret [ " trackers " ] . list ( ) ;
tr_list . push_back ( entry : : list_type ( ) ) ;
int tier = 0 ;
for ( std : : vector < announce_entry > : : const_iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
{
2009-09-25 20:17:59 +02:00
// don't save trackers we can't trust
// TODO: save the send_stats state instead
if ( i - > send_stats = = false ) continue ;
2008-09-22 19:39:18 +02:00
if ( i - > tier = = tier )
{
tr_list . back ( ) . list ( ) . push_back ( i - > url ) ;
}
else
{
tr_list . push_back ( entry : : list_t ) ;
tr_list . back ( ) . list ( ) . push_back ( i - > url ) ;
tier = i - > tier ;
}
}
}
// save web seeds
if ( ! m_web_seeds . empty ( ) )
{
entry : : list_type & url_list = ret [ " url-list " ] . list ( ) ;
2008-12-30 04:54:07 +01:00
entry : : list_type & httpseed_list = ret [ " httpseeds " ] . list ( ) ;
2010-02-12 07:10:20 +01:00
for ( std : : list < web_seed_entry > : : const_iterator i = m_web_seeds . begin ( )
2008-12-30 04:54:07 +01:00
, end ( m_web_seeds . end ( ) ) ; i ! = end ; + + i )
{
2010-02-12 07:10:20 +01:00
if ( i - > type = = web_seed_entry : : url_seed )
url_list . push_back ( i - > url ) ;
else if ( i - > type = = web_seed_entry : : http_seed )
httpseed_list . push_back ( i - > url ) ;
2008-09-22 19:39:18 +02:00
}
}
2008-04-13 20:54:36 +02:00
// write have bitmask
2009-03-21 05:33:53 +01:00
// the pieces string has one byte per piece. Each
// byte is a bitmask representing different properties
// for the piece
// bit 0: set if we have the piece
// bit 1: set if we have verified the piece (in seed mode)
2008-04-13 20:54:36 +02:00
entry : : string_type & pieces = ret [ " pieces " ] . string ( ) ;
pieces . resize ( m_torrent_file - > num_pieces ( ) ) ;
2008-06-07 04:58:28 +02:00
if ( is_seed ( ) )
{
2008-07-19 13:12:40 +02:00
std : : memset ( & pieces [ 0 ] , 1 , pieces . size ( ) ) ;
2008-06-07 04:58:28 +02:00
}
else
{
for ( int i = 0 , end ( pieces . size ( ) ) ; i < end ; + + i )
pieces [ i ] = m_picker - > have_piece ( i ) ? 1 : 0 ;
}
2008-04-13 20:54:36 +02:00
2009-03-21 05:33:53 +01:00
if ( m_seed_mode )
{
TORRENT_ASSERT ( m_verified . size ( ) = = pieces . size ( ) ) ;
for ( int i = 0 , end ( pieces . size ( ) ) ; i < end ; + + i )
pieces [ i ] | = m_verified [ i ] ? 2 : 0 ;
}
2009-03-22 23:21:48 +01:00
// write renamed files
2011-01-31 01:47:09 +01:00
// TODO: make this more generic to not just work if files have been
// renamed, but also if they have been merged into a single file for instance
if ( & m_torrent_file - > files ( ) ! = & m_torrent_file - > orig_files ( )
& & m_torrent_file - > files ( ) . num_files ( ) = = m_torrent_file - > orig_files ( ) . num_files ( ) )
2009-03-22 23:21:48 +01:00
{
entry : : list_type & fl = ret [ " mapped_files " ] . list ( ) ;
for ( torrent_info : : file_iterator i = m_torrent_file - > begin_files ( )
, end ( m_torrent_file - > end_files ( ) ) ; i ! = end ; + + i )
{
2010-11-25 00:49:22 +01:00
fl . push_back ( m_torrent_file - > files ( ) . file_path ( * i ) ) ;
2009-03-22 23:21:48 +01:00
}
}
2008-04-13 20:54:36 +02:00
// write local peers
2009-05-07 00:36:24 +02:00
std : : back_insert_iterator < entry : : string_type > peers ( ret [ " peers " ] . string ( ) ) ;
std : : back_insert_iterator < entry : : string_type > banned_peers ( ret [ " banned_peers " ] . string ( ) ) ;
# if TORRENT_USE_IPV6
std : : back_insert_iterator < entry : : string_type > peers6 ( ret [ " peers6 " ] . string ( ) ) ;
std : : back_insert_iterator < entry : : string_type > banned_peers6 ( ret [ " banned_peers6 " ] . string ( ) ) ;
# endif
2009-04-30 07:49:46 +02:00
// failcount is a 5 bit value
2010-02-14 02:39:55 +01:00
int max_failcount = ( std : : min ) ( settings ( ) . max_failcount , 31 ) ;
2008-04-13 20:54:36 +02:00
for ( policy : : const_iterator i = m_policy . begin_peer ( )
, end ( m_policy . end_peer ( ) ) ; i ! = end ; + + i )
{
2008-05-03 18:05:42 +02:00
error_code ec ;
2009-05-07 00:36:24 +02:00
policy : : peer const * p = * i ;
address addr = p - > address ( ) ;
if ( p - > banned )
2008-04-13 20:54:36 +02:00
{
2009-05-07 00:36:24 +02:00
# if TORRENT_USE_IPV6
if ( addr . is_v6 ( ) )
2010-03-20 23:00:13 +01:00
{
write_address ( addr , banned_peers6 ) ;
write_uint16 ( p - > port , banned_peers6 ) ;
}
2009-05-07 00:36:24 +02:00
else
# endif
2010-03-20 23:00:13 +01:00
{
write_address ( addr , banned_peers ) ;
write_uint16 ( p - > port , banned_peers ) ;
}
2008-04-13 20:54:36 +02:00
continue ;
}
2009-05-07 00:36:24 +02:00
2008-04-13 20:54:36 +02:00
// we cannot save remote connection
// since we don't know their listen port
// unless they gave us their listen port
// through the extension handshake
// so, if the peer is not connectable (i.e. we
// don't know its listen port) or if it has
// been banned, don't save it.
2009-05-07 00:36:24 +02:00
if ( ! p - > connectable ) continue ;
2008-04-13 20:54:36 +02:00
2009-05-07 00:36:24 +02:00
// don't save peers that don't work
2009-06-10 10:42:05 +02:00
if ( int ( p - > failcount ) > = max_failcount ) continue ;
2008-04-13 20:54:36 +02:00
2009-05-07 00:36:24 +02:00
# if TORRENT_USE_IPV6
if ( addr . is_v6 ( ) )
2010-03-20 23:00:13 +01:00
{
write_address ( addr , peers6 ) ;
write_uint16 ( p - > port , peers6 ) ;
}
2009-05-07 00:36:24 +02:00
else
# endif
2010-03-20 23:00:13 +01:00
{
write_address ( addr , peers ) ;
write_uint16 ( p - > port , peers ) ;
}
2008-04-13 20:54:36 +02:00
}
2008-07-19 13:12:40 +02:00
ret [ " upload_rate_limit " ] = upload_limit ( ) ;
ret [ " download_rate_limit " ] = download_limit ( ) ;
ret [ " max_connections " ] = max_connections ( ) ;
ret [ " max_uploads " ] = max_uploads ( ) ;
2011-06-05 22:48:00 +02:00
ret [ " paused " ] = is_torrent_paused ( ) ;
2010-03-29 02:34:04 +02:00
ret [ " announce_to_dht " ] = m_announce_to_dht ;
ret [ " announce_to_trackers " ] = m_announce_to_trackers ;
ret [ " announce_to_lsd " ] = m_announce_to_lsd ;
2008-07-19 13:12:40 +02:00
ret [ " auto_managed " ] = m_auto_managed ;
// write piece priorities
entry : : string_type & piece_priority = ret [ " piece_priority " ] . string ( ) ;
piece_priority . resize ( m_torrent_file - > num_pieces ( ) ) ;
if ( is_seed ( ) )
{
std : : memset ( & piece_priority [ 0 ] , 1 , pieces . size ( ) ) ;
}
else
{
for ( int i = 0 , end ( piece_priority . size ( ) ) ; i < end ; + + i )
piece_priority [ i ] = m_picker - > piece_priority ( i ) ;
}
2008-07-20 18:00:08 +02:00
// write file priorities
entry : : list_type & file_priority = ret [ " file_priority " ] . list ( ) ;
file_priority . clear ( ) ;
for ( int i = 0 , end ( m_file_priority . size ( ) ) ; i < end ; + + i )
file_priority . push_back ( m_file_priority [ i ] ) ;
2008-04-13 20:54:36 +02:00
}
2008-04-13 08:32:48 +02:00
void torrent : : get_full_peer_list ( std : : vector < peer_list_entry > & v ) const
{
v . clear ( ) ;
v . reserve ( m_policy . num_peers ( ) ) ;
for ( policy : : const_iterator i = m_policy . begin_peer ( ) ;
i ! = m_policy . end_peer ( ) ; + + i )
{
peer_list_entry e ;
2009-05-07 00:36:24 +02:00
e . ip = ( * i ) - > ip ( ) ;
e . flags = ( * i ) - > banned ? peer_list_entry : : banned : 0 ;
e . failcount = ( * i ) - > failcount ;
e . source = ( * i ) - > source ;
2008-04-13 08:32:48 +02:00
v . push_back ( e ) ;
}
}
2007-11-25 19:48:43 +01:00
void torrent : : get_peer_info ( std : : vector < peer_info > & v )
{
v . clear ( ) ;
for ( peer_iterator i = begin ( ) ;
i ! = end ( ) ; + + i )
{
peer_connection * peer = * i ;
// incoming peers that haven't finished the handshake should
// not be included in this list
if ( peer - > associated_torrent ( ) . expired ( ) ) continue ;
v . push_back ( peer_info ( ) ) ;
peer_info & p = v . back ( ) ;
peer - > get_peer_info ( p ) ;
# ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
if ( resolving_countries ( ) )
resolve_peer_country ( intrusive_ptr < peer_connection > ( peer ) ) ;
# endif
}
}
2011-11-20 21:49:18 +01:00
void torrent : : get_download_queue ( std : : vector < partial_piece_info > * queue )
2007-11-25 19:48:43 +01:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2011-11-20 21:49:18 +01:00
queue - > clear ( ) ;
2009-05-03 11:45:07 +02:00
std : : vector < block_info > & blk = m_ses . m_block_info_storage ;
blk . clear ( ) ;
2007-11-25 19:48:43 +01:00
if ( ! valid_metadata ( ) | | is_seed ( ) ) return ;
piece_picker const & p = picker ( ) ;
std : : vector < piece_picker : : downloading_piece > const & q
= p . get_download_queue ( ) ;
2009-05-03 11:45:07 +02:00
const int blocks_per_piece = m_picker - > blocks_in_piece ( 0 ) ;
blk . resize ( q . size ( ) * blocks_per_piece ) ;
2011-11-20 21:49:18 +01:00
// for some weird reason valgrind claims these are uninitialized
// unless it's zeroed out here (block_info has a construct that's
// supposed to initialize it)
2011-11-25 00:01:35 +01:00
if ( ! blk . empty ( ) )
memset ( & blk [ 0 ] , 0 , sizeof ( blk [ 0 ] ) * blk . size ( ) ) ;
2009-05-03 11:45:07 +02:00
int counter = 0 ;
2007-11-25 19:48:43 +01:00
for ( std : : vector < piece_picker : : downloading_piece > : : const_iterator i
2009-05-03 11:45:07 +02:00
= q . begin ( ) ; i ! = q . end ( ) ; + + i , + + counter )
2007-11-25 19:48:43 +01:00
{
partial_piece_info pi ;
pi . piece_state = ( partial_piece_info : : state_t ) i - > state ;
pi . blocks_in_piece = p . blocks_in_piece ( i - > index ) ;
pi . finished = ( int ) i - > finished ;
pi . writing = ( int ) i - > writing ;
pi . requested = ( int ) i - > requested ;
2011-11-20 21:49:18 +01:00
TORRENT_ASSERT ( counter * blocks_per_piece + pi . blocks_in_piece < = int ( blk . size ( ) ) ) ;
2009-05-03 11:45:07 +02:00
pi . blocks = & blk [ counter * blocks_per_piece ] ;
2008-04-05 23:18:27 +02:00
int piece_size = int ( torrent_file ( ) . piece_size ( i - > index ) ) ;
2009-05-03 11:45:07 +02:00
for ( int j = 0 ; j < pi . blocks_in_piece ; + + j )
2007-11-25 19:48:43 +01:00
{
block_info & bi = pi . blocks [ j ] ;
bi . state = i - > info [ j ] . state ;
2010-02-14 02:39:55 +01:00
bi . block_size = j < pi . blocks_in_piece - 1 ? block_size ( )
: piece_size - ( j * block_size ( ) ) ;
2007-11-25 19:48:43 +01:00
bool complete = bi . state = = block_info : : writing
| | bi . state = = block_info : : finished ;
if ( i - > info [ j ] . peer = = 0 )
{
2009-05-03 11:45:07 +02:00
bi . set_peer ( tcp : : endpoint ( ) ) ;
2007-11-25 19:48:43 +01:00
bi . bytes_progress = complete ? bi . block_size : 0 ;
}
else
{
policy : : peer * p = static_cast < policy : : peer * > ( i - > info [ j ] . peer ) ;
if ( p - > connection )
{
2009-05-03 11:45:07 +02:00
bi . set_peer ( p - > connection - > remote ( ) ) ;
2007-11-25 19:48:43 +01:00
if ( bi . state = = block_info : : requested )
{
boost : : optional < piece_block_progress > pbp
= p - > connection - > downloading_piece_progress ( ) ;
if ( pbp & & pbp - > piece_index = = i - > index & & pbp - > block_index = = j )
{
bi . bytes_progress = pbp - > bytes_downloaded ;
TORRENT_ASSERT ( bi . bytes_progress < = bi . block_size ) ;
}
else
{
bi . bytes_progress = 0 ;
}
}
else
{
bi . bytes_progress = complete ? bi . block_size : 0 ;
}
}
else
{
2009-05-03 11:45:07 +02:00
bi . set_peer ( p - > ip ( ) ) ;
2007-11-25 19:48:43 +01:00
bi . bytes_progress = complete ? bi . block_size : 0 ;
}
}
pi . blocks [ j ] . num_peers = i - > info [ j ] . num_peers ;
}
pi . piece_index = i - > index ;
2011-11-20 21:49:18 +01:00
queue - > push_back ( pi ) ;
2007-11-25 19:48:43 +01:00
}
}
2010-11-29 02:33:05 +01:00
bool torrent : : connect_to_peer ( policy : : peer * peerinfo , bool ignore_limit )
2006-04-25 23:04:48 +02:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2007-05-02 19:38:37 +02:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( peerinfo ) ;
TORRENT_ASSERT ( peerinfo - > connection = = 0 ) ;
2008-03-29 20:39:24 +01:00
2009-04-30 07:49:46 +02:00
peerinfo - > last_connected = m_ses . session_time ( ) ;
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2011-03-27 08:07:23 +02:00
if ( ! settings ( ) . allow_multiple_connections_per_ip )
{
// this asserts that we don't have duplicates in the policy's peer list
peer_iterator i_ = std : : find_if ( m_connections . begin ( ) , m_connections . end ( )
, boost : : bind ( & peer_connection : : remote , _1 ) = = peerinfo - > ip ( ) ) ;
2011-04-09 23:04:02 +02:00
# if TORRENT_USE_I2P
2011-03-27 08:07:23 +02:00
TORRENT_ASSERT ( i_ = = m_connections . end ( )
| | ( * i_ ) - > type ( ) ! = peer_connection : : bittorrent_connection
2011-04-09 23:04:02 +02:00
| | peerinfo - > is_i2p_addr ) ;
# else
TORRENT_ASSERT ( i_ = = m_connections . end ( )
| | ( * i_ ) - > type ( ) ! = peer_connection : : bittorrent_connection ) ;
2009-09-06 02:57:01 +02:00
# endif
2011-03-27 08:07:23 +02:00
}
2011-03-27 10:05:57 +02:00
# endif
2007-05-04 18:35:29 +02:00
2011-09-12 05:51:49 +02:00
// extend connect timeout by this many seconds
int timeout_extend = 0 ;
2010-11-29 02:33:05 +01:00
TORRENT_ASSERT ( want_more_peers ( ) | | ignore_limit ) ;
TORRENT_ASSERT ( m_ses . num_connections ( ) < m_ses . settings ( ) . connections_limit | | ignore_limit ) ;
2007-05-02 19:38:37 +02:00
2008-07-14 13:15:35 +02:00
tcp : : endpoint a ( peerinfo - > ip ( ) ) ;
2011-02-27 18:26:57 +01:00
TORRENT_ASSERT ( ! m_apply_ip_filter
| | ( m_ses . m_ip_filter . access ( peerinfo - > address ( ) ) & ip_filter : : blocked ) = = 0 ) ;
2006-11-24 15:22:52 +01:00
2008-01-27 23:39:50 +01:00
boost : : shared_ptr < socket_type > s ( new socket_type ( m_ses . m_io_service ) ) ;
2007-10-22 06:17:26 +02:00
2009-08-20 05:19:12 +02:00
# if TORRENT_USE_I2P
bool i2p = peerinfo - > is_i2p_addr ;
if ( i2p )
{
bool ret = instantiate_connection ( m_ses . m_io_service , m_ses . i2p_proxy ( ) , * s ) ;
( void ) ret ;
TORRENT_ASSERT ( ret ) ;
s - > get < i2p_stream > ( ) - > set_destination ( static_cast < policy : : i2p_peer * > ( peerinfo ) - > destination ) ;
s - > get < i2p_stream > ( ) - > set_command ( i2p_stream : : cmd_connect ) ;
s - > get < i2p_stream > ( ) - > set_session_id ( m_ses . m_i2p_conn . session_id ( ) ) ;
2011-09-12 05:51:49 +02:00
// i2p setups are slow
timeout_extend = 20 ;
2009-08-20 05:19:12 +02:00
}
else
# endif
{
2010-11-29 02:33:05 +01:00
// this is where we determine if we open a regular TCP connection
// or a uTP connection. If the m_utp_socket_manager pointer is not passed in
// we'll instantiate a TCP connection
utp_socket_manager * sm = 0 ;
if ( m_ses . m_settings . enable_outgoing_utp
& & ( ! m_ses . m_settings . enable_outgoing_tcp
| | peerinfo - > supports_utp
| | peerinfo - > confirmed_supports_utp ) )
sm = & m_ses . m_utp_socket_manager ;
// don't make a TCP connection if it's disabled
if ( sm = = 0 & & ! m_ses . m_settings . enable_outgoing_tcp ) return false ;
2011-09-12 05:51:49 +02:00
void * userdata = 0 ;
# ifdef TORRENT_USE_OPENSSL
if ( is_ssl_torrent ( ) )
{
userdata = m_ssl_ctx . get ( ) ;
// SSL handshakes are slow
timeout_extend = 10 ;
// we don't support SSL over uTP yet
sm = 0 ;
}
# endif
bool ret = instantiate_connection ( m_ses . m_io_service , m_ses . proxy ( ) , * s , userdata , sm , true ) ;
2009-08-20 05:19:12 +02:00
( void ) ret ;
TORRENT_ASSERT ( ret ) ;
}
2007-10-22 06:17:26 +02:00
2009-05-01 06:59:15 +02:00
m_ses . setup_socket_buffers ( * s ) ;
2006-04-25 23:04:48 +02:00
boost : : intrusive_ptr < peer_connection > c ( new bt_peer_connection (
2007-04-10 23:23:13 +02:00
m_ses , shared_from_this ( ) , s , a , peerinfo ) ) ;
2007-06-20 20:41:53 +02:00
2011-09-17 07:16:05 +02:00
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
2006-04-25 23:04:48 +02:00
c - > m_in_constructor = false ;
# endif
2011-06-01 08:47:57 +02:00
c - > add_stat ( size_type ( peerinfo - > prev_amount_download ) < < 10
, size_type ( peerinfo - > prev_amount_upload ) < < 10 ) ;
2008-04-07 10:15:31 +02:00
peerinfo - > prev_amount_download = 0 ;
peerinfo - > prev_amount_upload = 0 ;
2007-10-31 10:48:20 +01:00
# ifndef TORRENT_DISABLE_EXTENSIONS
2008-04-07 04:51:21 +02:00
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
2011-02-25 18:00:36 +01:00
TORRENT_TRY {
2007-10-31 10:48:20 +01:00
boost : : shared_ptr < peer_plugin > pp ( ( * i ) - > new_connection ( c . get ( ) ) ) ;
if ( pp ) c - > add_extension ( pp ) ;
2011-02-25 18:00:36 +01:00
} TORRENT_CATCH ( std : : exception & ) { }
2008-04-07 04:51:21 +02:00
}
2007-10-31 10:48:20 +01:00
# endif
2007-09-19 08:05:14 +02:00
2008-04-07 04:51:21 +02:00
// add the newly connected peer to this torrent's peer list
m_connections . insert ( boost : : get_pointer ( c ) ) ;
m_ses . m_connections . insert ( c ) ;
2009-08-02 00:48:43 +02:00
m_policy . set_connection ( peerinfo , c . get ( ) ) ;
2008-04-07 04:51:21 +02:00
c - > start ( ) ;
2006-04-25 23:04:48 +02:00
2008-04-07 04:51:21 +02:00
int timeout = settings ( ) . peer_connect_timeout ;
if ( peerinfo ) timeout + = 3 * peerinfo - > failcount ;
2011-09-12 05:51:49 +02:00
timeout + = timeout_extend ;
2007-10-15 07:03:29 +02:00
2011-02-25 18:00:36 +01:00
TORRENT_TRY
2008-04-07 04:51:21 +02:00
{
2007-05-05 02:29:33 +02:00
m_ses . m_half_open . enqueue (
2010-05-02 08:29:52 +02:00
boost : : bind ( & peer_connection : : on_connect , c , _1 )
, boost : : bind ( & peer_connection : : on_timeout , c )
2007-10-15 07:03:29 +02:00
, seconds ( timeout ) ) ;
2006-04-25 23:04:48 +02:00
}
2011-02-25 18:00:36 +01:00
TORRENT_CATCH ( std : : exception & )
2006-04-25 23:04:48 +02:00
{
2007-10-31 10:48:20 +01:00
std : : set < peer_connection * > : : iterator i
= m_connections . find ( boost : : get_pointer ( c ) ) ;
2006-04-25 23:04:48 +02:00
if ( i ! = m_connections . end ( ) ) m_connections . erase ( i ) ;
2009-11-29 08:06:38 +01:00
c - > disconnect ( errors : : no_error , 1 ) ;
2007-10-31 10:48:20 +01:00
return false ;
2006-01-06 21:20:20 +01:00
}
2008-09-25 09:40:55 +02:00
2010-09-05 18:01:36 +02:00
if ( m_share_mode )
recalc_share_mode ( ) ;
2008-09-25 09:40:55 +02:00
return peerinfo - > connection ;
2003-12-01 06:01:40 +01:00
}
2008-09-24 04:32:33 +02:00
bool torrent : : set_metadata ( char const * metadata_buf , int metadata_size )
2006-11-14 01:08:16 +01:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-06-10 22:46:09 +02:00
INVARIANT_CHECK ;
2008-09-24 04:32:33 +02:00
if ( m_torrent_file - > is_valid ( ) ) return false ;
hasher h ;
h . update ( metadata_buf , metadata_size ) ;
sha1_hash info_hash = h . final ( ) ;
if ( info_hash ! = m_torrent_file - > info_hash ( ) )
{
if ( alerts ( ) . should_post < metadata_failed_alert > ( ) )
{
alerts ( ) . post_alert ( metadata_failed_alert ( get_handle ( ) ) ) ;
}
return false ;
}
lazy_entry metadata ;
2009-02-13 20:01:02 +01:00
error_code ec ;
2010-10-28 06:01:59 +02:00
int ret = lazy_bdecode ( metadata_buf , metadata_buf + metadata_size , metadata , ec ) ;
2010-11-15 06:10:36 +01:00
if ( ret ! = 0 | | ! m_torrent_file - > parse_info_section ( metadata , ec , 0 ) )
2007-12-28 21:11:10 +01:00
{
2008-09-24 04:32:33 +02:00
// this means the metadata is correct, since we
// verified it against the info-hash, but we
// failed to parse it. Pause the torrent
if ( alerts ( ) . should_post < metadata_failed_alert > ( ) )
{
2010-10-28 06:01:59 +02:00
// TODO: pass in ec along with the alert
2008-09-24 04:32:33 +02:00
alerts ( ) . post_alert ( metadata_failed_alert ( get_handle ( ) ) ) ;
}
2009-11-29 08:06:38 +01:00
set_error ( errors : : invalid_swarm_metadata , " " ) ;
2008-09-24 04:32:33 +02:00
pause ( ) ;
2007-12-28 21:11:10 +01:00
return false ;
}
2006-11-14 01:08:16 +01:00
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < metadata_received_alert > ( ) )
2006-11-14 01:08:16 +01:00
{
m_ses . m_alerts . post_alert ( metadata_received_alert (
2008-07-06 14:22:56 +02:00
get_handle ( ) ) ) ;
2006-11-14 01:08:16 +01:00
}
2008-03-08 07:06:31 +01:00
2010-01-19 00:44:05 +01:00
// this makes the resume data "paused" and
// "auto_managed" fields be ignored. If the paused
// field is not ignored, the invariant check will fail
// since we will be paused but without having disconnected
// any of the peers.
m_override_resume_data = true ;
2008-03-08 07:06:31 +01:00
init ( ) ;
2007-12-29 08:16:36 +01:00
return true ;
2006-11-14 01:08:16 +01:00
}
2008-04-07 04:51:21 +02:00
bool torrent : : attach_peer ( peer_connection * p )
2003-12-01 06:01:40 +01:00
{
2007-08-16 14:41:46 +02:00
// INVARIANT_CHECK;
2006-04-25 23:04:48 +02:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( p ! = 0 ) ;
TORRENT_ASSERT ( ! p - > is_local ( ) ) ;
2004-01-13 04:08:59 +01:00
2008-06-05 20:19:03 +02:00
m_has_incoming = true ;
2011-03-06 21:38:24 +01:00
if ( m_apply_ip_filter
& & m_ses . m_ip_filter . access ( p - > remote ( ) . address ( ) ) & ip_filter : : blocked )
{
if ( m_ses . m_alerts . should_post < peer_blocked_alert > ( ) )
m_ses . m_alerts . post_alert ( peer_blocked_alert ( get_handle ( ) , p - > remote ( ) . address ( ) ) ) ;
p - > disconnect ( errors : : banned_by_ip_filter ) ;
return false ;
}
2008-03-14 11:17:27 +01:00
if ( ( m_state = = torrent_status : : queued_for_checking
2008-11-19 01:46:48 +01:00
| | m_state = = torrent_status : : checking_files
| | m_state = = torrent_status : : checking_resume_data )
2008-03-14 11:17:27 +01:00
& & valid_metadata ( ) )
2008-03-08 07:06:31 +01:00
{
2009-11-29 08:06:38 +01:00
p - > disconnect ( errors : : torrent_not_ready ) ;
2008-04-07 04:51:21 +02:00
return false ;
2008-03-08 07:06:31 +01:00
}
2007-10-31 10:48:20 +01:00
if ( m_ses . m_connections . find ( p ) = = m_ses . m_connections . end ( ) )
2006-04-25 23:04:48 +02:00
{
2009-11-29 08:06:38 +01:00
p - > disconnect ( errors : : peer_not_constructed ) ;
2008-04-07 04:51:21 +02:00
return false ;
2006-04-25 23:04:48 +02:00
}
2006-10-11 16:02:21 +02:00
if ( m_ses . is_aborted ( ) )
2006-05-28 21:03:54 +02:00
{
2009-11-29 08:06:38 +01:00
p - > disconnect ( errors : : session_closing ) ;
2008-04-07 04:51:21 +02:00
return false ;
2006-05-28 21:03:54 +02:00
}
2011-02-21 06:24:41 +01:00
if ( m_connections . size ( ) > = m_max_connections )
2007-12-27 11:19:36 +01:00
{
2009-11-29 08:06:38 +01:00
p - > disconnect ( errors : : too_many_connections ) ;
2008-04-07 04:51:21 +02:00
return false ;
2007-12-27 11:19:36 +01:00
}
2011-02-25 18:00:36 +01:00
TORRENT_TRY
2006-04-25 23:04:48 +02:00
{
2006-11-14 01:08:16 +01:00
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
boost : : shared_ptr < peer_plugin > pp ( ( * i ) - > new_connection ( p ) ) ;
if ( pp ) p - > add_extension ( pp ) ;
}
# endif
2009-04-30 07:49:46 +02:00
if ( ! m_policy . new_connection ( * p , m_ses . session_time ( ) ) )
2011-05-01 20:37:49 +02:00
{
# if defined TORRENT_LOGGING
( * m_ses . m_logger ) < < time_now_string ( ) < < " CLOSING CONNECTION "
< < p - > remote ( ) < < " policy::new_connection returned false (i.e. peer list full) \n " ;
# endif
2011-09-12 05:51:49 +02:00
p - > disconnect ( errors : : too_many_connections ) ;
2008-04-07 04:51:21 +02:00
return false ;
2011-05-01 20:37:49 +02:00
}
2006-04-25 23:04:48 +02:00
}
2011-02-25 18:00:36 +01:00
TORRENT_CATCH ( std : : exception & e )
2006-04-25 23:04:48 +02:00
{
2011-03-10 06:01:36 +01:00
TORRENT_DECLARE_DUMMY ( std : : exception , e ) ;
2011-02-21 06:24:41 +01:00
( void ) e ;
2008-04-07 04:51:21 +02:00
# if defined TORRENT_LOGGING
2007-12-19 22:36:54 +01:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " CLOSING CONNECTION "
< < p - > remote ( ) < < " policy::new_connection threw: " < < e . what ( ) < < " \n " ;
# endif
2009-11-29 08:06:38 +01:00
p - > disconnect ( errors : : no_error ) ;
2008-04-07 04:51:21 +02:00
return false ;
2006-04-25 23:04:48 +02:00
}
2008-01-19 20:00:54 +01:00
TORRENT_ASSERT ( m_connections . find ( p ) = = m_connections . end ( ) ) ;
peer_iterator ci = m_connections . insert ( p ) . first ;
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2008-05-03 18:05:42 +02:00
error_code ec ;
2008-01-31 18:52:29 +01:00
TORRENT_ASSERT ( p - > remote ( ) = = p - > get_socket ( ) - > remote_endpoint ( ec ) | | ec ) ;
# endif
2008-11-29 22:33:21 +01:00
# if defined TORRENT_DEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
2007-10-31 10:48:20 +01:00
m_policy . check_invariant ( ) ;
2005-10-01 13:20:47 +02:00
# endif
2010-09-05 18:01:36 +02:00
if ( m_share_mode )
recalc_share_mode ( ) ;
2008-04-07 04:51:21 +02:00
return true ;
2003-10-23 01:00:57 +02:00
}
2007-05-02 19:38:37 +02:00
bool torrent : : want_more_peers ( ) const
{
2011-02-21 06:24:41 +01:00
return m_connections . size ( ) < m_max_connections
2008-06-29 21:08:30 +02:00
& & ! is_paused ( )
2008-11-19 01:46:48 +01:00
& & ( ( m_state ! = torrent_status : : checking_files
& & m_state ! = torrent_status : : checking_resume_data
& & m_state ! = torrent_status : : queued_for_checking )
2008-05-18 20:30:26 +02:00
| | ! valid_metadata ( ) )
2008-10-30 18:13:10 +01:00
& & m_policy . num_connect_candidates ( ) > 0
2010-12-17 04:20:36 +01:00
& & ! m_abort
& & ( m_ses . settings ( ) . seeding_outgoing_connections
2010-12-19 00:21:13 +01:00
| | ( m_state ! = torrent_status : : seeding
& & m_state ! = torrent_status : : finished ) ) ;
2007-05-02 19:38:37 +02:00
}
2009-06-12 18:40:38 +02:00
void torrent : : disconnect_all ( error_code const & ec )
2003-10-23 01:00:57 +02:00
{
2010-03-29 02:34:04 +02:00
// doesn't work with the !m_allow_peers -> m_num_peers == 0 condition
2008-09-27 06:58:40 +02:00
// INVARIANT_CHECK;
2006-04-25 23:04:48 +02:00
while ( ! m_connections . empty ( ) )
2003-10-23 01:00:57 +02:00
{
2007-10-31 10:48:20 +01:00
peer_connection * p = * m_connections . begin ( ) ;
TORRENT_ASSERT ( p - > associated_torrent ( ) . lock ( ) . get ( ) = = this ) ;
2005-09-01 23:04:21 +02:00
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2010-01-19 00:44:05 +01:00
( * p - > m_logger ) < < " *** CLOSING CONNECTION: " < < ec . message ( ) < < " \n " ;
2005-09-01 23:04:21 +02:00
# endif
2011-05-08 11:04:59 +02:00
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
2006-04-25 23:04:48 +02:00
std : : size_t size = m_connections . size ( ) ;
# endif
2008-01-17 21:03:59 +01:00
if ( p - > is_disconnecting ( ) )
2008-01-17 22:25:19 +01:00
m_connections . erase ( m_connections . begin ( ) ) ;
2008-01-17 21:03:59 +01:00
else
2009-06-12 18:40:38 +02:00
p - > disconnect ( ec ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_connections . size ( ) < = size ) ;
2004-01-20 12:01:50 +01:00
}
}
2004-01-13 04:08:59 +01:00
2010-10-03 12:07:38 +02:00
// this returns true if lhs is a better disconnect candidate than rhs
bool compare_disconnect_peer ( peer_connection const * lhs , peer_connection const * rhs )
2008-05-12 07:17:11 +02:00
{
2010-10-03 12:07:38 +02:00
// prefer to disconnect peers that are already disconnecting
if ( lhs - > is_disconnecting ( ) ! = rhs - > is_disconnecting ( ) )
return lhs - > is_disconnecting ( ) ;
2009-05-22 08:27:47 +02:00
2010-10-03 12:07:38 +02:00
// prefer to disconnect peers we're not interested in
if ( lhs - > is_interesting ( ) ! = rhs - > is_interesting ( ) )
return rhs - > is_interesting ( ) ;
2008-05-12 07:17:11 +02:00
2010-10-03 12:07:38 +02:00
// prefer to disconnect peers that are not seeds
if ( lhs - > is_seed ( ) ! = rhs - > is_seed ( ) )
return rhs - > is_seed ( ) ;
2008-05-12 07:17:11 +02:00
2010-10-03 12:07:38 +02:00
// prefer to disconnect peers that are on parole
if ( lhs - > on_parole ( ) ! = rhs - > on_parole ( ) )
return lhs - > on_parole ( ) ;
2008-05-12 07:17:11 +02:00
2010-10-03 12:07:38 +02:00
// prefer to disconnect peers that send data at a lower rate
size_type lhs_transferred = lhs - > statistics ( ) . total_payload_download ( ) ;
size_type rhs_transferred = rhs - > statistics ( ) . total_payload_download ( ) ;
2008-05-12 07:17:11 +02:00
2010-10-03 12:07:38 +02:00
ptime now = time_now ( ) ;
size_type lhs_time_connected = total_seconds ( now - lhs - > connected_time ( ) ) ;
size_type rhs_time_connected = total_seconds ( now - rhs - > connected_time ( ) ) ;
2008-05-12 07:17:11 +02:00
2010-10-03 12:07:38 +02:00
lhs_transferred / = lhs_time_connected + 1 ;
rhs_transferred / = ( rhs_time_connected + 1 ) ;
if ( lhs_transferred ! = rhs_transferred )
return lhs_transferred < rhs_transferred ;
2008-05-12 07:17:11 +02:00
2010-10-03 12:07:38 +02:00
// prefer to disconnect peers that chokes us
if ( lhs - > is_choked ( ) ! = rhs - > is_choked ( ) )
return lhs - > is_choked ( ) ;
2008-05-12 07:17:11 +02:00
2010-10-03 12:07:38 +02:00
return lhs - > last_received ( ) < rhs - > last_received ( ) ;
2008-05-12 07:17:11 +02:00
}
2010-10-03 12:07:38 +02:00
int torrent : : disconnect_peers ( int num , error_code const & ec )
2008-05-12 07:17:11 +02:00
{
2009-01-27 07:17:55 +01:00
INVARIANT_CHECK ;
2009-02-03 08:46:24 +01:00
# ifdef TORRENT_DEBUG
2009-05-22 08:27:47 +02:00
for ( std : : set < peer_connection * > : : iterator i = m_connections . begin ( )
, end ( m_connections . end ( ) ) ; i ! = end ; + + i )
2009-02-03 08:46:24 +01:00
{
// make sure this peer is not a dangling pointer
TORRENT_ASSERT ( m_ses . has_peer ( * i ) ) ;
}
# endif
2009-05-22 08:27:47 +02:00
int ret = 0 ;
while ( ret < num & & ! m_connections . empty ( ) )
2008-05-12 07:17:11 +02:00
{
2009-05-22 08:27:47 +02:00
std : : set < peer_connection * > : : iterator i = std : : min_element (
m_connections . begin ( ) , m_connections . end ( ) , compare_disconnect_peer ) ;
2008-05-12 07:17:11 +02:00
peer_connection * p = * i ;
+ + ret ;
2010-03-08 02:54:56 +01:00
TORRENT_ASSERT ( p - > associated_torrent ( ) . lock ( ) . get ( ) = = this ) ;
2011-05-08 11:04:59 +02:00
# if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
2010-03-08 02:54:56 +01:00
int num_conns = m_connections . size ( ) ;
# endif
2010-10-03 12:07:38 +02:00
p - > disconnect ( ec ) ;
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( int ( m_connections . size ( ) ) = = num_conns - 1 ) ;
2008-05-12 07:17:11 +02:00
}
2009-05-22 08:27:47 +02:00
2008-05-12 07:17:11 +02:00
return ret ;
}
2007-02-20 00:06:20 +01:00
int torrent : : bandwidth_throttle ( int channel ) const
{
2009-04-26 02:21:59 +02:00
return m_bandwidth_channel [ channel ] . throttle ( ) ;
2007-01-10 16:02:25 +01:00
}
2007-10-18 02:32:16 +02:00
// called when torrent is finished (all interesting
// pieces have been downloaded)
2005-06-11 01:12:50 +02:00
void torrent : : finished ( )
2004-01-20 12:01:50 +01:00
{
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2008-10-05 03:44:57 +02:00
TORRENT_ASSERT ( is_finished ( ) ) ;
TORRENT_ASSERT ( m_state ! = torrent_status : : finished & & m_state ! = torrent_status : : seeding ) ;
2008-07-06 14:22:56 +02:00
if ( alerts ( ) . should_post < torrent_finished_alert > ( ) )
2004-01-21 14:16:11 +01:00
{
alerts ( ) . post_alert ( torrent_finished_alert (
2008-07-06 14:22:56 +02:00
get_handle ( ) ) ) ;
2004-01-21 14:16:11 +01:00
}
2008-07-03 12:05:51 +02:00
set_state ( torrent_status : : finished ) ;
2008-05-29 05:37:19 +02:00
set_queue_position ( - 1 ) ;
// we have to call completed() before we start
// disconnecting peers, since there's an assert
// to make sure we're cleared the piece picker
if ( is_seed ( ) ) completed ( ) ;
2008-03-08 07:06:31 +01:00
2009-11-24 19:49:59 +01:00
send_upload_only ( ) ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2010-03-09 04:21:35 +01:00
m_completed_time = time ( 0 ) ;
2008-08-18 22:02:50 +02:00
// disconnect all seeds
// TODO: should disconnect all peers that have the pieces we have
// not just seeds
2006-04-25 23:04:48 +02:00
std : : vector < peer_connection * > seeds ;
2004-01-20 12:01:50 +01:00
for ( peer_iterator i = m_connections . begin ( ) ;
2005-06-11 01:12:50 +02:00
i ! = m_connections . end ( ) ; + + i )
2004-01-20 12:01:50 +01:00
{
2007-10-31 10:48:20 +01:00
peer_connection * p = * i ;
TORRENT_ASSERT ( p - > associated_torrent ( ) . lock ( ) . get ( ) = = this ) ;
2008-05-20 05:21:45 +02:00
if ( p - > upload_only ( ) )
2005-09-01 23:04:21 +02:00
{
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2007-10-31 10:48:20 +01:00
( * p - > m_logger ) < < " *** SEED, CLOSING CONNECTION \n " ;
2005-09-01 23:04:21 +02:00
# endif
2007-10-31 10:48:20 +01:00
seeds . push_back ( p ) ;
2005-09-01 23:04:21 +02:00
}
2003-10-23 01:00:57 +02:00
}
2006-04-25 23:04:48 +02:00
std : : for_each ( seeds . begin ( ) , seeds . end ( )
2010-05-02 08:29:52 +02:00
, boost : : bind ( & peer_connection : : disconnect , _1 , errors : : torrent_finished , 0 ) ) ;
2004-01-21 14:16:11 +01:00
2009-06-10 10:30:55 +02:00
if ( m_abort ) return ;
2009-05-06 09:06:26 +02:00
m_policy . recalculate_connect_candidates ( ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_storage ) ;
2007-10-02 20:34:34 +02:00
// we need to keep the object alive during this operation
m_storage - > async_release_files (
2010-05-02 08:29:52 +02:00
boost : : bind ( & torrent : : on_files_released , shared_from_this ( ) , _1 , _2 ) ) ;
2011-01-30 14:15:29 +01:00
// this torrent just completed downloads, which means it will fall
// under a different limit with the auto-manager. Make sure we
// update auto-manage torrents in that case
2011-12-23 18:16:14 +01:00
if ( m_auto_managed )
m_ses . m_auto_manage_time_scaler = 2 ;
2005-06-11 01:12:50 +02:00
}
2008-05-20 05:21:45 +02:00
// this is called when we were finished, but some files were
// marked for downloading, and we are no longer finished
void torrent : : resume_download ( )
{
INVARIANT_CHECK ;
2005-06-11 01:12:50 +02:00
2008-06-08 15:47:35 +02:00
TORRENT_ASSERT ( ! is_finished ( ) ) ;
2008-07-03 12:05:51 +02:00
set_state ( torrent_status : : downloading ) ;
2008-05-29 05:37:19 +02:00
set_queue_position ( ( std : : numeric_limits < int > : : max ) ( ) ) ;
2009-05-06 09:06:26 +02:00
m_policy . recalculate_connect_candidates ( ) ;
2009-11-24 19:49:59 +01:00
2010-03-09 04:21:35 +01:00
m_completed_time = 0 ;
2009-11-24 19:49:59 +01:00
send_upload_only ( ) ;
2008-05-20 05:21:45 +02:00
}
2005-06-11 01:12:50 +02:00
// called when torrent is complete (all pieces downloaded)
void torrent : : completed ( )
{
2008-05-29 05:37:19 +02:00
m_picker . reset ( ) ;
2008-07-03 12:05:51 +02:00
set_state ( torrent_status : : seeding ) ;
2008-11-29 09:38:40 +01:00
if ( ! m_announcing ) return ;
ptime now = time_now ( ) ;
for ( std : : vector < announce_entry > : : iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
{
if ( i - > complete_sent ) continue ;
i - > next_announce = now ;
2009-12-02 05:05:24 +01:00
i - > min_announce = now ;
2008-11-29 09:38:40 +01:00
}
announce_with_tracker ( ) ;
2003-10-23 01:00:57 +02:00
}
2004-09-12 12:12:16 +02:00
// this will move the tracker with the given index
// to a prioritized position in the list (move it towards
// the begining) and return the new index to the tracker.
int torrent : : prioritize_tracker ( int index )
{
2006-05-28 21:03:54 +02:00
INVARIANT_CHECK ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( index > = 0 ) ;
2009-06-10 10:42:05 +02:00
TORRENT_ASSERT ( index < int ( m_trackers . size ( ) ) ) ;
2008-11-27 21:48:29 +01:00
if ( index > = ( int ) m_trackers . size ( ) ) return - 1 ;
2004-09-12 12:12:16 +02:00
while ( index > 0 & & m_trackers [ index ] . tier = = m_trackers [ index - 1 ] . tier )
{
2008-11-29 09:38:40 +01:00
using std : : swap ;
swap ( m_trackers [ index ] , m_trackers [ index - 1 ] ) ;
2008-12-12 11:00:20 +01:00
if ( m_last_working_tracker = = index ) - - m_last_working_tracker ;
else if ( m_last_working_tracker = = index - 1 ) + + m_last_working_tracker ;
2004-09-12 12:12:16 +02:00
- - index ;
}
return index ;
}
2003-10-23 01:00:57 +02:00
2008-11-29 09:38:40 +01:00
int torrent : : deprioritize_tracker ( int index )
2003-10-23 01:00:57 +02:00
{
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2008-11-29 09:38:40 +01:00
TORRENT_ASSERT ( index > = 0 ) ;
2009-06-10 10:42:05 +02:00
TORRENT_ASSERT ( index < int ( m_trackers . size ( ) ) ) ;
2008-11-29 09:38:40 +01:00
if ( index > = ( int ) m_trackers . size ( ) ) return - 1 ;
2008-07-12 10:25:19 +02:00
2009-06-10 10:42:05 +02:00
while ( index < int ( m_trackers . size ( ) ) - 1 & & m_trackers [ index ] . tier = = m_trackers [ index + 1 ] . tier )
2003-10-23 01:00:57 +02:00
{
2008-11-29 09:38:40 +01:00
using std : : swap ;
swap ( m_trackers [ index ] , m_trackers [ index + 1 ] ) ;
2008-12-12 11:00:20 +01:00
if ( m_last_working_tracker = = index ) + + m_last_working_tracker ;
else if ( m_last_working_tracker = = index + 1 ) - - m_last_working_tracker ;
2008-11-29 09:38:40 +01:00
+ + index ;
2003-10-23 01:00:57 +02:00
}
2008-11-29 09:38:40 +01:00
return index ;
2003-10-23 01:00:57 +02:00
}
2010-07-14 06:16:38 +02:00
void torrent : : files_checked ( )
2009-05-23 23:36:09 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_torrent_file - > is_valid ( ) ) ;
2003-12-07 16:03:06 +01:00
2009-01-02 10:47:51 +01:00
if ( m_abort ) return ;
2008-10-05 03:44:57 +02:00
// we might be finished already, in which case we should
2009-02-03 08:46:24 +01:00
// not switch to downloading mode. If all files are
// filtered, we're finished when we start.
2008-10-05 03:44:57 +02:00
if ( m_state ! = torrent_status : : finished )
set_state ( torrent_status : : downloading ) ;
2008-03-08 07:06:31 +01:00
2009-02-09 03:04:43 +01:00
INVARIANT_CHECK ;
2008-08-18 22:02:50 +02:00
if ( m_ses . m_alerts . should_post < torrent_checked_alert > ( ) )
{
m_ses . m_alerts . post_alert ( torrent_checked_alert (
get_handle ( ) ) ) ;
}
2011-02-11 08:10:47 +01:00
// calling pause will also trigger the auto managed
// recalculation
if ( m_auto_managed ) pause ( ) ;
2011-01-30 14:15:29 +01:00
// if this is an auto managed torrent, force a recalculation
// of which torrents to have active
2011-12-23 18:16:14 +01:00
if ( m_auto_managed )
m_ses . m_auto_manage_time_scaler = 2 ;
2011-01-30 14:15:29 +01:00
2006-12-04 13:20:34 +01:00
if ( ! is_seed ( ) )
{
2008-12-08 07:36:22 +01:00
// turn off super seeding if we're not a seed
if ( m_super_seeding ) m_super_seeding = false ;
2011-12-23 21:40:13 +01:00
// if we just finished checking and we're not a seed, we are
// likely to be unpaused
m_ses . m_auto_manage_time_scaler = 2 ;
2009-02-03 08:46:24 +01:00
if ( is_finished ( ) & & m_state ! = torrent_status : : finished )
finished ( ) ;
2008-08-18 22:02:50 +02:00
}
else
{
2008-11-29 09:38:40 +01:00
for ( std : : vector < announce_entry > : : iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
i - > complete_sent = true ;
2009-02-03 08:46:24 +01:00
if ( m_state ! = torrent_status : : finished )
finished ( ) ;
2006-12-04 13:20:34 +01:00
}
2007-05-10 00:54:26 +02:00
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
2011-02-25 18:00:36 +01:00
TORRENT_TRY {
2008-02-14 04:48:20 +01:00
( * i ) - > on_files_checked ( ) ;
2011-02-25 18:00:36 +01:00
} TORRENT_CATCH ( std : : exception & ) { }
2007-05-10 00:54:26 +02:00
}
# endif
2005-10-16 11:15:46 +02:00
if ( ! m_connections_initialized )
{
m_connections_initialized = true ;
// all peer connections have to initialize themselves now that the metadata
// is available
2008-07-18 12:03:42 +02:00
for ( torrent : : peer_iterator i = m_connections . begin ( ) ;
i ! = m_connections . end ( ) ; )
2005-10-16 11:15:46 +02:00
{
2008-07-18 12:03:42 +02:00
peer_connection * pc = * i ;
2008-04-07 04:51:21 +02:00
+ + i ;
2008-08-29 19:21:56 +02:00
if ( pc - > is_disconnecting ( ) ) continue ;
pc - > on_metadata_impl ( ) ;
if ( pc - > is_disconnecting ( ) ) continue ;
2008-07-18 12:03:42 +02:00
pc - > init ( ) ;
2005-10-16 11:15:46 +02:00
}
}
2008-04-23 03:01:00 +02:00
2007-12-14 07:09:44 +01:00
m_files_checked = true ;
2008-07-12 10:25:19 +02:00
start_announcing ( ) ;
2003-11-07 02:44:30 +01:00
}
2004-01-07 01:48:02 +01:00
alert_manager & torrent : : alerts ( ) const
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2004-01-07 01:48:02 +01:00
return m_ses . m_alerts ;
}
2009-10-26 02:29:39 +01:00
std : : string torrent : : save_path ( ) const
2004-06-14 01:30:42 +02:00
{
2008-03-08 07:06:31 +01:00
return m_save_path ;
2004-06-14 01:30:42 +02:00
}
2008-05-28 10:44:40 +02:00
bool torrent : : rename_file ( int index , std : : string const & name )
{
INVARIANT_CHECK ;
TORRENT_ASSERT ( index > = 0 ) ;
TORRENT_ASSERT ( index < m_torrent_file - > num_files ( ) ) ;
if ( ! m_owning_storage . get ( ) ) return false ;
m_owning_storage - > async_rename_file ( index , name
2010-05-02 08:29:52 +02:00
, boost : : bind ( & torrent : : on_file_renamed , shared_from_this ( ) , _1 , _2 ) ) ;
2008-05-28 10:44:40 +02:00
return true ;
}
2009-10-26 02:29:39 +01:00
void torrent : : move_storage ( std : : string const & save_path )
2004-07-18 02:39:58 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-05-28 21:03:54 +02:00
INVARIANT_CHECK ;
2007-06-10 22:46:09 +02:00
if ( m_owning_storage . get ( ) )
2005-01-10 12:14:22 +01:00
{
2007-06-11 23:24:14 +02:00
m_owning_storage - > async_move_storage ( save_path
2010-05-02 08:29:52 +02:00
, boost : : bind ( & torrent : : on_storage_moved , shared_from_this ( ) , _1 , _2 ) ) ;
2005-01-10 12:14:22 +01:00
}
else
{
m_save_path = save_path ;
2009-05-11 23:18:09 +02:00
if ( alerts ( ) . should_post < storage_moved_alert > ( ) )
{
2009-10-26 02:29:39 +01:00
alerts ( ) . post_alert ( storage_moved_alert ( get_handle ( ) , m_save_path ) ) ;
2009-05-11 23:18:09 +02:00
}
2005-01-10 12:14:22 +01:00
}
2004-07-18 02:39:58 +02:00
}
2007-06-11 23:24:14 +02:00
void torrent : : on_storage_moved ( int ret , disk_io_job const & j )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-06-11 23:24:14 +02:00
2009-05-11 23:18:09 +02:00
if ( ret = = 0 )
{
if ( alerts ( ) . should_post < storage_moved_alert > ( ) )
{
alerts ( ) . post_alert ( storage_moved_alert ( get_handle ( ) , j . str ) ) ;
}
m_save_path = j . str ;
}
else
2007-06-11 23:24:14 +02:00
{
2009-05-11 23:18:09 +02:00
if ( alerts ( ) . should_post < storage_moved_failed_alert > ( ) )
{
alerts ( ) . post_alert ( storage_moved_failed_alert ( get_handle ( ) , j . error ) ) ;
}
2007-06-11 23:24:14 +02:00
}
}
2004-06-14 01:30:42 +02:00
piece_manager & torrent : : filesystem ( )
{
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_owning_storage . get ( ) ) ;
2008-06-22 22:28:03 +02:00
TORRENT_ASSERT ( m_storage ) ;
return * m_storage ;
2004-06-14 01:30:42 +02:00
}
2008-04-09 22:09:36 +02:00
torrent_handle torrent : : get_handle ( )
2004-01-07 01:48:02 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-04-09 22:09:36 +02:00
return torrent_handle ( shared_from_this ( ) ) ;
2004-01-07 01:48:02 +01:00
}
2006-05-15 00:30:05 +02:00
session_settings const & torrent : : settings ( ) const
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-10-11 16:02:21 +02:00
return m_ses . settings ( ) ;
2006-05-15 00:30:05 +02:00
}
2004-01-07 01:48:02 +01:00
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2004-06-14 01:30:42 +02:00
void torrent : : check_invariant ( ) const
2003-12-14 06:56:12 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-10-30 10:36:18 +02:00
if ( is_paused ( ) ) TORRENT_ASSERT ( num_peers ( ) = = 0 | | m_graceful_pause_mode ) ;
2008-09-26 00:08:18 +02:00
2008-11-19 01:46:48 +01:00
if ( ! should_check_files ( ) )
TORRENT_ASSERT ( m_state ! = torrent_status : : checking_files ) ;
2009-02-09 03:04:43 +01:00
else
TORRENT_ASSERT ( m_queued_for_checking ) ;
2008-11-19 01:46:48 +01:00
2008-08-10 11:34:39 +02:00
if ( ! m_ses . m_queued_for_checking . empty ( ) )
{
// if there are torrents waiting to be checked
// assert that there's a torrent that is being
// processed right now
2008-08-10 12:22:36 +02:00
int found = 0 ;
2008-11-18 12:01:30 +01:00
int found_active = 0 ;
2008-08-10 11:34:39 +02:00
for ( aux : : session_impl : : torrent_map : : iterator i = m_ses . m_torrents . begin ( )
, end ( m_ses . m_torrents . end ( ) ) ; i ! = end ; + + i )
2008-11-18 12:01:30 +01:00
if ( i - > second - > m_state = = torrent_status : : checking_files )
{
+ + found ;
if ( i - > second - > should_check_files ( ) ) + + found_active ;
}
2011-06-03 10:40:13 +02:00
// if the session is paused, there might still be some torrents
// in the checking_files state that haven't been dequeued yet
if ( m_ses . is_paused ( ) )
{
TORRENT_ASSERT ( found_active = = 0 ) ;
}
else
{
// the case of 2 is in the special case where one switches over from
// checking to complete.
TORRENT_ASSERT ( found_active > = 1 ) ;
TORRENT_ASSERT ( found_active < = 2 ) ;
TORRENT_ASSERT ( found > = 1 ) ;
}
2008-08-10 11:34:39 +02:00
}
2008-07-01 01:14:31 +02:00
TORRENT_ASSERT ( m_resume_entry . type ( ) = = lazy_entry : : dict_t
| | m_resume_entry . type ( ) = = lazy_entry : : none_t ) ;
2008-04-13 00:08:07 +02:00
2007-08-17 09:37:08 +02:00
int num_uploads = 0 ;
2007-07-08 22:45:42 +02:00
std : : map < piece_block , int > num_requests ;
2006-04-25 23:04:48 +02:00
for ( const_peer_iterator i = begin ( ) ; i ! = end ( ) ; + + i )
2006-05-28 21:03:54 +02:00
{
2008-07-12 19:51:59 +02:00
# ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
2008-01-07 02:10:46 +01:00
// make sure this peer is not a dangling pointer
TORRENT_ASSERT ( m_ses . has_peer ( * i ) ) ;
2008-07-12 19:51:59 +02:00
# endif
2007-10-31 10:48:20 +01:00
peer_connection const & p = * ( * i ) ;
2009-12-25 17:52:57 +01:00
for ( std : : vector < pending_block > : : const_iterator i = p . request_queue ( ) . begin ( )
2007-07-08 22:45:42 +02:00
, end ( p . request_queue ( ) . end ( ) ) ; i ! = end ; + + i )
2009-12-25 17:52:57 +01:00
+ + num_requests [ i - > block ] ;
2009-03-17 10:34:44 +01:00
for ( std : : vector < pending_block > : : const_iterator i = p . download_queue ( ) . begin ( )
2007-07-08 22:45:42 +02:00
, end ( p . download_queue ( ) . end ( ) ) ; i ! = end ; + + i )
2009-03-17 10:34:44 +01:00
if ( ! i - > not_wanted & & ! i - > timed_out ) + + num_requests [ i - > block ] ;
2009-01-28 07:14:21 +01:00
if ( ! p . is_choked ( ) & & ! p . ignore_unchoke_slots ( ) ) + + num_uploads ;
2006-05-28 21:03:54 +02:00
torrent * associated_torrent = p . associated_torrent ( ) . lock ( ) . get ( ) ;
2010-09-05 18:01:36 +02:00
if ( associated_torrent ! = this & & associated_torrent ! = 0 )
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( false ) ;
2006-05-28 21:03:54 +02:00
}
2011-02-21 06:24:41 +01:00
TORRENT_ASSERT ( num_uploads = = int ( m_num_uploads ) ) ;
2006-04-25 23:04:48 +02:00
2007-07-08 22:45:42 +02:00
if ( has_picker ( ) )
{
for ( std : : map < piece_block , int > : : iterator i = num_requests . begin ( )
, end ( num_requests . end ( ) ) ; i ! = end ; + + i )
{
2009-03-17 10:34:44 +01:00
piece_block b = i - > first ;
int count = i - > second ;
int picker_count = m_picker - > num_peers ( b ) ;
if ( ! m_picker - > is_downloaded ( b ) )
TORRENT_ASSERT ( picker_count = = count ) ;
2007-07-08 22:45:42 +02:00
}
2008-06-07 16:03:21 +02:00
TORRENT_ASSERT ( num_have ( ) > = m_picker - > num_have_filtered ( ) ) ;
2007-07-08 22:45:42 +02:00
}
2006-12-11 13:48:33 +01:00
if ( valid_metadata ( ) )
{
2010-02-22 02:51:25 +01:00
TORRENT_ASSERT ( m_abort | | m_error | | ! m_picker | | m_picker - > num_pieces ( ) = = m_torrent_file - > num_pieces ( ) ) ;
2006-12-11 13:48:33 +01:00
}
else
{
2010-02-22 02:51:25 +01:00
TORRENT_ASSERT ( m_abort | | m_error | | ! m_picker | | m_picker - > num_pieces ( ) = = 0 ) ;
2006-12-11 13:48:33 +01:00
}
2008-07-12 19:51:59 +02:00
# ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
2009-04-30 07:49:46 +02:00
// make sure we haven't modified the peer object
// in a way that breaks the sort order
if ( m_policy . begin_peer ( ) ! = m_policy . end_peer ( ) )
{
policy : : const_iterator i = m_policy . begin_peer ( ) ;
policy : : const_iterator prev = i + + ;
policy : : const_iterator end ( m_policy . end_peer ( ) ) ;
2009-05-25 19:23:03 +02:00
policy : : peer_address_compare cmp ;
2009-04-30 07:49:46 +02:00
for ( ; i ! = end ; + + i , + + prev )
{
2009-05-07 00:36:24 +02:00
TORRENT_ASSERT ( ! cmp ( * i , * prev ) ) ;
2009-04-30 07:49:46 +02:00
}
2007-09-19 08:05:14 +02:00
}
2008-07-12 19:51:59 +02:00
# endif
2007-10-31 10:48:20 +01:00
2006-12-11 13:48:33 +01:00
size_type total_done = quantized_bytes_done ( ) ;
2007-09-01 05:00:31 +02:00
if ( m_torrent_file - > is_valid ( ) )
2007-02-15 04:03:50 +01:00
{
if ( is_seed ( ) )
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( total_done = = m_torrent_file - > total_size ( ) ) ;
2007-02-15 04:03:50 +01:00
else
2008-06-07 04:58:28 +02:00
TORRENT_ASSERT ( total_done ! = m_torrent_file - > total_size ( ) | | ! m_files_checked ) ;
2008-06-18 14:34:39 +02:00
2010-02-14 02:39:55 +01:00
TORRENT_ASSERT ( block_size ( ) < = m_torrent_file - > piece_length ( ) ) ;
2007-02-15 04:03:50 +01:00
}
2006-12-11 13:48:33 +01:00
else
2007-02-15 04:03:50 +01:00
{
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( total_done = = 0 ) ;
2007-02-15 04:03:50 +01:00
}
2006-12-11 13:48:33 +01:00
2007-10-18 06:18:09 +02:00
if ( m_picker & & ! m_abort )
2007-10-18 02:32:16 +02:00
{
// make sure that pieces that have completed the download
// of all their blocks are in the disk io thread's queue
// to be checked.
const std : : vector < piece_picker : : downloading_piece > & dl_queue
= m_picker - > get_download_queue ( ) ;
for ( std : : vector < piece_picker : : downloading_piece > : : const_iterator i =
dl_queue . begin ( ) ; i ! = dl_queue . end ( ) ; + + i )
{
const int blocks_per_piece = m_picker - > blocks_in_piece ( i - > index ) ;
bool complete = true ;
for ( int j = 0 ; j < blocks_per_piece ; + + j )
{
if ( i - > info [ j ] . state = = piece_picker : : block_info : : state_finished )
continue ;
complete = false ;
break ;
}
}
}
2010-02-22 02:51:25 +01:00
if ( m_files_checked & & valid_metadata ( ) )
2009-02-03 08:46:24 +01:00
{
2010-02-14 02:39:55 +01:00
TORRENT_ASSERT ( block_size ( ) > 0 ) ;
2009-02-03 08:46:24 +01:00
}
2007-10-05 02:30:00 +02:00
// if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0);
2009-07-04 06:58:24 +02:00
for ( std : : vector < size_type > : : const_iterator i = m_file_progress . begin ( )
, end ( m_file_progress . end ( ) ) ; i ! = end ; + + i )
{
int index = i - m_file_progress . begin ( ) ;
TORRENT_ASSERT ( * i < = m_torrent_file - > files ( ) . at ( index ) . size ) ;
}
2003-12-14 06:56:12 +01:00
}
# endif
2008-01-31 18:52:29 +01:00
void torrent : : set_sequential_download ( bool sd )
2010-07-14 06:16:38 +02:00
{
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2011-11-15 03:34:00 +01:00
if ( m_sequential_download = = sd ) return ;
2010-07-14 06:16:38 +02:00
m_sequential_download = sd ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2010-07-14 06:16:38 +02:00
}
void torrent : : queue_up ( )
{
set_queue_position ( queue_position ( ) = = 0
? queue_position ( ) : queue_position ( ) - 1 ) ;
}
void torrent : : queue_down ( )
{
set_queue_position ( queue_position ( ) + 1 ) ;
}
2006-09-04 19:17:45 +02:00
2008-05-29 05:37:19 +02:00
void torrent : : set_queue_position ( int p )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-06-17 18:49:55 +02:00
TORRENT_ASSERT ( ( p = = - 1 ) = = is_finished ( )
| | ( ! m_auto_managed & & p = = - 1 )
| | ( m_abort & & p = = - 1 ) ) ;
2008-06-08 15:47:35 +02:00
if ( is_finished ( ) & & p ! = - 1 ) return ;
2008-05-29 05:37:19 +02:00
if ( p = = m_sequence_number ) return ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2008-05-29 05:37:19 +02:00
session_impl : : torrent_map & torrents = m_ses . m_torrents ;
2008-06-17 00:27:14 +02:00
if ( p > = 0 & & m_sequence_number = = - 1 )
{
2008-06-21 17:51:03 +02:00
int max_seq = - 1 ;
2008-06-17 00:27:14 +02:00
for ( session_impl : : torrent_map : : iterator i = torrents . begin ( )
, end ( torrents . end ( ) ) ; i ! = end ; + + i )
{
torrent * t = i - > second . get ( ) ;
if ( t - > m_sequence_number > max_seq ) max_seq = t - > m_sequence_number ;
2011-10-15 09:11:50 +02:00
if ( t - > m_sequence_number > = p ) + + t - > m_sequence_number ;
2008-06-17 00:27:14 +02:00
}
m_sequence_number = ( std : : min ) ( max_seq + 1 , p ) ;
}
else if ( p < 0 )
2008-05-29 05:37:19 +02:00
{
for ( session_impl : : torrent_map : : iterator i = torrents . begin ( )
, end ( torrents . end ( ) ) ; i ! = end ; + + i )
{
torrent * t = i - > second . get ( ) ;
if ( t = = this ) continue ;
if ( t - > m_sequence_number > = m_sequence_number
& & t - > m_sequence_number ! = - 1 )
- - t - > m_sequence_number ;
}
m_sequence_number = p ;
}
else if ( p < m_sequence_number )
{
for ( session_impl : : torrent_map : : iterator i = torrents . begin ( )
, end ( torrents . end ( ) ) ; i ! = end ; + + i )
{
torrent * t = i - > second . get ( ) ;
if ( t = = this ) continue ;
2008-06-11 14:14:10 +02:00
if ( t - > m_sequence_number > = p
& & t - > m_sequence_number < m_sequence_number
2008-05-29 05:37:19 +02:00
& & t - > m_sequence_number ! = - 1 )
+ + t - > m_sequence_number ;
}
m_sequence_number = p ;
}
else if ( p > m_sequence_number )
{
int max_seq = 0 ;
for ( session_impl : : torrent_map : : iterator i = torrents . begin ( )
, end ( torrents . end ( ) ) ; i ! = end ; + + i )
{
torrent * t = i - > second . get ( ) ;
int pos = t - > m_sequence_number ;
2008-06-11 14:14:10 +02:00
if ( pos > max_seq ) max_seq = pos ;
if ( t = = this ) continue ;
2008-05-29 05:37:19 +02:00
if ( pos < = p
2008-06-17 00:27:14 +02:00
& & pos > m_sequence_number
& & pos ! = - 1 )
2008-05-29 05:37:19 +02:00
- - t - > m_sequence_number ;
2008-06-11 14:14:10 +02:00
2008-05-29 05:37:19 +02:00
}
2008-06-11 14:14:10 +02:00
m_sequence_number = ( std : : min ) ( max_seq , p ) ;
2008-05-29 05:37:19 +02:00
}
2008-06-03 22:21:47 +02:00
2011-12-23 18:16:14 +01:00
m_ses . m_auto_manage_time_scaler = 2 ;
2008-05-29 05:37:19 +02:00
}
2006-09-04 19:17:45 +02:00
2004-10-29 15:21:09 +02:00
void torrent : : set_max_uploads ( int limit )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( limit > = - 1 ) ;
2007-08-21 06:46:17 +02:00
if ( limit < = 0 ) limit = ( std : : numeric_limits < int > : : max ) ( ) ;
2011-11-15 03:34:00 +01:00
if ( m_max_uploads ! = limit ) state_updated ( ) ;
2007-08-16 14:41:46 +02:00
m_max_uploads = limit ;
2004-10-29 15:21:09 +02:00
}
void torrent : : set_max_connections ( int limit )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( limit > = - 1 ) ;
2007-08-21 06:46:17 +02:00
if ( limit < = 0 ) limit = ( std : : numeric_limits < int > : : max ) ( ) ;
2011-11-15 03:34:00 +01:00
if ( m_max_connections ! = limit ) state_updated ( ) ;
2007-08-16 14:41:46 +02:00
m_max_connections = limit ;
2010-10-03 12:07:38 +02:00
2011-02-21 06:24:41 +01:00
if ( num_peers ( ) > int ( m_max_connections ) )
2010-10-03 12:07:38 +02:00
{
disconnect_peers ( num_peers ( ) - m_max_connections
, error_code ( errors : : too_many_connections , get_libtorrent_category ( ) ) ) ;
}
2004-10-29 15:21:09 +02:00
}
2010-10-01 18:09:22 +02:00
int torrent : : get_peer_upload_limit ( tcp : : endpoint ip ) const
{
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-10-12 11:01:51 +02:00
const_peer_iterator i = std : : find_if ( m_connections . begin ( ) , m_connections . end ( )
2010-10-01 18:09:22 +02:00
, boost : : bind ( & peer_connection : : remote , _1 ) = = ip ) ;
if ( i = = m_connections . end ( ) ) return - 1 ;
return ( * i ) - > get_upload_limit ( ) ;
}
int torrent : : get_peer_download_limit ( tcp : : endpoint ip ) const
{
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-10-12 11:01:51 +02:00
const_peer_iterator i = std : : find_if ( m_connections . begin ( ) , m_connections . end ( )
2010-10-01 18:09:22 +02:00
, boost : : bind ( & peer_connection : : remote , _1 ) = = ip ) ;
if ( i = = m_connections . end ( ) ) return - 1 ;
return ( * i ) - > get_download_limit ( ) ;
}
2006-04-25 23:04:48 +02:00
void torrent : : set_peer_upload_limit ( tcp : : endpoint ip , int limit )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( limit > = - 1 ) ;
2007-10-31 10:48:20 +01:00
peer_iterator i = std : : find_if ( m_connections . begin ( ) , m_connections . end ( )
2010-05-02 08:29:52 +02:00
, boost : : bind ( & peer_connection : : remote , _1 ) = = ip ) ;
2007-10-31 10:48:20 +01:00
if ( i = = m_connections . end ( ) ) return ;
( * i ) - > set_upload_limit ( limit ) ;
2006-04-25 23:04:48 +02:00
}
void torrent : : set_peer_download_limit ( tcp : : endpoint ip , int limit )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( limit > = - 1 ) ;
2007-10-31 10:48:20 +01:00
peer_iterator i = std : : find_if ( m_connections . begin ( ) , m_connections . end ( )
2010-05-02 08:29:52 +02:00
, boost : : bind ( & peer_connection : : remote , _1 ) = = ip ) ;
2007-10-31 10:48:20 +01:00
if ( i = = m_connections . end ( ) ) return ;
( * i ) - > set_download_limit ( limit ) ;
2006-04-25 23:04:48 +02:00
}
2004-07-24 13:54:17 +02:00
void torrent : : set_upload_limit ( int limit )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( limit > = - 1 ) ;
2009-04-26 02:21:59 +02:00
if ( limit < = 0 ) limit = 0 ;
2011-11-15 03:34:00 +01:00
if ( m_bandwidth_channel [ peer_connection : : upload_channel ] . throttle ( ) ! = limit )
state_updated ( ) ;
2009-04-26 02:21:59 +02:00
m_bandwidth_channel [ peer_connection : : upload_channel ] . throttle ( limit ) ;
2004-07-24 13:54:17 +02:00
}
2007-04-10 11:25:17 +02:00
int torrent : : upload_limit ( ) const
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-04-26 02:21:59 +02:00
int limit = m_bandwidth_channel [ peer_connection : : upload_channel ] . throttle ( ) ;
2007-08-21 06:46:17 +02:00
if ( limit = = ( std : : numeric_limits < int > : : max ) ( ) ) limit = - 1 ;
2007-04-10 11:25:17 +02:00
return limit ;
}
2004-07-24 13:54:17 +02:00
void torrent : : set_download_limit ( int limit )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( limit > = - 1 ) ;
2009-04-26 02:21:59 +02:00
if ( limit < = 0 ) limit = 0 ;
2011-11-15 03:34:00 +01:00
if ( m_bandwidth_channel [ peer_connection : : download_channel ] . throttle ( ) ! = limit )
state_updated ( ) ;
2009-04-26 02:21:59 +02:00
m_bandwidth_channel [ peer_connection : : download_channel ] . throttle ( limit ) ;
2004-07-24 13:54:17 +02:00
}
2007-04-10 11:25:17 +02:00
int torrent : : download_limit ( ) const
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-04-26 02:21:59 +02:00
int limit = m_bandwidth_channel [ peer_connection : : download_channel ] . throttle ( ) ;
2007-08-21 06:46:17 +02:00
if ( limit = = ( std : : numeric_limits < int > : : max ) ( ) ) limit = - 1 ;
2007-04-10 11:25:17 +02:00
return limit ;
}
2007-10-13 05:33:33 +02:00
void torrent : : delete_files ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-08-18 19:14:40 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING
log_to_all_peers ( " DELETING FILES IN TORRENT " ) ;
2007-10-13 05:33:33 +02:00
# endif
2009-11-29 08:06:38 +01:00
disconnect_all ( errors : : torrent_removed ) ;
2008-07-12 10:25:19 +02:00
stop_announcing ( ) ;
2007-10-13 05:33:33 +02:00
if ( m_owning_storage . get ( ) )
{
TORRENT_ASSERT ( m_storage ) ;
m_storage - > async_delete_files (
2010-05-02 08:29:52 +02:00
boost : : bind ( & torrent : : on_files_deleted , shared_from_this ( ) , _1 , _2 ) ) ;
2007-10-13 05:33:33 +02:00
}
}
2008-07-12 19:00:52 +02:00
void torrent : : clear_error ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-02-23 02:21:19 +01:00
if ( ! m_error ) return ;
2008-11-19 01:46:48 +01:00
bool checking_files = should_check_files ( ) ;
2011-12-23 18:16:14 +01:00
m_ses . m_auto_manage_time_scaler = 2 ;
2009-02-23 02:21:19 +01:00
m_error = error_code ( ) ;
m_error_file . clear ( ) ;
2010-12-30 02:47:30 +01:00
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2010-12-30 02:47:30 +01:00
// if we haven't downloaded the metadata from m_url, try again
if ( ! m_url . empty ( ) & & ! m_torrent_file - > is_valid ( ) )
{
start_download_url ( ) ;
return ;
}
2010-02-22 02:51:25 +01:00
// if the error happened during initialization, try again now
if ( ! m_storage ) init ( ) ;
2008-11-19 01:46:48 +01:00
if ( ! checking_files & & should_check_files ( ) )
2009-02-08 02:29:09 +01:00
queue_torrent_check ( ) ;
2010-12-30 02:47:30 +01:00
2008-07-12 19:00:52 +02:00
}
2009-02-23 02:21:19 +01:00
void torrent : : set_error ( error_code const & ec , std : : string const & error_file )
2009-01-27 10:18:51 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-01-27 10:18:51 +01:00
bool checking_files = should_check_files ( ) ;
2009-02-23 02:21:19 +01:00
m_error = ec ;
m_error_file = error_file ;
2010-08-18 19:14:40 +02:00
2011-01-22 20:06:43 +01:00
if ( alerts ( ) . should_post < torrent_error_alert > ( ) )
alerts ( ) . post_alert ( torrent_error_alert ( get_handle ( ) , ec ) ) ;
2010-08-18 19:14:40 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING
if ( ec )
{
char buf [ 1024 ] ;
snprintf ( buf , sizeof ( buf ) , " TORRENT ERROR: %s: %s " , ec . message ( ) . c_str ( ) , error_file . c_str ( ) ) ;
log_to_all_peers ( buf ) ;
}
# endif
2009-01-27 10:18:51 +01:00
if ( checking_files & & ! should_check_files ( ) )
{
// stop checking
m_storage - > abort_disk_io ( ) ;
2009-02-08 02:29:09 +01:00
dequeue_torrent_check ( ) ;
2009-01-27 10:18:51 +01:00
set_state ( torrent_status : : queued_for_checking ) ;
}
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2009-01-27 10:18:51 +01:00
}
2008-04-24 05:28:48 +02:00
void torrent : : auto_managed ( bool a )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-04-24 05:28:48 +02:00
INVARIANT_CHECK ;
if ( m_auto_managed = = a ) return ;
2008-09-20 19:42:25 +02:00
bool checking_files = should_check_files ( ) ;
2008-04-24 05:28:48 +02:00
m_auto_managed = a ;
2011-06-05 22:48:00 +02:00
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2011-06-05 22:48:00 +02:00
// we need to save this new state as well
m_need_save_resume_data = true ;
2008-04-24 05:28:48 +02:00
// recalculate which torrents should be
// paused
2011-12-23 18:16:14 +01:00
m_ses . m_auto_manage_time_scaler = 2 ;
2008-09-20 19:42:25 +02:00
if ( ! checking_files & & should_check_files ( ) )
2009-02-08 02:29:09 +01:00
{
queue_torrent_check ( ) ;
}
2008-09-20 19:42:25 +02:00
else if ( checking_files & & ! should_check_files ( ) )
{
2008-11-18 12:01:30 +01:00
// stop checking
m_storage - > abort_disk_io ( ) ;
2009-02-08 02:29:09 +01:00
dequeue_torrent_check ( ) ;
2008-11-19 01:46:48 +01:00
set_state ( torrent_status : : queued_for_checking ) ;
2008-09-20 19:42:25 +02:00
}
2011-01-30 14:15:29 +01:00
// if this torrent is running and just became auto-managed
// we might want to pause it in favor of some other torrent
2011-12-23 18:16:14 +01:00
if ( m_auto_managed & & ! is_paused ( ) )
m_ses . m_auto_manage_time_scaler = 2 ;
2008-04-24 05:28:48 +02:00
}
2008-05-06 20:03:41 +02:00
// the higher seed rank, the more important to seed
int torrent : : seed_rank ( session_settings const & s ) const
2008-04-24 05:28:48 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-05-06 20:03:41 +02:00
enum flags
{
seed_ratio_not_met = 0x400000 ,
recently_started = 0x200000 ,
no_seeds = 0x100000 ,
prio_mask = 0xfffff
} ;
2008-04-24 05:28:48 +02:00
2008-10-19 10:05:36 +02:00
if ( ! is_finished ( ) ) return 0 ;
int scale = 100 ;
if ( ! is_seed ( ) ) scale = 50 ;
2008-04-24 05:28:48 +02:00
2008-05-06 20:03:41 +02:00
int ret = 0 ;
2008-04-24 05:28:48 +02:00
2009-05-25 04:45:51 +02:00
ptime now = time_now ( ) ;
2008-04-24 05:28:48 +02:00
2010-02-14 02:39:55 +01:00
int finished_time = m_finished_time ;
int download_time = int ( m_active_time ) - finished_time ;
2008-05-06 20:03:41 +02:00
// if we haven't yet met the seed limits, set the seed_ratio_not_met
// flag. That will make this seed prioritized
2009-01-19 11:05:48 +01:00
// downloaded may be 0 if the torrent is 0-sized
2008-04-24 05:28:48 +02:00
size_type downloaded = ( std : : max ) ( m_total_downloaded , m_torrent_file - > total_size ( ) ) ;
2009-09-30 19:21:59 +02:00
if ( finished_time < s . seed_time_limit
& & ( download_time > 1 & & finished_time / download_time < s . seed_time_ratio_limit )
2009-01-19 11:05:48 +01:00
& & downloaded > 0
2008-05-07 19:05:16 +02:00
& & m_total_uploaded / downloaded < s . share_ratio_limit )
2008-05-06 20:03:41 +02:00
ret | = seed_ratio_not_met ;
// if this torrent is running, and it was started less
// than 30 minutes ago, give it priority, to avoid oscillation
if ( ! is_paused ( ) & & now - m_started < minutes ( 30 ) )
ret | = recently_started ;
// if we have any scrape data, use it to calculate
// seed rank
int seeds = 0 ;
int downloaders = 0 ;
2010-09-06 06:02:15 +02:00
if ( m_complete ! = 0xffffff ) seeds = m_complete ;
2008-05-06 20:03:41 +02:00
else seeds = m_policy . num_seeds ( ) ;
2010-09-06 06:02:15 +02:00
if ( m_downloaders ! = 0xffffff ) downloaders = m_downloaders ;
else if ( m_incomplete ! = 0xffffff ) downloaders = m_incomplete ;
2008-05-06 20:03:41 +02:00
else downloaders = m_policy . num_peers ( ) - m_policy . num_seeds ( ) ;
if ( seeds = = 0 )
{
ret | = no_seeds ;
ret | = downloaders & prio_mask ;
}
else
{
2008-10-19 10:05:36 +02:00
ret | = ( downloaders * scale / seeds ) & prio_mask ;
2008-05-06 20:03:41 +02:00
}
2008-04-24 05:28:48 +02:00
return ret ;
}
2008-04-13 20:54:36 +02:00
// this is an async operation triggered by the client
2010-10-29 04:21:43 +02:00
void torrent : : save_resume_data ( int flags )
2008-04-13 20:54:36 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-04-13 20:54:36 +02:00
INVARIANT_CHECK ;
2011-03-04 07:17:55 +01:00
if ( ! valid_metadata ( ) )
{
alerts ( ) . post_alert ( save_resume_data_failed_alert ( get_handle ( )
, errors : : no_metadata ) ) ;
return ;
}
2008-10-17 03:56:36 +02:00
if ( ! m_owning_storage . get ( ) )
2008-04-13 20:54:36 +02:00
{
2009-09-23 20:44:21 +02:00
alerts ( ) . post_alert ( save_resume_data_failed_alert ( get_handle ( )
2009-11-29 08:06:38 +01:00
, errors : : destructing_torrent ) ) ;
2008-10-17 03:56:36 +02:00
return ;
2008-04-13 20:54:36 +02:00
}
2008-10-17 03:56:36 +02:00
2010-04-12 02:36:31 +02:00
m_need_save_resume_data = false ;
2010-08-25 08:38:04 +02:00
m_last_saved_resume = time ( 0 ) ;
2011-02-26 08:48:05 +01:00
m_save_resume_flags = boost : : uint8_t ( flags ) ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2010-04-12 02:36:31 +02:00
2008-10-17 03:56:36 +02:00
TORRENT_ASSERT ( m_storage ) ;
if ( m_state = = torrent_status : : queued_for_checking
2008-11-19 01:46:48 +01:00
| | m_state = = torrent_status : : checking_files
| | m_state = = torrent_status : : checking_resume_data )
2008-04-13 20:54:36 +02:00
{
2009-09-23 20:44:21 +02:00
boost : : shared_ptr < entry > rd ( new entry ) ;
write_resume_data ( * rd ) ;
alerts ( ) . post_alert ( save_resume_data_alert ( rd
, get_handle ( ) ) ) ;
2008-10-17 03:56:36 +02:00
return ;
2008-04-13 20:54:36 +02:00
}
2010-10-29 04:21:43 +02:00
if ( flags & torrent_handle : : flush_disk_cache )
m_storage - > async_release_files ( ) ;
2008-10-17 03:56:36 +02:00
m_storage - > async_save_resume_data (
2010-05-02 08:29:52 +02:00
boost : : bind ( & torrent : : on_save_resume_data , shared_from_this ( ) , _1 , _2 ) ) ;
2008-04-13 20:54:36 +02:00
}
2008-09-20 19:42:25 +02:00
bool torrent : : should_check_files ( ) const
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-03-29 02:34:04 +02:00
// #error should m_allow_peers really affect checking?
2008-11-18 12:01:30 +01:00
return ( m_state = = torrent_status : : checking_files
| | m_state = = torrent_status : : queued_for_checking )
2010-04-15 16:31:49 +02:00
& & ( m_allow_peers | | m_auto_managed )
2009-02-23 02:21:19 +01:00
& & ! has_error ( )
2010-10-30 10:36:18 +02:00
& & ! m_abort
2011-01-23 19:00:52 +01:00
& & ! m_graceful_pause_mode
& & ! m_ses . is_paused ( ) ;
2008-09-20 19:42:25 +02:00
}
2010-01-09 22:17:52 +01:00
void torrent : : flush_cache ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-01-09 22:17:52 +01:00
m_storage - > async_release_files (
2010-05-02 08:29:52 +02:00
boost : : bind ( & torrent : : on_cache_flushed , shared_from_this ( ) , _1 , _2 ) ) ;
2010-01-09 22:17:52 +01:00
}
void torrent : : on_cache_flushed ( int ret , disk_io_job const & j )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2011-04-19 10:21:09 +02:00
if ( m_ses . is_aborted ( ) ) return ;
2010-01-09 22:17:52 +01:00
if ( alerts ( ) . should_post < cache_flushed_alert > ( ) )
alerts ( ) . post_alert ( cache_flushed_alert ( get_handle ( ) ) ) ;
}
2008-06-29 21:08:30 +02:00
bool torrent : : is_paused ( ) const
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-10-30 10:36:18 +02:00
return ! m_allow_peers | | m_ses . is_paused ( ) | | m_graceful_pause_mode ;
2008-06-29 21:08:30 +02:00
}
2010-10-30 10:36:18 +02:00
void torrent : : pause ( bool graceful )
2004-03-21 03:03:37 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2010-03-29 02:34:04 +02:00
if ( ! m_allow_peers ) return ;
2010-10-30 10:36:18 +02:00
if ( ! graceful ) m_allow_peers = false ;
2010-03-29 02:34:04 +02:00
m_announce_to_dht = false ;
m_announce_to_trackers = false ;
m_announce_to_lsd = false ;
2010-10-30 10:36:18 +02:00
2011-06-05 22:48:00 +02:00
// we need to save this new state
m_need_save_resume_data = true ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2011-06-05 22:48:00 +02:00
2010-11-07 10:39:35 +01:00
bool prev_graceful = m_graceful_pause_mode ;
2010-10-30 10:36:18 +02:00
m_graceful_pause_mode = graceful ;
2010-11-07 10:39:35 +01:00
if ( ! m_ses . is_paused ( ) | | ( prev_graceful & & ! m_graceful_pause_mode ) )
2009-02-09 03:04:43 +01:00
do_pause ( ) ;
2008-06-29 21:08:30 +02:00
}
void torrent : : do_pause ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-06-29 21:08:30 +02:00
if ( ! is_paused ( ) ) return ;
2006-11-14 01:08:16 +01:00
2011-09-05 07:50:41 +02:00
# ifdef TORRENT_USE_OPENSSL
if ( m_torrent_file - > is_valid ( ) & & m_torrent_file - > encryption_key ( ) . size ( ) = = 32 & & m_in_encrypted_list )
{
m_ses . m_encrypted_torrents . erase ( shared_from_this ( ) ) ;
m_in_encrypted_list = false ;
}
# endif
2006-11-14 01:08:16 +01:00
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
2011-02-25 18:00:36 +01:00
TORRENT_TRY {
2008-04-07 04:51:21 +02:00
if ( ( * i ) - > on_pause ( ) ) return ;
2011-02-25 18:00:36 +01:00
} TORRENT_CATCH ( std : : exception & ) { }
2006-11-14 01:08:16 +01:00
}
# endif
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2010-08-18 19:14:40 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING
log_to_all_peers ( " PAUSING TORRENT " ) ;
2007-08-16 14:41:46 +02:00
# endif
2005-03-05 15:17:17 +01:00
// this will make the storage close all
// files and flush all cached data
2007-06-10 22:46:09 +02:00
if ( m_owning_storage . get ( ) )
{
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_storage ) ;
2007-06-11 23:24:14 +02:00
m_storage - > async_release_files (
2010-05-02 08:29:52 +02:00
boost : : bind ( & torrent : : on_torrent_paused , shared_from_this ( ) , _1 , _2 ) ) ;
2008-07-18 17:31:22 +02:00
m_storage - > async_clear_read_cache ( ) ;
2007-06-10 22:46:09 +02:00
}
2008-03-30 17:44:31 +02:00
else
{
2008-07-06 14:22:56 +02:00
if ( alerts ( ) . should_post < torrent_paused_alert > ( ) )
alerts ( ) . post_alert ( torrent_paused_alert ( get_handle ( ) ) ) ;
2008-03-30 17:44:31 +02:00
}
2008-07-12 10:25:19 +02:00
2010-10-30 10:36:18 +02:00
if ( ! m_graceful_pause_mode )
{
disconnect_all ( errors : : torrent_paused ) ;
}
else
{
// disconnect all peers with no outstanding data to receive
// and choke all remaining peers to prevent responding to new
// requests
for ( std : : set < peer_connection * > : : iterator i = m_connections . begin ( )
, end ( m_connections . end ( ) ) ; i ! = end ; )
{
std : : set < peer_connection * > : : iterator j = i + + ;
peer_connection * p = * j ;
TORRENT_ASSERT ( p - > associated_torrent ( ) . lock ( ) . get ( ) = = this ) ;
if ( p - > is_disconnecting ( ) )
m_connections . erase ( j ) ;
if ( p - > outstanding_bytes ( ) > 0 )
{
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2011-08-13 20:46:52 +02:00
p - > peer_log ( " *** CHOKING PEER: torrent graceful paused " ) ;
2010-10-30 10:36:18 +02:00
# endif
// remove any un-sent requests from the queue
p - > clear_request_queue ( ) ;
// don't accept new requests from the peer
if ( ! p - > is_choked ( ) ) m_ses . choke_peer ( * p ) ;
continue ;
}
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2011-08-13 20:46:52 +02:00
p - > peer_log ( " *** CLOSING CONNECTION: torrent_paused " ) ;
2010-10-30 10:36:18 +02:00
# endif
p - > disconnect ( errors : : torrent_paused ) ;
}
}
2008-07-12 10:25:19 +02:00
stop_announcing ( ) ;
2011-01-23 19:00:52 +01:00
if ( m_queued_for_checking & & ! should_check_files ( ) )
{
// stop checking
m_storage - > abort_disk_io ( ) ;
dequeue_torrent_check ( ) ;
set_state ( torrent_status : : queued_for_checking ) ;
2011-06-03 10:40:13 +02:00
TORRENT_ASSERT ( ! m_queued_for_checking ) ;
2011-01-23 19:00:52 +01:00
}
2011-01-30 14:15:29 +01:00
// if this torrent was just paused
// we might have to resume some other auto-managed torrent
2011-12-23 18:16:14 +01:00
m_ses . m_auto_manage_time_scaler = 2 ;
2004-03-21 03:03:37 +01:00
}
2010-08-18 19:14:40 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING
void torrent : : log_to_all_peers ( char const * message )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-09-22 18:59:28 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2010-08-18 19:14:40 +02:00
for ( peer_iterator i = m_connections . begin ( ) ;
i ! = m_connections . end ( ) ; + + i )
{
2011-08-13 20:46:52 +02:00
( * i ) - > peer_log ( " *** %s " , message ) ;
2010-08-18 19:14:40 +02:00
}
2010-09-22 18:59:28 +02:00
# endif
( * m_ses . m_logger ) < < time_now_string ( ) < < " " < < message < < " \n " ;
2010-08-18 19:14:40 +02:00
}
# endif
2010-10-30 10:36:18 +02:00
void torrent : : set_allow_peers ( bool b , bool graceful )
2010-03-31 04:40:00 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-10-30 10:36:18 +02:00
if ( m_allow_peers = = b
& & m_graceful_pause_mode = = graceful ) return ;
2010-03-31 04:40:00 +02:00
m_allow_peers = b ;
2010-11-07 10:39:35 +01:00
if ( ! m_ses . is_paused ( ) )
m_graceful_pause_mode = graceful ;
2010-03-31 04:40:00 +02:00
if ( ! b )
{
m_announce_to_dht = false ;
m_announce_to_trackers = false ;
m_announce_to_lsd = false ;
do_pause ( ) ;
}
else
{
do_resume ( ) ;
}
}
2004-03-21 03:03:37 +01:00
void torrent : : resume ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2010-03-29 02:34:04 +02:00
if ( m_allow_peers
& & m_announce_to_dht
& & m_announce_to_trackers
& & m_announce_to_lsd ) return ;
m_allow_peers = true ;
2010-03-31 04:40:00 +02:00
m_announce_to_dht = true ;
m_announce_to_trackers = true ;
m_announce_to_lsd = true ;
2010-11-07 10:39:35 +01:00
if ( ! m_ses . is_paused ( ) ) m_graceful_pause_mode = false ;
2011-06-05 22:48:00 +02:00
// we need to save this new state
m_need_save_resume_data = true ;
2008-06-29 21:08:30 +02:00
do_resume ( ) ;
}
void torrent : : do_resume ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-06-29 21:08:30 +02:00
if ( is_paused ( ) ) return ;
2006-11-14 01:08:16 +01:00
2011-09-05 07:50:41 +02:00
# ifdef TORRENT_USE_OPENSSL
if ( m_torrent_file - > is_valid ( ) & & m_torrent_file - > encryption_key ( ) . size ( ) = = 32 & & ! m_in_encrypted_list )
{
m_ses . m_encrypted_torrents . insert ( shared_from_this ( ) ) ;
m_in_encrypted_list = true ;
}
# endif
2006-11-14 01:08:16 +01:00
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
2011-02-25 18:00:36 +01:00
TORRENT_TRY {
2008-04-07 04:51:21 +02:00
if ( ( * i ) - > on_resume ( ) ) return ;
2011-02-25 18:00:36 +01:00
} TORRENT_CATCH ( std : : exception & ) { }
2006-11-14 01:08:16 +01:00
}
# endif
2008-07-12 10:25:19 +02:00
if ( alerts ( ) . should_post < torrent_resumed_alert > ( ) )
alerts ( ) . post_alert ( torrent_resumed_alert ( get_handle ( ) ) ) ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2008-05-06 20:03:41 +02:00
m_started = time_now ( ) ;
2009-02-23 02:21:19 +01:00
clear_error ( ) ;
2008-07-12 10:25:19 +02:00
start_announcing ( ) ;
2011-01-23 19:00:52 +01:00
if ( ! m_queued_for_checking & & should_check_files ( ) )
queue_torrent_check ( ) ;
2008-07-12 10:25:19 +02:00
}
2004-07-24 13:54:17 +02:00
2010-05-03 10:24:30 +02:00
void torrent : : update_tracker_timer ( ptime now )
2008-07-12 10:25:19 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2011-08-18 01:01:35 +02:00
if ( ! m_announcing )
{
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
debug_log ( " *** update tracker timer: not announcing " ) ;
# endif
return ;
}
2008-07-12 10:25:19 +02:00
2008-11-29 09:38:40 +01:00
ptime next_announce = max_time ( ) ;
int tier = INT_MAX ;
2009-06-28 22:21:55 +02:00
bool found_working = false ;
2008-11-29 09:38:40 +01:00
for ( std : : vector < announce_entry > : : iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
{
2011-08-18 01:01:35 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
char msg [ 1000 ] ;
snprintf ( msg , sizeof ( msg ) , " *** update tracker timer: considering \" %s \" "
" [ announce_to_all_tiers: %d announce_to_all_trackers: %d "
" found_working: %d i->tier: %d tier: %d "
" is_working: %d fails: %d fail_limit: %d updating: %d ] "
, i - > url . c_str ( ) , settings ( ) . announce_to_all_tiers
, settings ( ) . announce_to_all_trackers , found_working
, i - > tier , tier , i - > is_working ( ) , i - > fails , i - > fail_limit
, i - > updating ) ;
debug_log ( msg ) ;
# endif
2010-02-14 02:39:55 +01:00
if ( settings ( ) . announce_to_all_tiers
2009-06-28 22:21:55 +02:00
& & found_working
& & i - > tier < = tier
& & tier ! = INT_MAX )
continue ;
2010-02-14 02:39:55 +01:00
if ( i - > tier > tier & & ! settings ( ) . announce_to_all_tiers ) break ;
2009-06-28 22:21:55 +02:00
if ( i - > is_working ( ) ) { tier = i - > tier ; found_working = false ; }
2008-11-29 09:38:40 +01:00
if ( i - > fails > = i - > fail_limit & & i - > fail_limit ! = 0 ) continue ;
2011-09-12 07:21:16 +02:00
if ( i - > updating )
{
found_working = true ;
}
else
{
ptime next_tracker_announce = ( std : : max ) ( i - > next_announce , i - > min_announce ) ;
if ( next_tracker_announce < next_announce
& & ( ! found_working | | i - > is_working ( ) ) )
next_announce = next_tracker_announce ;
}
2010-04-27 20:22:59 +02:00
if ( i - > is_working ( ) ) found_working = true ;
2011-09-12 07:21:16 +02:00
if ( found_working
& & ! settings ( ) . announce_to_all_trackers
2010-04-27 20:22:59 +02:00
& & ! settings ( ) . announce_to_all_tiers ) break ;
2008-11-29 09:38:40 +01:00
}
2010-05-03 10:24:30 +02:00
2011-08-18 01:01:35 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
char msg [ 200 ] ;
snprintf ( msg , sizeof ( msg ) , " *** update tracker timer: next_announce < now %d "
" m_waiting_tracker: %d next_announce_in: %d "
, next_announce < = now , m_waiting_tracker , total_seconds ( now - next_announce ) ) ;
debug_log ( msg ) ;
# endif
if ( next_announce < = now ) next_announce = now ;
2010-07-15 07:16:06 +02:00
m_waiting_tracker = true ;
error_code ec ;
boost : : weak_ptr < torrent > self ( shared_from_this ( ) ) ;
2011-09-12 07:21:16 +02:00
// don't re-issue the timer if it's the same expiration time as last time
if ( m_tracker_timer . expires_at ( ) = = next_announce ) return ;
2008-11-29 09:38:40 +01:00
2010-11-28 02:47:30 +01:00
# if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async ( " tracker::on_tracker_announce_disp " ) ;
# endif
2008-11-29 09:38:40 +01:00
m_tracker_timer . expires_at ( next_announce , ec ) ;
2010-05-02 08:29:52 +02:00
m_tracker_timer . async_wait ( boost : : bind ( & torrent : : on_tracker_announce_disp , self , _1 ) ) ;
2008-07-12 10:25:19 +02:00
}
void torrent : : start_announcing ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-07-12 10:25:19 +02:00
if ( is_paused ( ) ) return ;
2008-08-27 17:15:41 +02:00
// if we don't have metadata, we need to announce
// before checking files, to get peers to
// request the metadata from
if ( ! m_files_checked & & valid_metadata ( ) ) return ;
2008-07-12 10:25:19 +02:00
if ( m_announcing ) return ;
m_announcing = true ;
if ( ! m_trackers . empty ( ) )
{
// tell the tracker that we're back
2008-11-29 09:38:40 +01:00
std : : for_each ( m_trackers . begin ( ) , m_trackers . end ( )
2010-05-02 08:29:52 +02:00
, boost : : bind ( & announce_entry : : reset , _1 ) ) ;
2008-07-12 10:25:19 +02:00
}
2010-02-18 07:45:07 +01:00
// reset the stats, since from the tracker's
// point of view, this is a new session
m_total_failed_bytes = 0 ;
m_total_redundant_bytes = 0 ;
m_stat . clear ( ) ;
announce_with_tracker ( ) ;
2008-07-12 10:25:19 +02:00
// private torrents are never announced on LSD
// or on DHT, we don't need this timer.
2009-08-20 05:19:12 +02:00
if ( ! m_torrent_file - > is_valid ( )
| | ( ! m_torrent_file - > priv ( )
& & ( ! m_torrent_file - > is_i2p ( )
2010-02-14 02:39:55 +01:00
| | settings ( ) . allow_i2p_mixed ) ) )
2008-07-12 10:25:19 +02:00
{
2010-02-05 09:23:17 +01:00
if ( m_ses . m_lsd ) lsd_announce ( ) ;
# ifndef TORRENT_DISABLE_DHT
2010-02-14 02:39:55 +01:00
if ( m_ses . m_dht ) dht_announce ( ) ;
2010-02-05 09:23:17 +01:00
# endif
2008-07-12 10:25:19 +02:00
}
}
void torrent : : stop_announcing ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-07-12 10:25:19 +02:00
if ( ! m_announcing ) return ;
error_code ec ;
m_tracker_timer . cancel ( ec ) ;
2008-06-08 07:14:40 +02:00
2008-07-12 10:25:19 +02:00
m_announcing = false ;
2004-07-24 13:54:17 +02:00
2008-11-29 09:38:40 +01:00
ptime now = time_now ( ) ;
for ( std : : vector < announce_entry > : : iterator i = m_trackers . begin ( )
, end ( m_trackers . end ( ) ) ; i ! = end ; + + i )
2009-12-02 05:05:24 +01:00
{
2008-11-29 09:38:40 +01:00
i - > next_announce = now ;
2009-12-02 05:05:24 +01:00
i - > min_announce = now ;
}
2008-11-29 09:38:40 +01:00
announce_with_tracker ( tracker_request : : stopped ) ;
2004-03-21 03:03:37 +01:00
}
2009-07-19 06:59:27 +02:00
void torrent : : second_tick ( stat & accumulator , int tick_interval_ms )
2003-12-01 06:01:40 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2009-06-19 00:32:55 +02:00
ptime now = time_now ( ) ;
2006-11-14 01:08:16 +01:00
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
2011-02-25 18:00:36 +01:00
TORRENT_TRY {
2008-04-07 04:51:21 +02:00
( * i ) - > tick ( ) ;
2011-02-25 18:00:36 +01:00
} TORRENT_CATCH ( std : : exception & ) { }
2006-11-14 01:08:16 +01:00
}
# endif
2009-05-13 03:34:10 +02:00
m_time_scaler - - ;
if ( m_time_scaler < = 0 )
{
m_time_scaler = 10 ;
if ( settings ( ) . max_sparse_regions > 0
& & m_picker
& & m_picker - > sparse_regions ( ) > settings ( ) . max_sparse_regions )
{
// we have too many sparse regions. Prioritize pieces
// that won't introduce new sparse regions
// prioritize pieces that will reduce the number of sparse
// regions even higher
int start = m_picker - > cursor ( ) ;
int end = m_picker - > reverse_cursor ( ) ;
for ( int i = start ; i < end ; + + i )
update_sparse_piece_prio ( i , start , end ) ;
}
2009-07-23 06:38:52 +02:00
// ------------------------
// upload shift
// ------------------------
// this part will shift downloads
// from peers that are seeds and peers
// that don't want to download from us
// to peers that cannot upload anything
// to us. The shifting will make sure
// that the torrent's share ratio
// will be maintained
// if the share ratio is 0 (infinite)
// m_available_free_upload isn't used
// because it isn't necessary
if ( ratio ( ) ! = 0.f )
{
// accumulate all the free download we get
// and add it to the available free upload
2011-02-21 06:24:41 +01:00
add_free_upload ( collect_free_download (
this - > begin ( ) , this - > end ( ) ) ) ;
2009-07-23 06:38:52 +02:00
// distribute the free upload among the peers
m_available_free_upload = distribute_free_upload (
this - > begin ( ) , this - > end ( ) , m_available_free_upload ) ;
}
2009-05-13 03:34:10 +02:00
}
2009-06-19 00:32:55 +02:00
// if we're in upload only mode and we're auto-managed
// leave upload mode every 10 minutes hoping that the error
// condition has been fixed
2011-02-21 06:24:41 +01:00
if ( m_upload_mode & & m_auto_managed & & int ( m_upload_mode_time )
2010-02-14 02:39:55 +01:00
> = settings ( ) . optimistic_disk_retry )
2009-06-19 00:32:55 +02:00
{
set_upload_mode ( false ) ;
}
2008-07-12 10:25:19 +02:00
if ( is_paused ( ) )
2005-03-30 01:47:13 +02:00
{
// let the stats fade out to 0
2009-12-29 18:49:24 +01:00
accumulator + = m_stat ;
2009-07-19 06:59:27 +02:00
m_stat . second_tick ( tick_interval_ms ) ;
2011-11-15 03:34:00 +01:00
// if the rate is 0, there's no update because of network transfers
if ( m_stat . low_pass_upload_rate ( ) > 0 | | m_stat . low_pass_download_rate ( ) > 0 )
state_updated ( ) ;
2005-03-30 01:47:13 +02:00
return ;
}
2010-02-14 02:39:55 +01:00
if ( settings ( ) . rate_limit_ip_overhead )
2009-04-26 02:21:59 +02:00
{
int up_limit = m_bandwidth_channel [ peer_connection : : upload_channel ] . throttle ( ) ;
int down_limit = m_bandwidth_channel [ peer_connection : : download_channel ] . throttle ( ) ;
if ( down_limit > 0
& & m_stat . download_ip_overhead ( ) > = down_limit
& & alerts ( ) . should_post < performance_alert > ( ) )
{
alerts ( ) . post_alert ( performance_alert ( get_handle ( )
, performance_alert : : download_limit_too_low ) ) ;
}
if ( up_limit > 0
& & m_stat . upload_ip_overhead ( ) > = up_limit
& & alerts ( ) . should_post < performance_alert > ( ) )
{
alerts ( ) . post_alert ( performance_alert ( get_handle ( )
, performance_alert : : upload_limit_too_low ) ) ;
}
}
2010-02-14 02:39:55 +01:00
int seconds_since_last_tick = 1 ;
if ( m_ses . m_tick_residual > = 1000 ) + + seconds_since_last_tick ;
if ( is_seed ( ) ) m_seeding_time + = seconds_since_last_tick ;
if ( is_finished ( ) ) m_finished_time + = seconds_since_last_tick ;
if ( m_upload_mode ) m_upload_mode_time + = seconds_since_last_tick ;
m_last_scrape + = seconds_since_last_tick ;
m_active_time + = seconds_since_last_tick ;
2010-07-08 21:29:38 +02:00
m_last_download + = seconds_since_last_tick ;
m_last_upload + = seconds_since_last_tick ;
2008-04-16 08:31:05 +02:00
2009-03-17 10:34:44 +01:00
// ---- TIME CRITICAL PIECES ----
if ( ! m_time_critical_pieces . empty ( ) )
{
request_time_critical_pieces ( ) ;
}
2006-04-25 23:04:48 +02:00
// ---- WEB SEEDS ----
2007-11-28 03:54:46 +01:00
// if we have everything we want we don't need to connect to any web-seed
2011-04-30 22:05:23 +02:00
if ( ! is_finished ( ) & & ! m_web_seeds . empty ( ) & & m_files_checked
& & int ( m_connections . size ( ) ) < m_max_connections
2011-05-01 21:28:13 +02:00
& & m_ses . num_connections ( ) < m_ses . settings ( ) . connections_limit )
2007-11-28 03:54:46 +01:00
{
2006-04-25 23:04:48 +02:00
// keep trying web-seeds if there are any
// first find out which web seeds we are connected to
2010-02-12 07:10:20 +01:00
for ( std : : list < web_seed_entry > : : iterator i = m_web_seeds . begin ( ) ;
i ! = m_web_seeds . end ( ) ; )
2006-04-25 23:04:48 +02:00
{
2010-02-12 07:10:20 +01:00
std : : list < web_seed_entry > : : iterator w = i + + ;
if ( w - > connection ) continue ;
if ( w - > retry > time_now ( ) ) continue ;
if ( w - > resolving ) continue ;
2006-04-25 23:04:48 +02:00
2010-02-12 07:10:20 +01:00
connect_to_url_seed ( w ) ;
}
2006-04-25 23:04:48 +02:00
}
2004-01-13 04:08:59 +01:00
for ( peer_iterator i = m_connections . begin ( ) ;
2007-05-24 19:07:43 +02:00
i ! = m_connections . end ( ) ; )
2003-12-07 06:53:04 +01:00
{
2007-10-31 10:48:20 +01:00
peer_connection * p = * i ;
2007-05-24 19:07:43 +02:00
+ + i ;
2010-07-15 08:27:44 +02:00
if ( ! p - > ignore_stats ( ) )
m_stat + = p - > statistics ( ) ;
2004-03-28 19:45:37 +02:00
// updates the peer connection's ul/dl bandwidth
// resource requests
2011-02-25 18:00:36 +01:00
TORRENT_TRY {
2009-07-19 06:59:27 +02:00
p - > second_tick ( tick_interval_ms ) ;
2007-05-24 19:07:43 +02:00
}
2011-02-25 18:00:36 +01:00
TORRENT_CATCH ( std : : exception & e )
2007-05-24 19:07:43 +02:00
{
2011-03-10 06:01:36 +01:00
TORRENT_DECLARE_DUMMY ( std : : exception , e ) ;
2011-02-21 06:24:41 +01:00
( void ) e ;
2008-02-17 21:57:16 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2011-08-13 20:46:52 +02:00
p - > peer_log ( " *** ERROR %s " , e . what ( ) ) ;
2007-05-24 19:07:43 +02:00
# endif
2009-11-29 08:06:38 +01:00
p - > disconnect ( errors : : no_error , 1 ) ;
2007-05-24 19:07:43 +02:00
}
2003-12-07 06:53:04 +01:00
}
2010-01-02 15:16:35 +01:00
if ( m_ses . m_alerts . should_post < stats_alert > ( ) )
m_ses . m_alerts . post_alert ( stats_alert ( get_handle ( ) , tick_interval_ms , m_stat ) ) ;
2004-04-18 15:41:08 +02:00
accumulator + = m_stat ;
2008-04-16 08:31:05 +02:00
m_total_uploaded + = m_stat . last_payload_uploaded ( ) ;
m_total_downloaded + = m_stat . last_payload_downloaded ( ) ;
2009-07-19 06:59:27 +02:00
m_stat . second_tick ( tick_interval_ms ) ;
2011-11-15 03:34:00 +01:00
// if the rate is 0, there's no update because of network transfers
if ( m_stat . low_pass_upload_rate ( ) > 0 | | m_stat . low_pass_download_rate ( ) > 0 )
state_updated ( ) ;
2004-03-23 23:58:18 +01:00
}
2010-09-05 18:01:36 +02:00
void torrent : : recalc_share_mode ( )
{
TORRENT_ASSERT ( share_mode ( ) ) ;
if ( is_seed ( ) ) return ;
int pieces_in_torrent = m_torrent_file - > num_pieces ( ) ;
int num_seeds = 0 ;
int num_peers = 0 ;
int num_downloaders = 0 ;
int missing_pieces = 0 ;
int num_interested = 0 ;
for ( std : : set < peer_connection * > : : iterator i = m_connections . begin ( )
, end ( m_connections . end ( ) ) ; i ! = end ; + + i )
{
peer_connection * p = * i ;
if ( p - > is_connecting ( ) ) continue ;
+ + num_peers ;
if ( p - > is_seed ( ) )
{
+ + num_seeds ;
continue ;
}
if ( p - > share_mode ( ) ) continue ;
if ( ( * i ) - > is_peer_interested ( ) ) + + num_interested ;
+ + num_downloaders ;
missing_pieces + = pieces_in_torrent - p - > num_have_pieces ( ) ;
}
if ( num_peers = = 0 ) return ;
if ( num_seeds * 100 / num_peers > 50
& & ( num_peers * 100 / m_max_connections > 90
| | num_peers > 20 ) )
{
// we are connected to more than 90% seeds (and we're beyond
// 90% of the max number of connections). That will
// limit our ability to upload. We need more downloaders.
// disconnect some seeds so that we don't have more than 50%
int to_disconnect = num_seeds - num_peers / 2 ;
std : : vector < peer_connection * > seeds ;
seeds . reserve ( num_seeds ) ;
for ( std : : set < peer_connection * > : : iterator i = m_connections . begin ( )
, end ( m_connections . end ( ) ) ; i ! = end ; + + i )
{
peer_connection * p = * i ;
if ( p - > is_seed ( ) ) seeds . push_back ( p ) ;
}
std : : random_shuffle ( seeds . begin ( ) , seeds . end ( ) ) ;
TORRENT_ASSERT ( to_disconnect < = int ( seeds . size ( ) ) ) ;
for ( int i = 0 ; i < to_disconnect ; + + i )
seeds [ i ] - > disconnect ( errors : : upload_upload_connection ) ;
}
if ( num_downloaders = = 0 ) return ;
// assume that the seeds are about as fast as us. During the time
// we can download one piece, and upload one piece, each seed
// can upload two pieces.
missing_pieces - = 2 * num_seeds ;
if ( missing_pieces < = 0 ) return ;
// missing_pieces represents our opportunity to download pieces
// and share them more than once each
// now, download at least one piece, otherwise download one more
// piece if our downloaded (and downloading) pieces is less than 50%
// of the uploaded bytes
int num_downloaded_pieces = ( std : : max ) ( m_picker - > num_have ( )
, pieces_in_torrent - m_picker - > num_filtered ( ) ) ;
if ( num_downloaded_pieces * m_torrent_file - > piece_length ( )
* settings ( ) . share_mode_target > m_total_uploaded
& & num_downloaded_pieces > 0 )
return ;
// don't have more pieces downloading in parallel than 5% of the total
// number of pieces we have downloaded
2011-02-21 06:24:41 +01:00
if ( int ( m_picker - > get_download_queue ( ) . size ( ) ) > num_downloaded_pieces / 20 )
2010-09-05 18:01:36 +02:00
return ;
// one more important property is that there are enough pieces
// that more than one peer wants to download
// make sure that there are enough downloaders for the rarest
// piece. Go through all pieces, figure out which one is the rarest
// and how many peers that has that piece
std : : vector < int > rarest_pieces ;
int num_pieces = m_torrent_file - > num_pieces ( ) ;
int rarest_rarity = INT_MAX ;
bool prio_updated = false ;
for ( int i = 0 ; i < num_pieces ; + + i )
{
piece_picker : : piece_pos const & pp = m_picker - > piece_stats ( i ) ;
if ( pp . peer_count = = 0 ) continue ;
if ( pp . filtered ( ) & & ( pp . have ( ) | | pp . downloading ) )
{
m_picker - > set_piece_priority ( i , 1 ) ;
prio_updated = true ;
continue ;
}
// don't count pieces we already have or are downloading
if ( ! pp . filtered ( ) | | pp . have ( ) ) continue ;
2011-02-21 06:24:41 +01:00
if ( int ( pp . peer_count ) > rarest_rarity ) continue ;
if ( int ( pp . peer_count ) = = rarest_rarity )
2010-09-05 18:01:36 +02:00
{
rarest_pieces . push_back ( i ) ;
continue ;
}
rarest_pieces . clear ( ) ;
rarest_rarity = pp . peer_count ;
rarest_pieces . push_back ( i ) ;
}
if ( prio_updated )
m_policy . recalculate_connect_candidates ( ) ;
// now, rarest_pieces is a list of all pieces that are the rarest ones.
// and rarest_rarity is the number of peers that have the rarest pieces
// if there's only a single peer that doesn't have the rarest piece
// it's impossible for us to download one piece and upload it
// twice. i.e. we cannot get a positive share ratio
if ( num_peers - rarest_rarity < settings ( ) . share_mode_target ) return ;
// we might be able to do better than a share ratio of 2 if there are
// enough downloaders of the pieces we already have.
// TODO: go through the pieces we have and count the total number
// of downloaders we have. Only count peers that are interested in us
// since some peers might not send have messages for pieces we have
// it num_interested == 0, we need to pick a new piece
// now, pick one of the rarest pieces to download
2011-02-26 08:55:51 +01:00
int pick = random ( ) % rarest_pieces . size ( ) ;
2010-09-05 18:01:36 +02:00
bool was_finished = is_finished ( ) ;
m_picker - > set_piece_priority ( rarest_pieces [ pick ] , 1 ) ;
update_peer_interest ( was_finished ) ;
m_policy . recalculate_connect_candidates ( ) ;
}
2010-01-15 17:45:42 +01:00
void torrent : : refresh_explicit_cache ( int cache_size )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-01-15 17:45:42 +01:00
if ( ! ready_for_connections ( ) ) return ;
// rotate the cached pieces
// add blocks_per_piece / 2 in order to round to closest whole piece
2010-02-14 02:39:55 +01:00
int blocks_per_piece = m_torrent_file - > piece_length ( ) / block_size ( ) ;
2010-01-15 17:45:42 +01:00
int num_cache_pieces = ( cache_size + blocks_per_piece / 2 ) / blocks_per_piece ;
if ( num_cache_pieces > m_torrent_file - > num_pieces ( ) )
num_cache_pieces = m_torrent_file - > num_pieces ( ) ;
std : : vector < int > avail_vec ;
if ( has_picker ( ) )
{
m_picker - > get_availability ( avail_vec ) ;
}
else
{
// we don't keep track of availability, do it the expensive way
// do a linear search from the first piece
for ( int i = 0 ; i < m_torrent_file - > num_pieces ( ) ; + + i )
{
int availability = 0 ;
if ( ! have_piece ( i ) )
{
avail_vec . push_back ( INT_MAX ) ;
continue ;
}
for ( const_peer_iterator j = this - > begin ( ) ; j ! = this - > end ( ) ; + + j )
if ( ( * j ) - > has_piece ( i ) ) + + availability ;
avail_vec . push_back ( availability ) ;
}
}
// now pick the num_cache_pieces rarest pieces from avail_vec
std : : vector < std : : pair < int , int > > pieces ( m_torrent_file - > num_pieces ( ) ) ;
for ( int i = 0 ; i < m_torrent_file - > num_pieces ( ) ; + + i )
{
pieces [ i ] . second = i ;
if ( ! have_piece ( i ) ) pieces [ i ] . first = INT_MAX ;
else pieces [ i ] . first = avail_vec [ i ] ;
}
// decrease the availability of the pieces that are
// already in the read cache, to move them closer to
// the beginning of the pieces list, and more likely
// to be included in this round of cache pieces
std : : vector < cached_piece_info > ret ;
m_ses . m_disk_thread . get_cache_info ( info_hash ( ) , ret ) ;
// remove write cache entries
ret . erase ( std : : remove_if ( ret . begin ( ) , ret . end ( )
, boost : : bind ( & cached_piece_info : : kind , _1 ) = = cached_piece_info : : write_cache )
, ret . end ( ) ) ;
for ( std : : vector < cached_piece_info > : : iterator i = ret . begin ( )
, end ( ret . end ( ) ) ; i ! = end ; + + i )
{
- - pieces [ i - > piece ] . first ;
}
std : : random_shuffle ( pieces . begin ( ) , pieces . end ( ) ) ;
std : : stable_sort ( pieces . begin ( ) , pieces . end ( )
, boost : : bind ( & std : : pair < int , int > : : first , _1 ) <
boost : : bind ( & std : : pair < int , int > : : first , _2 ) ) ;
avail_vec . clear ( ) ;
for ( int i = 0 ; i < num_cache_pieces ; + + i )
{
if ( pieces [ i ] . first = = INT_MAX ) break ;
avail_vec . push_back ( pieces [ i ] . second ) ;
}
if ( ! avail_vec . empty ( ) )
{
// the number of pieces to cache for this torrent is proportional
// the number of peers it has, divided by the total number of peers.
// Each peer gets an equal share of the cache
avail_vec . resize ( ( std : : min ) ( num_cache_pieces , int ( avail_vec . size ( ) ) ) ) ;
for ( std : : vector < int > : : iterator i = avail_vec . begin ( )
, end ( avail_vec . end ( ) ) ; i ! = end ; + + i )
2010-05-02 08:29:52 +02:00
filesystem ( ) . async_cache ( * i , boost : : bind ( & torrent : : on_disk_cache_complete
2010-01-15 17:45:42 +01:00
, shared_from_this ( ) , _1 , _2 ) ) ;
}
}
void torrent : : get_suggested_pieces ( std : : vector < int > & s ) const
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-02-14 02:39:55 +01:00
if ( settings ( ) . suggest_mode = = session_settings : : no_piece_suggestions )
2010-01-15 17:45:42 +01:00
{
s . clear ( ) ;
return ;
}
std : : vector < cached_piece_info > ret ;
m_ses . m_disk_thread . get_cache_info ( info_hash ( ) , ret ) ;
ptime now = time_now ( ) ;
// remove write cache entries
ret . erase ( std : : remove_if ( ret . begin ( ) , ret . end ( )
, boost : : bind ( & cached_piece_info : : kind , _1 ) = = cached_piece_info : : write_cache )
, ret . end ( ) ) ;
// sort by how new the cached entry is, new pieces first
std : : sort ( ret . begin ( ) , ret . end ( )
, boost : : bind ( & cached_piece_info : : last_use , _1 )
< boost : : bind ( & cached_piece_info : : last_use , _2 ) ) ;
// cut off the oldest pieces that we don't want to suggest
// if we have an explicit cache, it's much more likely to
// stick around, so we should suggest all pieces
int num_pieces_to_suggest = int ( ret . size ( ) ) ;
2011-03-15 02:58:48 +01:00
if ( num_pieces_to_suggest = = 0 ) return ;
2010-02-14 02:39:55 +01:00
if ( ! settings ( ) . explicit_read_cache )
2010-01-15 17:45:42 +01:00
num_pieces_to_suggest = ( std : : max ) ( 1 , int ( ret . size ( ) / 2 ) ) ;
ret . resize ( num_pieces_to_suggest ) ;
std : : transform ( ret . begin ( ) , ret . end ( ) , std : : back_inserter ( s )
, boost : : bind ( & cached_piece_info : : piece , _1 ) ) ;
}
2009-12-29 18:49:24 +01:00
void torrent : : add_stats ( stat const & s )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-12-29 18:49:24 +01:00
// these stats are propagated to the session
// stats the next time second_tick is called
m_stat + = s ;
}
2009-03-17 10:34:44 +01:00
void torrent : : request_time_critical_pieces ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2009-03-17 10:34:44 +01:00
// build a list of peers and sort it by download_queue_time
2011-08-05 09:56:07 +02:00
// we use this sorted list to determine which peer we should
// request a block from. The higher up a peer is in the list,
// the sooner we will fully download the block we request.
2009-03-17 10:34:44 +01:00
std : : vector < peer_connection * > peers ;
peers . reserve ( m_connections . size ( ) ) ;
std : : remove_copy_if ( m_connections . begin ( ) , m_connections . end ( )
, std : : back_inserter ( peers ) , ! boost : : bind ( & peer_connection : : can_request_time_critical , _1 ) ) ;
std : : sort ( peers . begin ( ) , peers . end ( )
, boost : : bind ( & peer_connection : : download_queue_time , _1 , 16 * 1024 )
< boost : : bind ( & peer_connection : : download_queue_time , _2 , 16 * 1024 ) ) ;
std : : set < peer_connection * > peers_with_requests ;
std : : vector < piece_block > interesting_blocks ;
std : : vector < piece_block > backup1 ;
std : : vector < piece_block > backup2 ;
std : : vector < int > ignore ;
ptime now = time_now ( ) ;
2011-08-05 09:56:07 +02:00
// now, iterate over all time critical pieces, in order of importance, and
// request them from the peers, in order of responsiveness. i.e. request
// the most time critical pieces from the fastest peers.
2009-03-17 10:34:44 +01:00
for ( std : : list < time_critical_piece > : : iterator i = m_time_critical_pieces . begin ( )
, end ( m_time_critical_pieces . end ( ) ) ; i ! = end ; + + i )
{
2011-08-05 19:35:09 +02:00
if ( peers . empty ( ) ) break ;
2009-03-17 10:34:44 +01:00
if ( i ! = m_time_critical_pieces . begin ( ) & & i - > deadline > now
2010-02-14 02:39:55 +01:00
+ milliseconds ( m_average_piece_time + m_piece_time_deviation * 4 ) )
2009-03-17 10:34:44 +01:00
{
// don't request pieces whose deadline is too far in the future
2011-08-05 09:56:07 +02:00
// this is one of the termination conditions. We don't want to
// send requests for all pieces in the torrent right away
2009-03-17 10:34:44 +01:00
break ;
}
2011-08-05 09:56:07 +02:00
// loop until every block has been requested from this piece (i->piece)
2009-03-17 10:34:44 +01:00
do
{
// pick the peer with the lowest download_queue_time that has i->piece
std : : vector < peer_connection * > : : iterator p = std : : find_if ( peers . begin ( ) , peers . end ( )
, boost : : bind ( & peer_connection : : has_piece , _1 , i - > piece ) ) ;
2011-08-05 09:56:07 +02:00
// obviously we'll have to skip it if we don't have a peer that has this piece
2009-03-17 10:34:44 +01:00
if ( p = = peers . end ( ) ) break ;
peer_connection & c = * * p ;
interesting_blocks . clear ( ) ;
backup1 . clear ( ) ;
backup2 . clear ( ) ;
2011-02-19 22:24:32 +01:00
// specifically request blocks with no affinity towards fast or slow
// pieces. If we would, the picked block might end up in one of
// the backup lists
2009-03-17 10:34:44 +01:00
m_picker - > add_blocks ( i - > piece , c . get_bitfield ( ) , interesting_blocks
, backup1 , backup2 , 1 , 0 , c . peer_info_struct ( )
2011-02-19 22:24:32 +01:00
, ignore , piece_picker : : none , 0 ) ;
2009-03-17 10:34:44 +01:00
2009-12-25 17:52:57 +01:00
std : : vector < pending_block > const & rq = c . request_queue ( ) ;
2009-03-17 10:34:44 +01:00
bool added_request = false ;
2009-12-25 17:52:57 +01:00
if ( ! interesting_blocks . empty ( ) & & std : : find_if ( rq . begin ( ) , rq . end ( )
, has_block ( interesting_blocks . front ( ) ) ) ! = rq . end ( ) )
2009-03-17 10:34:44 +01:00
{
c . make_time_critical ( interesting_blocks . front ( ) ) ;
added_request = true ;
}
else if ( ! interesting_blocks . empty ( ) )
{
2011-08-05 19:35:09 +02:00
if ( ! c . add_request ( interesting_blocks . front ( ) , peer_connection : : req_time_critical ) )
{
peers . erase ( p ) ;
continue ;
}
2009-03-17 10:34:44 +01:00
added_request = true ;
}
// TODO: if there's been long enough since we requested something
// from this piece, request one of the backup blocks (the one with
// the least number of requests to it) and update the last request
// timestamp
if ( added_request )
{
peers_with_requests . insert ( peers_with_requests . begin ( ) , & c ) ;
if ( i - > first_requested = = min_time ( ) ) i - > first_requested = now ;
if ( ! c . can_request_time_critical ( ) )
{
peers . erase ( p ) ;
}
else
{
// resort p, since it will have a higher download_queue_time now
while ( p ! = peers . end ( ) - 1 & & ( * p ) - > download_queue_time ( ) > ( * ( p + 1 ) ) - > download_queue_time ( ) )
{
std : : iter_swap ( p , p + 1 ) ;
+ + p ;
}
}
}
} while ( ! interesting_blocks . empty ( ) ) ;
}
// commit all the time critical requests
for ( std : : set < peer_connection * > : : iterator i = peers_with_requests . begin ( )
, end ( peers_with_requests . end ( ) ) ; i ! = end ; + + i )
{
( * i ) - > send_block_requests ( ) ;
}
}
2008-12-30 04:54:07 +01:00
std : : set < std : : string > torrent : : web_seeds ( web_seed_entry : : type_t type ) const
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-12-30 04:54:07 +01:00
std : : set < std : : string > ret ;
2010-02-12 07:10:20 +01:00
for ( std : : list < web_seed_entry > : : const_iterator i = m_web_seeds . begin ( )
2008-12-30 04:54:07 +01:00
, end ( m_web_seeds . end ( ) ) ; i ! = end ; + + i )
{
if ( i - > type ! = type ) continue ;
ret . insert ( i - > url ) ;
}
return ret ;
}
2010-04-14 08:22:00 +02:00
void torrent : : retry_web_seed ( peer_connection * p , int retry )
2007-11-27 04:37:47 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2010-02-12 07:10:20 +01:00
std : : list < web_seed_entry > : : iterator i = std : : find_if ( m_web_seeds . begin ( ) , m_web_seeds . end ( )
2010-04-14 08:22:00 +02:00
, ( boost : : bind ( & web_seed_entry : : connection , _1 ) = = p ) ) ;
2010-02-12 07:10:20 +01:00
2010-04-14 08:22:00 +02:00
TORRENT_ASSERT ( i ! = m_web_seeds . end ( ) ) ;
if ( i = = m_web_seeds . end ( ) ) return ;
2008-12-30 04:54:07 +01:00
if ( retry = = 0 ) retry = m_ses . settings ( ) . urlseed_wait_retry ;
2010-04-14 08:22:00 +02:00
i - > retry = time_now ( ) + seconds ( retry ) ;
2007-11-27 04:37:47 +01:00
}
2007-08-16 14:41:46 +02:00
bool torrent : : try_connect_peer ( )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( want_more_peers ( ) ) ;
2008-03-29 20:39:24 +01:00
if ( m_deficit_counter < 100 ) return false ;
m_deficit_counter - = 100 ;
2009-04-30 07:49:46 +02:00
bool ret = m_policy . connect_one_peer ( m_ses . session_time ( ) ) ;
2008-03-29 20:39:24 +01:00
return ret ;
}
void torrent : : give_connect_points ( int points )
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-03-29 20:39:24 +01:00
TORRENT_ASSERT ( points < = 100 ) ;
TORRENT_ASSERT ( points > 0 ) ;
TORRENT_ASSERT ( want_more_peers ( ) ) ;
m_deficit_counter + = points ;
2007-08-16 14:41:46 +02:00
}
2010-07-14 06:16:38 +02:00
void torrent : : add_peer ( tcp : : endpoint const & adr , int source )
{
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
peer_id id ( 0 ) ;
m_policy . add_peer ( adr , id , source , 0 ) ;
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2010-07-14 06:16:38 +02:00
}
2008-04-13 00:08:07 +02:00
void torrent : : async_verify_piece ( int piece_index , boost : : function < void ( int ) > const & f )
2003-12-07 06:53:04 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-18 02:32:16 +02:00
// INVARIANT_CHECK;
2006-04-25 23:04:48 +02:00
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( m_storage ) ;
TORRENT_ASSERT ( m_storage - > refcount ( ) > 0 ) ;
TORRENT_ASSERT ( piece_index > = 0 ) ;
TORRENT_ASSERT ( piece_index < m_torrent_file - > num_pieces ( ) ) ;
2008-06-07 04:58:28 +02:00
TORRENT_ASSERT ( piece_index < ( int ) m_picker - > num_pieces ( ) ) ;
2010-04-24 21:24:27 +02:00
TORRENT_ASSERT ( ! m_picker | | ! m_picker - > have_piece ( piece_index ) ) ;
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2008-02-18 04:07:14 +01:00
if ( m_picker )
{
int blocks_in_piece = m_picker - > blocks_in_piece ( piece_index ) ;
for ( int i = 0 ; i < blocks_in_piece ; + + i )
{
TORRENT_ASSERT ( m_picker - > num_peers ( piece_block ( piece_index , i ) ) = = 0 ) ;
}
}
# endif
2004-01-25 13:37:15 +01:00
2010-05-02 08:29:52 +02:00
m_storage - > async_hash ( piece_index , boost : : bind ( & torrent : : on_piece_verified
2007-06-10 22:46:09 +02:00
, shared_from_this ( ) , _1 , _2 , f ) ) ;
2008-11-29 22:33:21 +01:00
# if defined TORRENT_DEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
2007-10-18 02:32:16 +02:00
check_invariant ( ) ;
# endif
2007-06-10 22:46:09 +02:00
}
2003-12-07 06:53:04 +01:00
2007-06-10 22:46:09 +02:00
void torrent : : on_piece_verified ( int ret , disk_io_job const & j
2008-04-13 00:08:07 +02:00
, boost : : function < void ( int ) > f )
2007-06-10 22:46:09 +02:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-04-13 00:08:07 +02:00
// return value:
// 0: success, piece passed hash check
// -1: disk failure
// -2: hash check failed
2011-12-19 06:55:38 +01:00
state_updated ( ) ;
2009-06-10 10:30:55 +02:00
if ( ret = = - 1 ) handle_disk_error ( j ) ;
2008-04-13 00:08:07 +02:00
f ( ret ) ;
2003-12-01 06:01:40 +01:00
}
2010-02-14 02:39:55 +01:00
tcp : : endpoint torrent : : current_tracker ( ) const
2004-03-01 01:50:00 +01:00
{
return m_tracker_address ;
}
2008-11-29 09:38:40 +01:00
announce_entry * torrent : : find_tracker ( tracker_request const & r )
{
std : : vector < announce_entry > : : iterator i = std : : find_if (
m_trackers . begin ( ) , m_trackers . end ( )
2010-05-02 08:29:52 +02:00
, boost : : bind ( & announce_entry : : url , _1 ) = = r . url ) ;
2008-11-29 09:38:40 +01:00
if ( i = = m_trackers . end ( ) ) return 0 ;
return & * i ;
}
2009-07-19 06:59:27 +02:00
# if !TORRENT_NO_FPU
2006-06-12 01:24:36 +02:00
void torrent : : file_progress ( std : : vector < float > & fp ) const
2008-07-12 15:38:22 +02:00
{
fp . clear ( ) ;
fp . resize ( m_torrent_file - > num_files ( ) , 1.f ) ;
if ( is_seed ( ) ) return ;
std : : vector < size_type > progress ;
file_progress ( progress ) ;
for ( int i = 0 ; i < m_torrent_file - > num_files ( ) ; + + i )
{
file_entry const & f = m_torrent_file - > file_at ( i ) ;
if ( f . size = = 0 ) fp [ i ] = 1.f ;
else fp [ i ] = float ( progress [ i ] ) / f . size ;
}
}
2009-07-19 06:59:27 +02:00
# endif
2008-07-12 15:38:22 +02:00
2009-07-04 06:58:24 +02:00
void torrent : : file_progress ( std : : vector < size_type > & fp , int flags ) const
2006-06-12 01:24:36 +02:00
{
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( valid_metadata ( ) ) ;
2006-06-12 01:24:36 +02:00
2008-07-12 15:38:22 +02:00
fp . resize ( m_torrent_file - > num_files ( ) , 0 ) ;
2009-07-04 06:58:24 +02:00
if ( flags & torrent_handle : : piece_granularity )
{
std : : copy ( m_file_progress . begin ( ) , m_file_progress . end ( ) , fp . begin ( ) ) ;
return ;
}
2008-06-07 04:58:28 +02:00
if ( is_seed ( ) )
{
2008-07-12 15:38:22 +02:00
for ( int i = 0 ; i < m_torrent_file - > num_files ( ) ; + + i )
fp [ i ] = m_torrent_file - > files ( ) . at ( i ) . size ;
2008-06-07 04:58:28 +02:00
return ;
}
2006-06-12 01:24:36 +02:00
2008-07-30 10:52:39 +02:00
TORRENT_ASSERT ( has_picker ( ) ) ;
2007-09-01 05:00:31 +02:00
for ( int i = 0 ; i < m_torrent_file - > num_files ( ) ; + + i )
2006-06-12 01:24:36 +02:00
{
2008-05-28 10:44:40 +02:00
peer_request ret = m_torrent_file - > files ( ) . map_file ( i , 0 , 0 ) ;
size_type size = m_torrent_file - > files ( ) . at ( i ) . size ;
2006-10-08 22:36:05 +02:00
// zero sized files are considered
// 100% done all the time
if ( size = = 0 )
{
2008-07-12 15:38:22 +02:00
fp [ i ] = 0 ;
2006-10-08 22:36:05 +02:00
continue ;
}
2006-06-12 01:24:36 +02:00
size_type done = 0 ;
2006-08-27 20:38:30 +02:00
while ( size > 0 )
2006-06-12 01:24:36 +02:00
{
2008-02-25 11:28:53 +01:00
size_type bytes_step = ( std : : min ) ( size_type ( m_torrent_file - > piece_size ( ret . piece )
- ret . start ) , size ) ;
2008-06-07 04:58:28 +02:00
if ( m_picker - > have_piece ( ret . piece ) ) done + = bytes_step ;
2006-06-12 01:24:36 +02:00
+ + ret . piece ;
ret . start = 0 ;
2006-08-27 20:38:30 +02:00
size - = bytes_step ;
2006-06-12 01:24:36 +02:00
}
2007-10-05 02:30:00 +02:00
TORRENT_ASSERT ( size = = 0 ) ;
2006-10-08 22:36:05 +02:00
2008-07-12 15:38:22 +02:00
fp [ i ] = done ;
2006-06-12 01:24:36 +02:00
}
2008-07-09 12:45:07 +02:00
const std : : vector < piece_picker : : downloading_piece > & q
= m_picker - > get_download_queue ( ) ;
for ( std : : vector < piece_picker : : downloading_piece > : : const_iterator
i = q . begin ( ) , end ( q . end ( ) ) ; i ! = end ; + + i )
{
size_type offset = size_type ( i - > index ) * m_torrent_file - > piece_length ( ) ;
torrent_info : : file_iterator file = m_torrent_file - > file_at_offset ( offset ) ;
int file_index = file - m_torrent_file - > begin_files ( ) ;
int num_blocks = m_picker - > blocks_in_piece ( i - > index ) ;
piece_picker : : block_info const * info = i - > info ;
for ( int k = 0 ; k < num_blocks ; + + k )
{
2008-07-13 18:44:14 +02:00
TORRENT_ASSERT ( file ! = m_torrent_file - > end_files ( ) ) ;
2008-07-11 16:10:33 +02:00
TORRENT_ASSERT ( offset = = size_type ( i - > index ) * m_torrent_file - > piece_length ( )
2010-02-14 02:39:55 +01:00
+ k * block_size ( ) ) ;
2008-07-13 18:44:14 +02:00
TORRENT_ASSERT ( offset < m_torrent_file - > total_size ( ) ) ;
while ( offset > = file - > offset + file - > size )
{
+ + file ;
+ + file_index ;
}
TORRENT_ASSERT ( file ! = m_torrent_file - > end_files ( ) ) ;
2008-07-11 16:10:33 +02:00
2010-02-14 02:39:55 +01:00
size_type block = block_size ( ) ;
2008-07-11 16:10:33 +02:00
if ( info [ k ] . state = = piece_picker : : block_info : : state_none )
{
2010-02-14 02:39:55 +01:00
offset + = block ;
2008-07-09 12:45:07 +02:00
continue ;
2008-07-11 16:10:33 +02:00
}
if ( info [ k ] . state = = piece_picker : : block_info : : state_requested )
{
2010-02-14 02:39:55 +01:00
block = 0 ;
2008-07-11 16:10:33 +02:00
policy : : peer * p = static_cast < policy : : peer * > ( info [ k ] . peer ) ;
if ( p & & p - > connection )
{
boost : : optional < piece_block_progress > pbp
= p - > connection - > downloading_piece_progress ( ) ;
if ( pbp & & pbp - > piece_index = = i - > index & & pbp - > block_index = = k )
2010-02-14 02:39:55 +01:00
block = pbp - > bytes_downloaded ;
TORRENT_ASSERT ( block < = block_size ( ) ) ;
2008-07-11 16:10:33 +02:00
}
2010-02-14 02:39:55 +01:00
if ( block = = 0 )
2008-07-11 16:10:33 +02:00
{
2010-02-14 02:39:55 +01:00
offset + = block_size ( ) ;
2008-07-11 16:10:33 +02:00
continue ;
}
}
2010-02-14 02:39:55 +01:00
if ( offset + block > file - > offset + file - > size )
2008-07-09 12:45:07 +02:00
{
2011-02-21 06:24:41 +01:00
int left_over = int ( block_size ( ) - block ) ;
2008-07-09 12:45:07 +02:00
// split the block on multiple files
2010-02-14 02:39:55 +01:00
while ( block > 0 )
2008-07-09 12:45:07 +02:00
{
2008-07-09 17:23:42 +02:00
TORRENT_ASSERT ( offset < = file - > offset + file - > size ) ;
2008-07-13 09:58:32 +02:00
size_type slice = ( std : : min ) ( file - > offset + file - > size - offset
2010-02-14 02:39:55 +01:00
, block ) ;
2008-07-12 15:38:22 +02:00
fp [ file_index ] + = slice ;
2008-07-09 12:45:07 +02:00
offset + = slice ;
2010-02-14 02:39:55 +01:00
block - = slice ;
2008-07-13 18:44:14 +02:00
TORRENT_ASSERT ( offset < = file - > offset + file - > size ) ;
if ( offset = = file - > offset + file - > size )
{
+ + file ;
+ + file_index ;
if ( file = = m_torrent_file - > end_files ( ) )
{
2010-02-14 02:39:55 +01:00
offset + = block ;
2008-07-13 18:44:14 +02:00
break ;
}
}
2008-07-09 12:45:07 +02:00
}
2008-07-11 16:10:33 +02:00
offset + = left_over ;
2008-07-13 18:44:14 +02:00
TORRENT_ASSERT ( offset = = size_type ( i - > index ) * m_torrent_file - > piece_length ( )
2010-02-14 02:39:55 +01:00
+ ( k + 1 ) * block_size ( ) ) ;
2008-07-09 12:45:07 +02:00
}
else
{
2010-02-14 02:39:55 +01:00
fp [ file_index ] + = block ;
offset + = block_size ( ) ;
2008-07-09 12:45:07 +02:00
}
2008-07-13 18:44:14 +02:00
TORRENT_ASSERT ( file_index < = m_torrent_file - > num_files ( ) ) ;
2008-07-09 12:45:07 +02:00
}
}
2006-06-12 01:24:36 +02:00
}
2005-10-16 18:58:41 +02:00
2008-07-03 12:05:51 +02:00
void torrent : : set_state ( torrent_status : : state_t s )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-11-29 22:33:21 +01:00
# ifdef TORRENT_DEBUG
2009-02-09 03:04:43 +01:00
if ( s ! = torrent_status : : checking_files
& & s ! = torrent_status : : queued_for_checking )
2009-04-26 09:31:26 +02:00
{
// the only valid transition away from queued_for_checking
// is to checking_files. One exception is to finished
// in case all the files are marked with priority 0
if ( m_queued_for_checking )
{
std : : vector < int > pieces ;
m_picker - > piece_priorities ( pieces ) ;
// make sure all pieces have priority 0
2009-08-30 09:38:52 +02:00
TORRENT_ASSERT ( std : : accumulate ( pieces . begin ( ) , pieces . end ( ) , 0 ) = = 0 ) ;
2009-04-26 09:31:26 +02:00
}
}
2008-10-05 03:44:57 +02:00
if ( s = = torrent_status : : seeding )
TORRENT_ASSERT ( is_seed ( ) ) ;
if ( s = = torrent_status : : finished )
TORRENT_ASSERT ( is_finished ( ) ) ;
if ( s = = torrent_status : : downloading & & m_state = = torrent_status : : finished )
TORRENT_ASSERT ( ! is_finished ( ) ) ;
# endif
2011-02-21 06:24:41 +01:00
if ( int ( m_state ) = = s ) return ;
2008-07-06 14:22:56 +02:00
if ( m_ses . m_alerts . should_post < state_changed_alert > ( ) )
2010-02-14 02:39:55 +01:00
m_ses . m_alerts . post_alert ( state_changed_alert ( get_handle ( ) , s , ( torrent_status : : state_t ) m_state ) ) ;
2008-12-01 01:19:05 +01:00
m_state = s ;
2011-01-29 11:37:21 +01:00
2011-11-15 03:34:00 +01:00
state_updated ( ) ;
2011-01-29 11:37:21 +01:00
# ifndef TORRENT_DISABLE_EXTENSIONS
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
2011-02-25 18:00:36 +01:00
TORRENT_TRY {
2011-01-29 11:37:21 +01:00
( * i ) - > on_state ( m_state ) ;
2011-02-25 18:00:36 +01:00
} TORRENT_CATCH ( std : : exception & ) { }
2011-01-29 11:37:21 +01:00
}
# endif
2008-07-03 12:05:51 +02:00
}
2011-05-02 03:45:56 +02:00
# ifndef TORRENT_DISABLE_EXTENSIONS
void torrent : : notify_extension_add_peer ( tcp : : endpoint const & ip
, int src , int flags )
{
for ( extension_list_t : : iterator i = m_extensions . begin ( )
, end ( m_extensions . end ( ) ) ; i ! = end ; + + i )
{
TORRENT_TRY {
( * i ) - > on_add_peer ( ip , src , flags ) ;
} TORRENT_CATCH ( std : : exception & ) { }
}
}
# endif
2011-11-15 03:34:00 +01:00
void torrent : : state_updated ( )
{
// we're either not subscribing to this torrent, or
// it has already been updated this round, no need to
// add it to the list twice
if ( ! m_state_subscription | | m_in_state_updates ) return ;
2011-11-15 07:47:02 +01:00
m_ses . add_to_update_queue ( shared_from_this ( ) ) ;
2011-11-15 03:34:00 +01:00
m_in_state_updates = true ;
}
2011-02-01 10:48:28 +01:00
void torrent : : status ( torrent_status * st , boost : : uint32_t flags )
2003-10-26 18:35:23 +01:00
{
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2008-05-19 06:06:25 +02:00
ptime now = time_now ( ) ;
2011-02-01 10:48:28 +01:00
st - > handle = get_handle ( ) ;
2011-04-19 10:21:09 +02:00
st - > info_hash = info_hash ( ) ;
2003-10-30 00:28:09 +01:00
2011-09-12 05:51:49 +02:00
st - > listen_port = 0 ;
# ifdef TORRENT_USE_OPENSSL
if ( is_ssl_torrent ( ) & & m_ssl_acceptor ) st - > listen_port = m_ssl_acceptor - > external_port ;
# endif
2011-02-01 10:48:28 +01:00
st - > has_incoming = m_has_incoming ;
if ( m_error ) st - > error = m_error . message ( ) + " : " + m_error_file ;
st - > seed_mode = m_seed_mode ;
2008-05-20 09:57:44 +02:00
2011-02-01 10:48:28 +01:00
st - > added_time = m_added_time ;
st - > completed_time = m_completed_time ;
2010-03-09 04:21:35 +01:00
2011-02-01 10:48:28 +01:00
st - > last_scrape = m_last_scrape ;
st - > share_mode = m_share_mode ;
st - > upload_mode = m_upload_mode ;
st - > up_bandwidth_queue = 0 ;
st - > down_bandwidth_queue = 0 ;
st - > priority = m_priority ;
2008-01-17 18:40:46 +01:00
2011-02-01 10:48:28 +01:00
st - > num_peers = ( int ) std : : count_if ( m_connections . begin ( ) , m_connections . end ( )
2007-11-20 23:46:27 +01:00
, ! boost : : bind ( & peer_connection : : is_connecting , _1 ) ) ;
2011-02-01 10:48:28 +01:00
st - > list_peers = m_policy . num_peers ( ) ;
st - > list_seeds = m_policy . num_seeds ( ) ;
st - > connect_candidates = m_policy . num_connect_candidates ( ) ;
st - > seed_rank = seed_rank ( settings ( ) ) ;
2005-11-05 11:56:47 +01:00
2011-02-01 10:48:28 +01:00
st - > all_time_upload = m_total_uploaded ;
st - > all_time_download = m_total_downloaded ;
2008-04-16 08:31:05 +02:00
2010-07-08 21:29:38 +02:00
// activity time
2011-10-26 02:58:21 +02:00
st - > finished_time = m_finished_time ;
2011-02-01 10:48:28 +01:00
st - > active_time = m_active_time ;
st - > seeding_time = m_seeding_time ;
st - > time_since_upload = m_last_upload ;
st - > time_since_download = m_last_download ;
st - > storage_mode = ( storage_mode_t ) m_storage_mode ;
st - > num_complete = ( m_complete = = 0xffffff ) ? - 1 : m_complete ;
st - > num_incomplete = ( m_incomplete = = 0xffffff ) ? - 1 : m_incomplete ;
st - > paused = is_torrent_paused ( ) ;
st - > auto_managed = m_auto_managed ;
st - > sequential_download = m_sequential_download ;
st - > is_seeding = is_seed ( ) ;
st - > is_finished = is_finished ( ) ;
st - > has_metadata = valid_metadata ( ) ;
bytes_done ( * st , flags & torrent_handle : : query_accurate_download_counters ) ;
TORRENT_ASSERT ( st - > total_wanted_done > = 0 ) ;
TORRENT_ASSERT ( st - > total_done > = st - > total_wanted_done ) ;
2003-10-31 13:07:07 +01:00
2003-12-22 08:14:35 +01:00
// payload transfer
2011-02-01 10:48:28 +01:00
st - > total_payload_download = m_stat . total_payload_download ( ) ;
st - > total_payload_upload = m_stat . total_payload_upload ( ) ;
2003-12-22 08:14:35 +01:00
// total transfer
2011-02-01 10:48:28 +01:00
st - > total_download = m_stat . total_payload_download ( )
2003-12-22 08:14:35 +01:00
+ m_stat . total_protocol_download ( ) ;
2011-02-01 10:48:28 +01:00
st - > total_upload = m_stat . total_payload_upload ( )
2003-12-22 08:14:35 +01:00
+ m_stat . total_protocol_upload ( ) ;
2004-04-18 14:28:02 +02:00
// failed bytes
2011-02-01 10:48:28 +01:00
st - > total_failed_bytes = m_total_failed_bytes ;
st - > total_redundant_bytes = m_total_redundant_bytes ;
2004-04-18 14:28:02 +02:00
2003-12-22 08:14:35 +01:00
// transfer rate
2011-02-01 10:48:28 +01:00
st - > download_rate = m_stat . download_rate ( ) ;
st - > upload_rate = m_stat . upload_rate ( ) ;
st - > download_payload_rate = m_stat . download_payload_rate ( ) ;
st - > upload_payload_rate = m_stat . upload_payload_rate ( ) ;
2003-12-22 08:14:35 +01:00
2008-12-27 08:22:57 +01:00
if ( m_waiting_tracker & & ! is_paused ( ) )
2011-02-01 10:48:28 +01:00
st - > next_announce = boost : : posix_time : : seconds (
2008-12-27 08:22:57 +01:00
total_seconds ( next_announce ( ) - now ) ) ;
else
2011-02-01 10:48:28 +01:00
st - > next_announce = boost : : posix_time : : seconds ( 0 ) ;
2008-12-27 08:22:57 +01:00
2011-02-01 10:48:28 +01:00
if ( st - > next_announce . is_negative ( ) )
st - > next_announce = boost : : posix_time : : seconds ( 0 ) ;
2007-04-05 00:27:36 +02:00
2011-02-01 10:48:28 +01:00
st - > announce_interval = boost : : posix_time : : seconds ( 0 ) ;
2004-01-17 21:04:19 +01:00
2011-02-01 10:48:28 +01:00
st - > current_tracker . clear ( ) ;
2005-03-11 18:21:56 +01:00
if ( m_last_working_tracker > = 0 )
{
2009-06-10 10:42:05 +02:00
TORRENT_ASSERT ( m_last_working_tracker < int ( m_trackers . size ( ) ) ) ;
2011-02-01 10:48:28 +01:00
st - > current_tracker = m_trackers [ m_last_working_tracker ] . url ;
2005-03-11 18:21:56 +01:00
}
2008-11-29 09:38:40 +01:00
else
2008-11-26 02:31:54 +01:00
{
2008-11-29 09:38:40 +01:00
std : : vector < announce_entry > : : const_iterator i ;
for ( i = m_trackers . begin ( ) ; i ! = m_trackers . end ( ) ; + + i )
2010-03-04 20:15:23 +01:00
{
if ( ! i - > updating ) continue ;
2011-02-01 10:48:28 +01:00
st - > current_tracker = i - > url ;
2010-03-04 20:15:23 +01:00
break ;
}
2008-11-26 02:31:54 +01:00
}
2005-03-11 18:21:56 +01:00
2011-08-07 09:19:18 +02:00
if ( ( flags & torrent_handle : : query_verified_pieces ) )
{
st - > verified_pieces = m_verified ;
}
2011-02-01 10:48:28 +01:00
st - > num_uploads = m_num_uploads ;
st - > uploads_limit = m_max_uploads ;
st - > num_connections = int ( m_connections . size ( ) ) ;
st - > connections_limit = m_max_connections ;
2004-06-14 01:30:42 +02:00
// if we don't have any metadata, stop here
2011-02-01 10:48:28 +01:00
st - > queue_position = queue_position ( ) ;
st - > need_save_resume = need_save_resume_data ( ) ;
2011-02-27 18:26:57 +01:00
st - > ip_filter_applies = m_apply_ip_filter ;
2010-11-06 19:04:07 +01:00
2011-02-01 10:48:28 +01:00
st - > state = ( torrent_status : : state_t ) m_state ;
2008-03-08 07:06:31 +01:00
2004-06-14 01:30:42 +02:00
if ( ! valid_metadata ( ) )
{
2011-02-01 10:48:28 +01:00
st - > state = torrent_status : : downloading_metadata ;
st - > progress_ppm = m_progress_ppm ;
2009-07-19 06:59:27 +02:00
# if !TORRENT_NO_FPU
2011-02-01 10:48:28 +01:00
st - > progress = m_progress_ppm / 1000000.f ;
2009-07-19 06:59:27 +02:00
# endif
2011-02-01 10:48:28 +01:00
st - > block_size = 0 ;
return ;
2004-06-14 01:30:42 +02:00
}
2011-02-01 10:48:28 +01:00
st - > block_size = block_size ( ) ;
2006-04-25 23:04:48 +02:00
2008-03-08 07:06:31 +01:00
if ( m_state = = torrent_status : : checking_files )
2009-07-19 06:59:27 +02:00
{
2011-02-01 10:48:28 +01:00
st - > progress_ppm = m_progress_ppm ;
2009-07-19 06:59:27 +02:00
# if !TORRENT_NO_FPU
2011-02-01 10:48:28 +01:00
st - > progress = m_progress_ppm / 1000000.f ;
2009-07-19 06:59:27 +02:00
# endif
}
2011-02-01 10:48:28 +01:00
else if ( st - > total_wanted = = 0 )
2009-07-19 06:59:27 +02:00
{
2011-02-01 10:48:28 +01:00
st - > progress_ppm = 1000000 ;
st - > progress = 1.f ;
2009-07-19 06:59:27 +02:00
}
else
{
2011-02-01 10:48:28 +01:00
st - > progress_ppm = st - > total_wanted_done * 1000000
/ st - > total_wanted ;
2009-07-19 06:59:27 +02:00
# if !TORRENT_NO_FPU
2011-02-01 10:48:28 +01:00
st - > progress = st - > progress_ppm / 1000000.f ;
2009-07-19 06:59:27 +02:00
# endif
}
2004-01-15 02:01:09 +01:00
2008-06-07 04:58:28 +02:00
if ( has_picker ( ) )
{
2011-02-01 10:48:28 +01:00
st - > sparse_regions = m_picker - > sparse_regions ( ) ;
2008-06-07 04:58:28 +02:00
int num_pieces = m_picker - > num_pieces ( ) ;
2011-02-01 10:48:28 +01:00
st - > pieces . resize ( num_pieces , false ) ;
2008-06-07 04:58:28 +02:00
for ( int i = 0 ; i < num_pieces ; + + i )
2011-02-01 10:48:28 +01:00
if ( m_picker - > have_piece ( i ) ) st - > pieces . set_bit ( i ) ;
2008-06-07 04:58:28 +02:00
}
2011-07-26 03:52:51 +02:00
else if ( is_seed ( ) )
{
2011-07-26 20:44:39 +02:00
int num_pieces = m_torrent_file - > num_pieces ( ) ;
2011-07-26 03:52:51 +02:00
st - > pieces . resize ( num_pieces , true ) ;
}
2011-02-01 10:48:28 +01:00
st - > num_pieces = num_have ( ) ;
st - > num_seeds = num_seeds ( ) ;
2010-03-04 20:15:23 +01:00
if ( ( flags & torrent_handle : : query_distributed_copies ) & & m_picker . get ( ) )
2009-07-19 06:59:27 +02:00
{
2011-02-01 10:48:28 +01:00
boost : : tie ( st - > distributed_full_copies , st - > distributed_fraction ) =
2009-07-19 06:59:27 +02:00
m_picker - > distributed_copies ( ) ;
# if TORRENT_NO_FPU
2011-02-01 10:48:28 +01:00
st - > distributed_copies = - 1.f ;
2009-07-19 06:59:27 +02:00
# else
2011-02-01 10:48:28 +01:00
st - > distributed_copies = st - > distributed_full_copies
+ float ( st - > distributed_fraction ) / 1000 ;
2009-07-19 06:59:27 +02:00
# endif
}
2006-12-04 13:20:34 +01:00
else
2009-07-19 06:59:27 +02:00
{
2011-02-01 10:48:28 +01:00
st - > distributed_full_copies = - 1 ;
st - > distributed_fraction = - 1 ;
st - > distributed_copies = - 1.f ;
2009-07-19 06:59:27 +02:00
}
2010-03-19 19:39:51 +01:00
if ( flags & torrent_handle : : query_last_seen_complete )
{
time_t last = last_seen_complete ( ) ;
2010-03-21 03:13:56 +01:00
for ( std : : set < peer_connection * > : : const_iterator i = m_connections . begin ( )
2011-01-25 09:20:22 +01:00
, end ( m_connections . end ( ) ) ; i ! = end ; + + i )
2010-03-19 19:39:51 +01:00
{
last = ( std : : max ) ( last , ( * i ) - > last_seen_complete ( ) ) ;
}
2011-02-01 10:48:28 +01:00
st - > last_seen_complete = last ;
2010-03-19 19:39:51 +01:00
}
else
{
2011-02-01 10:48:28 +01:00
st - > last_seen_complete = 0 ;
2010-03-19 19:39:51 +01:00
}
2003-10-26 18:35:23 +01:00
}
2011-11-16 03:29:59 +01:00
void torrent : : add_redundant_bytes ( int b , torrent : : wasted_reason_t reason )
2008-07-11 09:30:04 +02:00
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-07-11 09:30:04 +02:00
TORRENT_ASSERT ( b > 0 ) ;
m_total_redundant_bytes + = b ;
2011-11-16 03:29:59 +01:00
m_ses . add_redundant_bytes ( b , reason ) ;
2010-11-23 21:36:27 +01:00
// TORRENT_ASSERT(m_total_redundant_bytes + m_total_failed_bytes
// <= m_stat.total_payload_download());
2008-07-11 09:30:04 +02:00
}
void torrent : : add_failed_bytes ( int b )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2008-07-11 09:30:04 +02:00
TORRENT_ASSERT ( b > 0 ) ;
m_total_failed_bytes + = b ;
m_ses . add_failed_bytes ( b ) ;
2010-10-27 08:39:18 +02:00
// TORRENT_ASSERT(m_total_redundant_bytes + m_total_failed_bytes
// <= m_stat.total_payload_download());
2008-07-11 09:30:04 +02:00
}
2004-08-05 15:56:26 +02:00
int torrent : : num_seeds ( ) const
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2006-04-25 23:04:48 +02:00
INVARIANT_CHECK ;
2009-08-30 09:38:52 +02:00
int ret = 0 ;
2009-09-01 15:36:30 +02:00
for ( std : : set < peer_connection * > : : const_iterator i = m_connections . begin ( )
2009-08-30 09:38:52 +02:00
, end ( m_connections . end ( ) ) ; i ! = end ; + + i )
if ( ( * i ) - > is_seed ( ) ) + + ret ;
return ret ;
2004-09-12 15:53:00 +02:00
}
2004-01-26 11:29:00 +01:00
// TODO: with some response codes, we should just consider
2003-12-22 08:14:35 +01:00
// the tracker as a failure and not retry
// it anymore
2007-11-20 23:46:27 +01:00
void torrent : : tracker_request_error ( tracker_request const & r
2010-02-23 22:53:45 +01:00
, int response_code , error_code const & ec , const std : : string & msg
2009-12-21 10:47:32 +01:00
, int retry_interval )
2003-12-22 08:14:35 +01:00
{
2010-07-14 06:16:38 +02:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-03-31 00:00:26 +02:00
2006-05-28 21:03:54 +02:00
INVARIANT_CHECK ;
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2010-02-23 22:53:45 +01:00
debug_log ( " *** tracker error: " + ec . message ( ) + " " + msg ) ;
2003-12-22 08:14:35 +01:00
# endif
2008-07-06 14:22:56 +02:00
if ( r . kind = = tracker_request : : announce_request )
2003-12-22 08:14:35 +01:00
{
2008-11-29 09:38:40 +01:00
announce_entry * ae = find_tracker ( r ) ;
if ( ae )
2007-11-20 23:46:27 +01:00
{
2009-12-21 10:47:32 +01:00
ae - > failed ( retry_interval ) ;
2010-04-13 06:37:39 +02:00
ae - > last_error = ec ;
ae - > message = msg ;
2008-11-29 09:38:40 +01:00
int tracker_index = ae - & m_trackers [ 0 ] ;
2011-08-18 01:01:35 +02:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
debug_log ( " *** increment tracker fail count [ "
+ std : : string ( to_string ( ae - > fails ) . elems ) + " ] " ) ;
# endif
2008-11-29 09:38:40 +01:00
deprioritize_tracker ( tracker_index ) ;
2007-11-20 23:46:27 +01:00
}
2008-11-29 09:38:40 +01:00
if ( m_ses . m_alerts . should_post < tracker_error_alert > ( ) )
2008-11-27 21:51:59 +01:00
{
2008-11-29 09:38:40 +01:00
m_ses . m_alerts . post_alert ( tracker_error_alert ( get_handle ( )
2010-02-23 22:53:45 +01:00
, ae ? ae - > fails : 0 , response_code , r . url , ec , msg ) ) ;
2008-11-27 21:51:59 +01:00
}
2008-07-06 14:22:56 +02:00
}
else if ( r . kind = = tracker_request : : scrape_request )
{
if ( m_ses . m_alerts . should_post < scrape_failed_alert > ( ) )
2007-11-20 23:46:27 +01:00
{
2010-02-23 22:53:45 +01:00
m_ses . m_alerts . post_alert ( scrape_failed_alert ( get_handle ( ) , r . url , ec ) ) ;
2007-11-20 23:46:27 +01:00
}
2003-12-22 08:14:35 +01:00
}
2010-05-17 04:06:30 +02:00
// announce to the next working tracker
2011-09-13 04:38:50 +02:00
if ( ( ! m_abort & & ! is_paused ( ) ) | | r . event = = tracker_request : : stopped )
2011-09-13 04:23:18 +02:00
announce_with_tracker ( r . event ) ;
2010-05-03 10:24:30 +02:00
update_tracker_timer ( time_now ( ) ) ;
2003-12-22 08:14:35 +01:00
}
2008-02-07 08:09:52 +01:00
# if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2003-11-20 20:58:29 +01:00
void torrent : : debug_log ( const std : : string & line )
{
2010-12-04 23:20:31 +01:00
TORRENT_ASSERT ( m_ses . is_network_thread ( ) ) ;
2007-10-26 09:14:19 +02:00
( * m_ses . m_logger ) < < time_now_string ( ) < < " " < < line < < " \n " ;
2003-11-20 20:58:29 +01:00
}
# endif
2005-06-15 14:54:35 +02:00
}