mirror of
https://git.deluge-torrent.org/deluge
synced 2025-08-21 09:38:44 +00:00
Sync to libtorrent revision 1415
This commit is contained in:
parent
5145dafeae
commit
626e7657d0
26 changed files with 756 additions and 469 deletions
|
@ -130,6 +130,10 @@ char const* session_remove_torrent_doc =
|
||||||
"Close all peer connections associated with the torrent and tell the\n"
|
"Close all peer connections associated with the torrent and tell the\n"
|
||||||
"tracker that we've stopped participating in the swarm.";
|
"tracker that we've stopped participating in the swarm.";
|
||||||
|
|
||||||
|
char const* session_download_rate_limit_doc =
|
||||||
|
"";
|
||||||
|
char const* session_upload_rate_limit_doc =
|
||||||
|
"";
|
||||||
char const* session_set_download_rate_limit_doc =
|
char const* session_set_download_rate_limit_doc =
|
||||||
"";
|
"";
|
||||||
char const* session_set_upload_rate_limit_doc =
|
char const* session_set_upload_rate_limit_doc =
|
||||||
|
|
|
@ -38,7 +38,9 @@ extern char const* session_dht_state_doc;
|
||||||
extern char const* session_add_torrent_doc;
|
extern char const* session_add_torrent_doc;
|
||||||
extern char const* session_remove_torrent_doc;
|
extern char const* session_remove_torrent_doc;
|
||||||
extern char const* session_set_download_rate_limit_doc;
|
extern char const* session_set_download_rate_limit_doc;
|
||||||
|
extern char const* session_download_rate_limit_doc;
|
||||||
extern char const* session_set_upload_rate_limit_doc;
|
extern char const* session_set_upload_rate_limit_doc;
|
||||||
|
extern char const* session_upload_rate_limit_doc;
|
||||||
extern char const* session_set_max_uploads_doc;
|
extern char const* session_set_max_uploads_doc;
|
||||||
extern char const* session_set_max_connections_doc;
|
extern char const* session_set_max_connections_doc;
|
||||||
extern char const* session_set_max_half_open_connections_doc;
|
extern char const* session_set_max_half_open_connections_doc;
|
||||||
|
@ -176,10 +178,20 @@ void bind_session()
|
||||||
"set_download_rate_limit", allow_threads(&session::set_download_rate_limit)
|
"set_download_rate_limit", allow_threads(&session::set_download_rate_limit)
|
||||||
, session_set_download_rate_limit_doc
|
, session_set_download_rate_limit_doc
|
||||||
)
|
)
|
||||||
|
.def(
|
||||||
|
"download_rate_limit", allow_threads(&session::download_rate_limit)
|
||||||
|
, session_download_rate_limit_doc
|
||||||
|
)
|
||||||
|
|
||||||
.def(
|
.def(
|
||||||
"set_upload_rate_limit", allow_threads(&session::set_upload_rate_limit)
|
"set_upload_rate_limit", allow_threads(&session::set_upload_rate_limit)
|
||||||
, session_set_upload_rate_limit_doc
|
, session_set_upload_rate_limit_doc
|
||||||
)
|
)
|
||||||
|
.def(
|
||||||
|
"upload_rate_limit", allow_threads(&session::upload_rate_limit)
|
||||||
|
, session_upload_rate_limit_doc
|
||||||
|
)
|
||||||
|
|
||||||
.def(
|
.def(
|
||||||
"set_max_uploads", allow_threads(&session::set_max_uploads)
|
"set_max_uploads", allow_threads(&session::set_max_uploads)
|
||||||
, session_set_max_uploads_doc
|
, session_set_max_uploads_doc
|
||||||
|
|
|
@ -64,6 +64,30 @@ list get_peer_info(torrent_handle const& handle)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void prioritize_files(torrent_handle& info, object o)
|
||||||
|
{
|
||||||
|
|
||||||
|
std::vector<int> result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
object iter_obj = object( handle<>( PyObject_GetIter( o.ptr() ) ));
|
||||||
|
while( 1 )
|
||||||
|
{
|
||||||
|
object obj = extract<object>( iter_obj.attr( "next" )() );
|
||||||
|
result.push_back(extract<int const>( obj ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( error_already_set )
|
||||||
|
{
|
||||||
|
PyErr_Clear();
|
||||||
|
info.prioritize_files(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void replace_trackers(torrent_handle& info, object trackers)
|
void replace_trackers(torrent_handle& info, object trackers)
|
||||||
{
|
{
|
||||||
object iter(trackers.attr("__iter__")());
|
object iter(trackers.attr("__iter__")());
|
||||||
|
@ -106,7 +130,9 @@ list get_download_queue(torrent_handle& handle)
|
||||||
{
|
{
|
||||||
dict block_info;
|
dict block_info;
|
||||||
block_info["state"] = i->blocks[k].state;
|
block_info["state"] = i->blocks[k].state;
|
||||||
block_info["num_downloads"] = i->blocks[k].num_downloads;
|
block_info["num_peers"] = i->blocks[k].num_peers;
|
||||||
|
block_info["bytes_progress"] = i->blocks[k].bytes_progress;
|
||||||
|
block_info["block_size"] = i->blocks[k].block_size;
|
||||||
// block_info["peer"] = i->info[k].peer;
|
// block_info["peer"] = i->info[k].peer;
|
||||||
block_list.append(block_info);
|
block_list.append(block_info);
|
||||||
}
|
}
|
||||||
|
@ -124,6 +150,9 @@ void bind_torrent_handle()
|
||||||
void (torrent_handle::*force_reannounce1)(boost::posix_time::time_duration) const
|
void (torrent_handle::*force_reannounce1)(boost::posix_time::time_duration) const
|
||||||
= &torrent_handle::force_reannounce;
|
= &torrent_handle::force_reannounce;
|
||||||
|
|
||||||
|
int (torrent_handle::*piece_priority0)(int) const = &torrent_handle::piece_priority;
|
||||||
|
void (torrent_handle::*piece_priority1)(int, int) const = &torrent_handle::piece_priority;
|
||||||
|
|
||||||
return_value_policy<copy_const_reference> copy;
|
return_value_policy<copy_const_reference> copy;
|
||||||
|
|
||||||
#define _ allow_threads
|
#define _ allow_threads
|
||||||
|
@ -148,6 +177,8 @@ void bind_torrent_handle()
|
||||||
.def("is_paused", _(&torrent_handle::is_paused))
|
.def("is_paused", _(&torrent_handle::is_paused))
|
||||||
.def("is_seed", _(&torrent_handle::is_seed))
|
.def("is_seed", _(&torrent_handle::is_seed))
|
||||||
.def("filter_piece", _(&torrent_handle::filter_piece))
|
.def("filter_piece", _(&torrent_handle::filter_piece))
|
||||||
|
.def("piece_priority", _(piece_priority0))
|
||||||
|
.def("piece_priority", _(piece_priority1))
|
||||||
.def("is_piece_filtered", _(&torrent_handle::is_piece_filtered))
|
.def("is_piece_filtered", _(&torrent_handle::is_piece_filtered))
|
||||||
.def("has_metadata", _(&torrent_handle::has_metadata))
|
.def("has_metadata", _(&torrent_handle::has_metadata))
|
||||||
.def("save_path", _(&torrent_handle::save_path))
|
.def("save_path", _(&torrent_handle::save_path))
|
||||||
|
@ -156,6 +187,7 @@ void bind_torrent_handle()
|
||||||
.def("file_progress", file_progress)
|
.def("file_progress", file_progress)
|
||||||
.def("trackers", range(begin_trackers, end_trackers))
|
.def("trackers", range(begin_trackers, end_trackers))
|
||||||
.def("replace_trackers", replace_trackers)
|
.def("replace_trackers", replace_trackers)
|
||||||
|
.def("prioritize_files", prioritize_files)
|
||||||
.def("get_peer_info", get_peer_info)
|
.def("get_peer_info", get_peer_info)
|
||||||
.def("get_download_queue", get_download_queue)
|
.def("get_download_queue", get_download_queue)
|
||||||
;
|
;
|
||||||
|
|
|
@ -71,6 +71,7 @@ void bind_torrent_info()
|
||||||
.def("hash_for_piece", &torrent_info::hash_for_piece, copy)
|
.def("hash_for_piece", &torrent_info::hash_for_piece, copy)
|
||||||
.def("piece_size", &torrent_info::piece_size)
|
.def("piece_size", &torrent_info::piece_size)
|
||||||
|
|
||||||
|
.def("num_files", &torrent_info::num_files)
|
||||||
.def("file_at", &torrent_info::file_at, return_internal_reference<>())
|
.def("file_at", &torrent_info::file_at, return_internal_reference<>())
|
||||||
.def("files", range(&torrent_info::begin_files, &torrent_info::end_files))
|
.def("files", range(&torrent_info::begin_files, &torrent_info::end_files))
|
||||||
|
|
||||||
|
|
|
@ -391,10 +391,6 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't hand out chunks larger than the throttle
|
|
||||||
// per second on the torrent
|
|
||||||
assert(qe.max_block_size <= t->bandwidth_throttle(m_channel));
|
|
||||||
|
|
||||||
// so, hand out max_assignable, but no more than
|
// so, hand out max_assignable, but no more than
|
||||||
// the available bandwidth (amount) and no more
|
// the available bandwidth (amount) and no more
|
||||||
// than the max_bandwidth_block_size
|
// than the max_bandwidth_block_size
|
||||||
|
@ -402,6 +398,7 @@ private:
|
||||||
, amount);
|
, amount);
|
||||||
assert(hand_out_amount > 0);
|
assert(hand_out_amount > 0);
|
||||||
amount -= hand_out_amount;
|
amount -= hand_out_amount;
|
||||||
|
assert(hand_out_amount <= qe.max_block_size);
|
||||||
t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size);
|
t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size);
|
||||||
qe.peer->assign_bandwidth(m_channel, hand_out_amount);
|
qe.peer->assign_bandwidth(m_channel, hand_out_amount);
|
||||||
add_history_entry(history_entry<PeerConnection, Torrent>(
|
add_history_entry(history_entry<PeerConnection, Torrent>(
|
||||||
|
|
|
@ -202,7 +202,7 @@ namespace libtorrent
|
||||||
void write_metadata_request(std::pair<int, int> req);
|
void write_metadata_request(std::pair<int, int> req);
|
||||||
void write_keepalive();
|
void write_keepalive();
|
||||||
void write_dht_port(int listen_port);
|
void write_dht_port(int listen_port);
|
||||||
void on_connected() {}
|
void on_connected();
|
||||||
void on_metadata();
|
void on_metadata();
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -370,6 +370,8 @@ namespace libtorrent
|
||||||
bool m_sent_bitfield;
|
bool m_sent_bitfield;
|
||||||
|
|
||||||
bool m_in_constructor;
|
bool m_in_constructor;
|
||||||
|
|
||||||
|
bool m_sent_handshake;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -88,6 +88,9 @@ private:
|
||||||
int m_half_open_limit;
|
int m_half_open_limit;
|
||||||
|
|
||||||
deadline_timer m_timer;
|
deadline_timer m_timer;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
bool m_in_timeout_function;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,6 +395,9 @@ namespace libtorrent
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
buffer::interval wr_recv_buffer()
|
buffer::interval wr_recv_buffer()
|
||||||
{
|
{
|
||||||
|
#if defined _SECURE_SCL && _SECURE_SCL > 0
|
||||||
|
if (m_recv_buffer.empty()) return buffer::interval(0,0);
|
||||||
|
#endif
|
||||||
return buffer::interval(&m_recv_buffer[0]
|
return buffer::interval(&m_recv_buffer[0]
|
||||||
, &m_recv_buffer[0] + m_recv_pos);
|
, &m_recv_buffer[0] + m_recv_pos);
|
||||||
}
|
}
|
||||||
|
@ -402,6 +405,9 @@ namespace libtorrent
|
||||||
|
|
||||||
buffer::const_interval receive_buffer() const
|
buffer::const_interval receive_buffer() const
|
||||||
{
|
{
|
||||||
|
#if defined _SECURE_SCL && _SECURE_SCL > 0
|
||||||
|
if (m_recv_buffer.empty()) return buffer::const_interval(0,0);
|
||||||
|
#endif
|
||||||
return buffer::const_interval(&m_recv_buffer[0]
|
return buffer::const_interval(&m_recv_buffer[0]
|
||||||
, &m_recv_buffer[0] + m_recv_pos);
|
, &m_recv_buffer[0] + m_recv_pos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#pragma warning(push, 1)
|
#pragma warning(push, 1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
|
||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -90,12 +89,15 @@ namespace libtorrent
|
||||||
|
|
||||||
struct block_info
|
struct block_info
|
||||||
{
|
{
|
||||||
block_info(): num_downloads(0), state(state_none) {}
|
block_info(): peer(0), num_peers(0), state(state_none) {}
|
||||||
// the peer this block was requested or
|
// the peer this block was requested or
|
||||||
// downloaded from
|
// downloaded from. This is a pointer to
|
||||||
tcp::endpoint peer;
|
// a policy::peer object
|
||||||
// the number of times this block has been downloaded
|
void* peer;
|
||||||
unsigned num_downloads:14;
|
// the number of peers that has this block in their
|
||||||
|
// download or request queues
|
||||||
|
unsigned num_peers:14;
|
||||||
|
// the state of this block
|
||||||
enum { state_none, state_requested, state_writing, state_finished };
|
enum { state_none, state_requested, state_writing, state_finished };
|
||||||
unsigned state:2;
|
unsigned state:2;
|
||||||
};
|
};
|
||||||
|
@ -185,12 +187,17 @@ namespace libtorrent
|
||||||
// decides to download a piece, it must mark it as being downloaded
|
// decides to download a piece, it must mark it as being downloaded
|
||||||
// itself, by using the mark_as_downloading() member function.
|
// itself, by using the mark_as_downloading() member function.
|
||||||
// THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
|
// THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
|
||||||
// The last argument is the tcp::endpoint of the peer that we'll download
|
// The last argument is the policy::peer pointer for the peer that
|
||||||
// from.
|
// we'll download from.
|
||||||
void pick_pieces(const std::vector<bool>& pieces
|
void pick_pieces(const std::vector<bool>& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, int num_pieces, bool prefer_whole_pieces
|
, int num_pieces, bool prefer_whole_pieces
|
||||||
, tcp::endpoint peer, piece_state_t speed) const;
|
, void* peer, piece_state_t speed
|
||||||
|
, bool rarest_first) const;
|
||||||
|
|
||||||
|
// clears the peer pointer in all downloading pieces with this
|
||||||
|
// peer pointer
|
||||||
|
void clear_peer(void* peer);
|
||||||
|
|
||||||
// returns true if any client is currently downloading this
|
// returns true if any client is currently downloading this
|
||||||
// piece-block, or if it's queued for downloading by some client
|
// piece-block, or if it's queued for downloading by some client
|
||||||
|
@ -202,10 +209,11 @@ namespace libtorrent
|
||||||
bool is_finished(piece_block block) const;
|
bool is_finished(piece_block block) const;
|
||||||
|
|
||||||
// marks this piece-block as queued for downloading
|
// marks this piece-block as queued for downloading
|
||||||
void mark_as_downloading(piece_block block, tcp::endpoint const& peer
|
void mark_as_downloading(piece_block block, void* peer
|
||||||
, piece_state_t s);
|
, piece_state_t s);
|
||||||
void mark_as_writing(piece_block block, tcp::endpoint const& peer);
|
void mark_as_writing(piece_block block, void* peer);
|
||||||
void mark_as_finished(piece_block block, tcp::endpoint const& peer);
|
void mark_as_finished(piece_block block, void* peer);
|
||||||
|
int num_peers(piece_block block) const;
|
||||||
|
|
||||||
// if a piece had a hash-failure, it must be restored and
|
// if a piece had a hash-failure, it must be restored and
|
||||||
// made available for redownloading
|
// made available for redownloading
|
||||||
|
@ -224,12 +232,12 @@ namespace libtorrent
|
||||||
// the hash-check yet
|
// the hash-check yet
|
||||||
int unverified_blocks() const;
|
int unverified_blocks() const;
|
||||||
|
|
||||||
void get_downloaders(std::vector<tcp::endpoint>& d, int index) const;
|
void get_downloaders(std::vector<void*>& d, int index) const;
|
||||||
|
|
||||||
std::vector<downloading_piece> const& get_download_queue() const
|
std::vector<downloading_piece> const& get_download_queue() const
|
||||||
{ return m_downloads; }
|
{ return m_downloads; }
|
||||||
|
|
||||||
boost::optional<tcp::endpoint> get_downloader(piece_block block) const;
|
void* get_downloader(piece_block block) const;
|
||||||
|
|
||||||
// the number of filtered pieces we don't have
|
// the number of filtered pieces we don't have
|
||||||
int num_filtered() const { return m_num_filtered; }
|
int num_filtered() const { return m_num_filtered; }
|
||||||
|
@ -271,7 +279,8 @@ namespace libtorrent
|
||||||
assert(index_ >= 0);
|
assert(index_ >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// selects which vector to look in
|
// the number of peers that has this piece
|
||||||
|
// (availability)
|
||||||
unsigned peer_count : 10;
|
unsigned peer_count : 10;
|
||||||
// is 1 if the piece is marked as being downloaded
|
// is 1 if the piece is marked as being downloaded
|
||||||
unsigned downloading : 1;
|
unsigned downloading : 1;
|
||||||
|
@ -342,13 +351,15 @@ namespace libtorrent
|
||||||
|
|
||||||
void add(int index);
|
void add(int index);
|
||||||
void move(int vec_index, int elem_index);
|
void move(int vec_index, int elem_index);
|
||||||
|
void sort_piece(std::vector<downloading_piece>::iterator dp);
|
||||||
|
|
||||||
int add_interesting_blocks(const std::vector<int>& piece_list
|
int add_interesting_blocks(const std::vector<int>& piece_list
|
||||||
, const std::vector<bool>& pieces
|
, const std::vector<bool>& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, std::vector<piece_block>& backup_blocks
|
, std::vector<piece_block>& backup_blocks
|
||||||
, int num_blocks, bool prefer_whole_pieces
|
, int num_blocks, bool prefer_whole_pieces
|
||||||
, tcp::endpoint peer, piece_state_t speed) const;
|
, void* peer, piece_state_t speed
|
||||||
|
, bool ignore_downloading_pieces) const;
|
||||||
|
|
||||||
downloading_piece& add_download_piece();
|
downloading_piece& add_download_piece();
|
||||||
void erase_download_piece(std::vector<downloading_piece>::iterator i);
|
void erase_download_piece(std::vector<downloading_piece>::iterator i);
|
||||||
|
|
|
@ -68,10 +68,7 @@ namespace libtorrent
|
||||||
free_upload_amount = 4 * 16 * 1024
|
free_upload_amount = 4 * 16 * 1024
|
||||||
};
|
};
|
||||||
|
|
||||||
void request_a_block(
|
void request_a_block(torrent& t, peer_connection& c);
|
||||||
torrent& t
|
|
||||||
, peer_connection& c
|
|
||||||
, std::vector<peer_connection*> ignore = std::vector<peer_connection*>());
|
|
||||||
|
|
||||||
class TORRENT_EXPORT policy
|
class TORRENT_EXPORT policy
|
||||||
{
|
{
|
||||||
|
@ -121,9 +118,9 @@ namespace libtorrent
|
||||||
|
|
||||||
struct peer
|
struct peer
|
||||||
{
|
{
|
||||||
enum connection_type { not_connectable,connectable };
|
enum connection_type { not_connectable, connectable };
|
||||||
|
|
||||||
peer(const tcp::endpoint& ip, connection_type t, int src);
|
peer(tcp::endpoint const& ip, connection_type t, int src);
|
||||||
|
|
||||||
size_type total_download() const;
|
size_type total_download() const;
|
||||||
size_type total_upload() const;
|
size_type total_upload() const;
|
||||||
|
|
|
@ -107,6 +107,7 @@ namespace libtorrent
|
||||||
, inactivity_timeout(600)
|
, inactivity_timeout(600)
|
||||||
, unchoke_interval(20)
|
, unchoke_interval(20)
|
||||||
, num_want(200)
|
, num_want(200)
|
||||||
|
, initial_picker_threshold(4)
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
, use_dht_as_fallback(true)
|
, use_dht_as_fallback(true)
|
||||||
#endif
|
#endif
|
||||||
|
@ -246,6 +247,10 @@ namespace libtorrent
|
||||||
// the num want sent to trackers
|
// the num want sent to trackers
|
||||||
int num_want;
|
int num_want;
|
||||||
|
|
||||||
|
// while we have fewer pieces than this, pick
|
||||||
|
// random pieces instead of rarest first.
|
||||||
|
int initial_picker_threshold;
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
// while this is true, the dht will note be used unless the
|
// while this is true, the dht will note be used unless the
|
||||||
// tracker is online
|
// tracker is online
|
||||||
|
|
|
@ -131,6 +131,8 @@ namespace libtorrent
|
||||||
// transfers from earlier connections.
|
// transfers from earlier connections.
|
||||||
void add_stat(size_type downloaded, size_type uploaded)
|
void add_stat(size_type downloaded, size_type uploaded)
|
||||||
{
|
{
|
||||||
|
assert(downloaded >= 0);
|
||||||
|
assert(uploaded >= 0);
|
||||||
m_total_download_payload += downloaded;
|
m_total_download_payload += downloaded;
|
||||||
m_total_upload_payload += uploaded;
|
m_total_upload_payload += uploaded;
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,6 +262,8 @@ namespace libtorrent
|
||||||
// decreased in the piece_picker
|
// decreased in the piece_picker
|
||||||
void remove_peer(peer_connection* p);
|
void remove_peer(peer_connection* p);
|
||||||
|
|
||||||
|
void cancel_block(piece_block block);
|
||||||
|
|
||||||
bool want_more_peers() const;
|
bool want_more_peers() const;
|
||||||
bool try_connect_peer();
|
bool try_connect_peer();
|
||||||
|
|
||||||
|
@ -272,6 +274,18 @@ namespace libtorrent
|
||||||
return i->second;
|
return i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void connection_for(address const& a, std::vector<peer_connection*>& pc)
|
||||||
|
{
|
||||||
|
for (peer_iterator i = m_connections.begin()
|
||||||
|
, end(m_connections.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
if (i->first.address() == a) pc.push_back(i->second);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// the number of peers that belong to this torrent
|
// the number of peers that belong to this torrent
|
||||||
int num_peers() const { return (int)m_connections.size(); }
|
int num_peers() const { return (int)m_connections.size(); }
|
||||||
int num_seeds() const;
|
int num_seeds() const;
|
||||||
|
|
|
@ -101,6 +101,11 @@ namespace libtorrent
|
||||||
, num_seeds(0)
|
, num_seeds(0)
|
||||||
, distributed_copies(0.f)
|
, distributed_copies(0.f)
|
||||||
, block_size(0)
|
, block_size(0)
|
||||||
|
, num_uploads(0)
|
||||||
|
, num_connections(0)
|
||||||
|
, uploads_limit(0)
|
||||||
|
, connections_limit(0)
|
||||||
|
, compact_mode(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
enum state_t
|
enum state_t
|
||||||
|
@ -202,6 +207,15 @@ namespace libtorrent
|
||||||
// the number of bytes each piece request asks for
|
// the number of bytes each piece request asks for
|
||||||
// and each bit in the download queue bitfield represents
|
// and each bit in the download queue bitfield represents
|
||||||
int block_size;
|
int block_size;
|
||||||
|
|
||||||
|
int num_uploads;
|
||||||
|
int num_connections;
|
||||||
|
int uploads_limit;
|
||||||
|
int connections_limit;
|
||||||
|
|
||||||
|
// true if the torrent is saved in compact mode
|
||||||
|
// false if it is saved in full allocation mode
|
||||||
|
bool compact_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT block_info
|
struct TORRENT_EXPORT block_info
|
||||||
|
@ -210,8 +224,16 @@ namespace libtorrent
|
||||||
{ none, requested, writing, finished };
|
{ none, requested, writing, finished };
|
||||||
|
|
||||||
tcp::endpoint peer;
|
tcp::endpoint peer;
|
||||||
|
// number of bytes downloaded in this block
|
||||||
|
unsigned bytes_progress:16;
|
||||||
|
// the total number of bytes in this block
|
||||||
|
unsigned block_size:16;
|
||||||
|
// the state this block is in (see block_state_t)
|
||||||
unsigned state:2;
|
unsigned state:2;
|
||||||
unsigned num_downloads:14;
|
// the number of peers that has requested this block
|
||||||
|
// typically 0 or 1. If > 1, this block is in
|
||||||
|
// end game mode
|
||||||
|
unsigned num_peers:14;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT partial_piece_info
|
struct TORRENT_EXPORT partial_piece_info
|
||||||
|
|
|
@ -13,7 +13,7 @@ kademlia/traversal_algorithm.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libtorrent_la_SOURCES = allocate_resources.cpp \
|
libtorrent_la_SOURCES = allocate_resources.cpp \
|
||||||
bandwidth_manager.cpp entry.cpp escape_string.cpp \
|
entry.cpp escape_string.cpp \
|
||||||
peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \
|
peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \
|
||||||
natpmp.cpp piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp \
|
natpmp.cpp piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp \
|
||||||
stat.cpp storage.cpp torrent.cpp torrent_handle.cpp pe_crypto.cpp \
|
stat.cpp storage.cpp torrent.cpp torrent_handle.cpp pe_crypto.cpp \
|
||||||
|
|
|
@ -102,12 +102,73 @@ namespace libtorrent
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
, m_sent_bitfield(false)
|
, m_sent_bitfield(false)
|
||||||
, m_in_constructor(true)
|
, m_in_constructor(true)
|
||||||
|
, m_sent_handshake(false)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << "*** bt_peer_connection\n";
|
(*m_logger) << "*** bt_peer_connection\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_in_constructor = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_peer_connection::bt_peer_connection(
|
||||||
|
session_impl& ses
|
||||||
|
, boost::shared_ptr<socket_type> s
|
||||||
|
, policy::peer* peerinfo)
|
||||||
|
: peer_connection(ses, s, peerinfo)
|
||||||
|
, m_state(read_protocol_identifier)
|
||||||
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
, m_supports_extensions(false)
|
||||||
|
#endif
|
||||||
|
, m_supports_dht_port(false)
|
||||||
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
|
, m_encrypted(false)
|
||||||
|
, m_rc4_encrypted(false)
|
||||||
|
, m_sync_bytes_read(0)
|
||||||
|
, m_enc_send_buffer(0, 0)
|
||||||
|
#endif
|
||||||
|
#ifndef NDEBUG
|
||||||
|
, m_sent_bitfield(false)
|
||||||
|
, m_in_constructor(true)
|
||||||
|
, m_sent_handshake(false)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
|
// we are not attached to any torrent yet.
|
||||||
|
// we have to wait for the handshake to see
|
||||||
|
// which torrent the connector want's to connect to
|
||||||
|
|
||||||
|
|
||||||
|
// upload bandwidth will only be given to connections
|
||||||
|
// that are part of a torrent. Since this is an incoming
|
||||||
|
// connection, we have to give it some initial bandwidth
|
||||||
|
// to send the handshake.
|
||||||
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
|
m_bandwidth_limit[download_channel].assign(2048);
|
||||||
|
m_bandwidth_limit[upload_channel].assign(2048);
|
||||||
|
#else
|
||||||
|
m_bandwidth_limit[download_channel].assign(80);
|
||||||
|
m_bandwidth_limit[upload_channel].assign(80);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// start in the state where we are trying to read the
|
||||||
|
// handshake from the other side
|
||||||
|
reset_recv_buffer(20);
|
||||||
|
setup_receive();
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_in_constructor = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_peer_connection::~bt_peer_connection()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_peer_connection::on_connected()
|
||||||
|
{
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
|
|
||||||
pe_settings::enc_policy const& out_enc_policy = m_ses.get_pe_settings().out_enc_policy;
|
pe_settings::enc_policy const& out_enc_policy = m_ses.get_pe_settings().out_enc_policy;
|
||||||
|
@ -158,62 +219,6 @@ namespace libtorrent
|
||||||
reset_recv_buffer(20);
|
reset_recv_buffer(20);
|
||||||
setup_receive();
|
setup_receive();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
m_in_constructor = false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bt_peer_connection::bt_peer_connection(
|
|
||||||
session_impl& ses
|
|
||||||
, boost::shared_ptr<socket_type> s
|
|
||||||
, policy::peer* peerinfo)
|
|
||||||
: peer_connection(ses, s, peerinfo)
|
|
||||||
, m_state(read_protocol_identifier)
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
||||||
, m_supports_extensions(false)
|
|
||||||
#endif
|
|
||||||
, m_supports_dht_port(false)
|
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
|
||||||
, m_encrypted(false)
|
|
||||||
, m_rc4_encrypted(false)
|
|
||||||
, m_sync_bytes_read(0)
|
|
||||||
, m_enc_send_buffer(0, 0)
|
|
||||||
#endif
|
|
||||||
#ifndef NDEBUG
|
|
||||||
, m_sent_bitfield(false)
|
|
||||||
, m_in_constructor(true)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
|
|
||||||
// we are not attached to any torrent yet.
|
|
||||||
// we have to wait for the handshake to see
|
|
||||||
// which torrent the connector want's to connect to
|
|
||||||
|
|
||||||
|
|
||||||
// upload bandwidth will only be given to connections
|
|
||||||
// that are part of a torrent. Since this is an incoming
|
|
||||||
// connection, we have to give it some initial bandwidth
|
|
||||||
// to send the handshake.
|
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
|
||||||
m_bandwidth_limit[download_channel].assign(2048);
|
|
||||||
m_bandwidth_limit[upload_channel].assign(2048);
|
|
||||||
#else
|
|
||||||
m_bandwidth_limit[download_channel].assign(80);
|
|
||||||
m_bandwidth_limit[upload_channel].assign(80);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// start in the state where we are trying to read the
|
|
||||||
// handshake from the other side
|
|
||||||
reset_recv_buffer(20);
|
|
||||||
setup_receive();
|
|
||||||
#ifndef NDEBUG
|
|
||||||
m_in_constructor = false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bt_peer_connection::~bt_peer_connection()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::on_metadata()
|
void bt_peer_connection::on_metadata()
|
||||||
|
@ -226,6 +231,9 @@ namespace libtorrent
|
||||||
void bt_peer_connection::write_dht_port(int listen_port)
|
void bt_peer_connection::write_dht_port(int listen_port)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << time_now_string()
|
(*m_logger) << time_now_string()
|
||||||
<< " ==> DHT_PORT [ " << listen_port << " ]\n";
|
<< " ==> DHT_PORT [ " << listen_port << " ]\n";
|
||||||
|
@ -282,6 +290,7 @@ namespace libtorrent
|
||||||
assert(!m_encrypted);
|
assert(!m_encrypted);
|
||||||
assert(!m_rc4_encrypted);
|
assert(!m_rc4_encrypted);
|
||||||
assert(!m_DH_key_exchange.get());
|
assert(!m_DH_key_exchange.get());
|
||||||
|
assert(!m_sent_handshake);
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
if (is_local())
|
if (is_local())
|
||||||
|
@ -314,9 +323,10 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
assert (!m_encrypted);
|
assert(!m_encrypted);
|
||||||
assert (!m_rc4_encrypted);
|
assert(!m_rc4_encrypted);
|
||||||
assert (is_local());
|
assert(is_local());
|
||||||
|
assert(!m_sent_handshake);
|
||||||
|
|
||||||
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
assert(t);
|
assert(t);
|
||||||
|
@ -398,6 +408,7 @@ namespace libtorrent
|
||||||
assert(!m_encrypted);
|
assert(!m_encrypted);
|
||||||
assert(!m_rc4_encrypted);
|
assert(!m_rc4_encrypted);
|
||||||
assert(crypto_select == 0x02 || crypto_select == 0x01);
|
assert(crypto_select == 0x02 || crypto_select == 0x01);
|
||||||
|
assert(!m_sent_handshake);
|
||||||
|
|
||||||
int pad_size = 0; // rand() % 512; // Keep 0 for now
|
int pad_size = 0; // rand() % 512; // Keep 0 for now
|
||||||
|
|
||||||
|
@ -423,8 +434,8 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::write_pe_vc_cryptofield(buffer::interval& write_buf,
|
void bt_peer_connection::write_pe_vc_cryptofield(buffer::interval& write_buf
|
||||||
int crypto_field, int pad_size)
|
, int crypto_field, int pad_size)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
@ -433,6 +444,7 @@ namespace libtorrent
|
||||||
// vc,crypto_field,len(pad),pad, (len(ia))
|
// vc,crypto_field,len(pad),pad, (len(ia))
|
||||||
assert( (write_buf.left() == 8+4+2+pad_size+2 && is_local()) ||
|
assert( (write_buf.left() == 8+4+2+pad_size+2 && is_local()) ||
|
||||||
(write_buf.left() == 8+4+2+pad_size && !is_local()) );
|
(write_buf.left() == 8+4+2+pad_size && !is_local()) );
|
||||||
|
assert(!m_sent_handshake);
|
||||||
|
|
||||||
// encrypt(vc, crypto_provide/select, len(Pad), len(IA))
|
// encrypt(vc, crypto_provide/select, len(Pad), len(IA))
|
||||||
// len(pad) is zero for now, len(IA) only for outgoing connections
|
// len(pad) is zero for now, len(IA) only for outgoing connections
|
||||||
|
@ -587,6 +599,11 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
assert(!m_sent_handshake);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_sent_handshake = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
assert(t);
|
assert(t);
|
||||||
|
|
||||||
|
@ -1093,6 +1110,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
char buf[] = {0,0,0,0};
|
char buf[] = {0,0,0,0};
|
||||||
send_buffer(buf, buf + sizeof(buf));
|
send_buffer(buf, buf + sizeof(buf));
|
||||||
}
|
}
|
||||||
|
@ -1100,8 +1119,8 @@ namespace libtorrent
|
||||||
void bt_peer_connection::write_cancel(peer_request const& r)
|
void bt_peer_connection::write_cancel(peer_request const& r)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
assert(m_sent_bitfield == true);
|
|
||||||
|
|
||||||
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
assert(associated_torrent().lock()->valid_metadata());
|
assert(associated_torrent().lock()->valid_metadata());
|
||||||
|
|
||||||
char buf[] = {0,0,0,13, msg_cancel};
|
char buf[] = {0,0,0,13, msg_cancel};
|
||||||
|
@ -1125,8 +1144,8 @@ namespace libtorrent
|
||||||
void bt_peer_connection::write_request(peer_request const& r)
|
void bt_peer_connection::write_request(peer_request const& r)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
assert(m_sent_bitfield == true);
|
|
||||||
|
|
||||||
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
assert(associated_torrent().lock()->valid_metadata());
|
assert(associated_torrent().lock()->valid_metadata());
|
||||||
|
|
||||||
char buf[] = {0,0,0,13, msg_request};
|
char buf[] = {0,0,0,13, msg_request};
|
||||||
|
@ -1153,7 +1172,7 @@ namespace libtorrent
|
||||||
|
|
||||||
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
assert(t);
|
assert(t);
|
||||||
assert(m_sent_bitfield == false);
|
assert(m_sent_handshake && !m_sent_bitfield);
|
||||||
assert(t->valid_metadata());
|
assert(t->valid_metadata());
|
||||||
|
|
||||||
int num_pieces = bitfield.size();
|
int num_pieces = bitfield.size();
|
||||||
|
@ -1243,6 +1262,7 @@ namespace libtorrent
|
||||||
(*m_logger) << time_now_string() << " ==> EXTENSIONS\n";
|
(*m_logger) << time_now_string() << " ==> EXTENSIONS\n";
|
||||||
#endif
|
#endif
|
||||||
assert(m_supports_extensions);
|
assert(m_supports_extensions);
|
||||||
|
assert(m_sent_handshake);
|
||||||
|
|
||||||
entry handshake(entry::dictionary_t);
|
entry handshake(entry::dictionary_t);
|
||||||
entry extension_list(entry::dictionary_t);
|
entry extension_list(entry::dictionary_t);
|
||||||
|
@ -1257,7 +1277,7 @@ namespace libtorrent
|
||||||
std::string remote_address;
|
std::string remote_address;
|
||||||
std::back_insert_iterator<std::string> out(remote_address);
|
std::back_insert_iterator<std::string> out(remote_address);
|
||||||
detail::write_address(remote().address(), out);
|
detail::write_address(remote().address(), out);
|
||||||
handshake["ip"] = remote_address;
|
handshake["yourip"] = remote_address;
|
||||||
handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue;
|
handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue;
|
||||||
|
|
||||||
// loop backwards, to make the first extension be the last
|
// loop backwards, to make the first extension be the last
|
||||||
|
@ -1297,7 +1317,8 @@ namespace libtorrent
|
||||||
void bt_peer_connection::write_choke()
|
void bt_peer_connection::write_choke()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
assert(m_sent_bitfield == true);
|
|
||||||
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
if (is_choked()) return;
|
if (is_choked()) return;
|
||||||
char msg[] = {0,0,0,1,msg_choke};
|
char msg[] = {0,0,0,1,msg_choke};
|
||||||
|
@ -1307,7 +1328,8 @@ namespace libtorrent
|
||||||
void bt_peer_connection::write_unchoke()
|
void bt_peer_connection::write_unchoke()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
assert(m_sent_bitfield == true);
|
|
||||||
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
char msg[] = {0,0,0,1,msg_unchoke};
|
char msg[] = {0,0,0,1,msg_unchoke};
|
||||||
send_buffer(msg, msg + sizeof(msg));
|
send_buffer(msg, msg + sizeof(msg));
|
||||||
|
@ -1316,7 +1338,8 @@ namespace libtorrent
|
||||||
void bt_peer_connection::write_interested()
|
void bt_peer_connection::write_interested()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
assert(m_sent_bitfield == true);
|
|
||||||
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
char msg[] = {0,0,0,1,msg_interested};
|
char msg[] = {0,0,0,1,msg_interested};
|
||||||
send_buffer(msg, msg + sizeof(msg));
|
send_buffer(msg, msg + sizeof(msg));
|
||||||
|
@ -1325,7 +1348,8 @@ namespace libtorrent
|
||||||
void bt_peer_connection::write_not_interested()
|
void bt_peer_connection::write_not_interested()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
assert(m_sent_bitfield == true);
|
|
||||||
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
char msg[] = {0,0,0,1,msg_not_interested};
|
char msg[] = {0,0,0,1,msg_not_interested};
|
||||||
send_buffer(msg, msg + sizeof(msg));
|
send_buffer(msg, msg + sizeof(msg));
|
||||||
|
@ -1337,7 +1361,7 @@ namespace libtorrent
|
||||||
assert(associated_torrent().lock()->valid_metadata());
|
assert(associated_torrent().lock()->valid_metadata());
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
assert(index < associated_torrent().lock()->torrent_file().num_pieces());
|
assert(index < associated_torrent().lock()->torrent_file().num_pieces());
|
||||||
assert(m_sent_bitfield == true);
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
const int packet_size = 9;
|
const int packet_size = 9;
|
||||||
char msg[packet_size] = {0,0,0,5,msg_have};
|
char msg[packet_size] = {0,0,0,5,msg_have};
|
||||||
|
@ -1349,7 +1373,8 @@ namespace libtorrent
|
||||||
void bt_peer_connection::write_piece(peer_request const& r, char const* buffer)
|
void bt_peer_connection::write_piece(peer_request const& r, char const* buffer)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
assert(m_sent_bitfield == true);
|
|
||||||
|
assert(m_sent_handshake && m_sent_bitfield);
|
||||||
|
|
||||||
const int packet_size = 4 + 5 + 4 + r.length;
|
const int packet_size = 4 + 5 + 4 + r.length;
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ namespace libtorrent
|
||||||
, m_num_connecting(0)
|
, m_num_connecting(0)
|
||||||
, m_half_open_limit(0)
|
, m_half_open_limit(0)
|
||||||
, m_timer(ios)
|
, m_timer(ios)
|
||||||
|
#ifndef NDEBUG
|
||||||
|
, m_in_timeout_function(false)
|
||||||
|
#endif
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool connection_queue::free_slots() const
|
bool connection_queue::free_slots() const
|
||||||
|
@ -133,9 +136,22 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
struct function_guard
|
||||||
|
{
|
||||||
|
function_guard(bool& v): val(v) { assert(!val); val = true; }
|
||||||
|
~function_guard() { val = false; }
|
||||||
|
|
||||||
|
bool& val;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
void connection_queue::on_timeout(asio::error_code const& e)
|
void connection_queue::on_timeout(asio::error_code const& e)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
function_guard guard_(m_in_timeout_function);
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(!e || e == asio::error::operation_aborted);
|
assert(!e || e == asio::error::operation_aborted);
|
||||||
if (e) return;
|
if (e) return;
|
||||||
|
|
|
@ -216,6 +216,7 @@ namespace libtorrent
|
||||||
break;
|
break;
|
||||||
case disk_io_job::move_storage:
|
case disk_io_job::move_storage:
|
||||||
ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
|
ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
|
||||||
|
j.str = j.storage->save_path().string();
|
||||||
break;
|
break;
|
||||||
case disk_io_job::release_files:
|
case disk_io_job::release_files:
|
||||||
j.storage->release_files_impl();
|
j.storage->release_files_impl();
|
||||||
|
|
|
@ -50,6 +50,7 @@ namespace libtorrent {
|
||||||
|
|
||||||
m_DH->p = BN_bin2bn (m_dh_prime, sizeof(m_dh_prime), NULL);
|
m_DH->p = BN_bin2bn (m_dh_prime, sizeof(m_dh_prime), NULL);
|
||||||
m_DH->g = BN_bin2bn (m_dh_generator, sizeof(m_dh_generator), NULL);
|
m_DH->g = BN_bin2bn (m_dh_generator, sizeof(m_dh_generator), NULL);
|
||||||
|
m_DH->length = 160l;
|
||||||
|
|
||||||
assert (sizeof(m_dh_prime) == DH_size(m_DH));
|
assert (sizeof(m_dh_prime) == DH_size(m_DH));
|
||||||
|
|
||||||
|
@ -92,9 +93,17 @@ namespace libtorrent {
|
||||||
{
|
{
|
||||||
assert (remote_pubkey);
|
assert (remote_pubkey);
|
||||||
BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL);
|
BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL);
|
||||||
|
char dh_secret[96];
|
||||||
|
|
||||||
int ret =
|
int secret_size = DH_compute_key ( (unsigned char*)dh_secret,
|
||||||
DH_compute_key ( (unsigned char*)m_dh_secret, bn_remote_pubkey, m_DH); // TODO Check for errors
|
bn_remote_pubkey, m_DH); // TODO Check for errors
|
||||||
|
|
||||||
|
if (secret_size != 96)
|
||||||
|
{
|
||||||
|
assert(secret_size < 96 && secret_size > 0);
|
||||||
|
std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0);
|
||||||
|
}
|
||||||
|
std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size);
|
||||||
|
|
||||||
BN_free (bn_remote_pubkey);
|
BN_free (bn_remote_pubkey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -397,15 +397,6 @@ namespace libtorrent
|
||||||
try { (*i)->on_piece_pass(index); } catch (std::exception&) {}
|
try { (*i)->on_piece_pass(index); } catch (std::exception&) {}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (peer_info_struct())
|
|
||||||
{
|
|
||||||
peer_info_struct()->on_parole = false;
|
|
||||||
int& trust_points = peer_info_struct()->trust_points;
|
|
||||||
trust_points++;
|
|
||||||
// TODO: make this limit user settable
|
|
||||||
if (trust_points > 20) trust_points = 20;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void peer_connection::received_invalid_data(int index)
|
void peer_connection::received_invalid_data(int index)
|
||||||
|
@ -1090,10 +1081,6 @@ namespace libtorrent
|
||||||
, m_download_queue.end()
|
, m_download_queue.end()
|
||||||
, block_finished);
|
, block_finished);
|
||||||
|
|
||||||
// if there's another peer that needs to do another
|
|
||||||
// piece request, this will point to it
|
|
||||||
peer_connection* request_peer = 0;
|
|
||||||
|
|
||||||
if (b != m_download_queue.end())
|
if (b != m_download_queue.end())
|
||||||
{
|
{
|
||||||
if (m_assume_fifo)
|
if (m_assume_fifo)
|
||||||
|
@ -1122,31 +1109,18 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
m_download_queue.erase(b);
|
m_download_queue.erase(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t->cancel_block(block_finished);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* // cancel the block from the
|
|
||||||
// peer that has taken over it.
|
|
||||||
boost::optional<tcp::endpoint> peer
|
|
||||||
= t->picker().get_downloader(block_finished);
|
|
||||||
if (peer && t->picker().is_requested(block_finished))
|
|
||||||
{
|
|
||||||
peer_connection* pc = t->connection_for(*peer);
|
|
||||||
if (pc && pc != this)
|
|
||||||
{
|
|
||||||
pc->cancel_request(block_finished);
|
|
||||||
request_peer = pc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*/ {
|
|
||||||
if (t->alerts().should_post(alert::debug))
|
if (t->alerts().should_post(alert::debug))
|
||||||
{
|
{
|
||||||
t->alerts().post_alert(
|
t->alerts().post_alert(
|
||||||
peer_error_alert(
|
peer_error_alert(
|
||||||
m_remote
|
m_remote
|
||||||
, m_peer_id
|
, m_peer_id
|
||||||
, "got a block that was not requested"));
|
, "got a block that was not in the request queue"));
|
||||||
}
|
}
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << " *** The block we just got was not in the "
|
(*m_logger) << " *** The block we just got was not in the "
|
||||||
|
@ -1160,9 +1134,6 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
assert(picker.is_requested(block_finished));
|
|
||||||
|
|
||||||
// if the block we got is already finished, then ignore it
|
// if the block we got is already finished, then ignore it
|
||||||
if (picker.is_downloaded(block_finished))
|
if (picker.is_downloaded(block_finished))
|
||||||
|
@ -1174,25 +1145,12 @@ namespace libtorrent
|
||||||
request_a_block(*t, *this);
|
request_a_block(*t, *this);
|
||||||
send_block_requests();
|
send_block_requests();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request_peer && !request_peer->has_peer_choked() && !t->is_seed())
|
|
||||||
{
|
|
||||||
request_a_block(*t, *request_peer);
|
|
||||||
request_peer->send_block_requests();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.async_write(p, data, bind(&peer_connection::on_disk_write_complete
|
fs.async_write(p, data, bind(&peer_connection::on_disk_write_complete
|
||||||
, self(), _1, _2, p, t));
|
, self(), _1, _2, p, t));
|
||||||
picker.mark_as_writing(block_finished, m_remote);
|
picker.mark_as_writing(block_finished, peer_info_struct());
|
||||||
|
|
||||||
if (request_peer && !request_peer->has_peer_choked() && !t->is_seed())
|
|
||||||
{
|
|
||||||
request_a_block(*t, *request_peer);
|
|
||||||
request_peer->send_block_requests();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void peer_connection::on_disk_write_complete(int ret, disk_io_job const& j
|
void peer_connection::on_disk_write_complete(int ret, disk_io_job const& j
|
||||||
|
@ -1224,7 +1182,7 @@ namespace libtorrent
|
||||||
assert(p.piece == j.piece);
|
assert(p.piece == j.piece);
|
||||||
assert(p.start == j.offset);
|
assert(p.start == j.offset);
|
||||||
piece_block block_finished(p.piece, p.start / t->block_size());
|
piece_block block_finished(p.piece, p.start / t->block_size());
|
||||||
picker.mark_as_finished(block_finished, m_remote);
|
picker.mark_as_finished(block_finished, peer_info_struct());
|
||||||
|
|
||||||
if (!has_peer_choked() && !t->is_seed() && !m_torrent.expired())
|
if (!has_peer_choked() && !t->is_seed() && !m_torrent.expired())
|
||||||
{
|
{
|
||||||
|
@ -1328,7 +1286,7 @@ namespace libtorrent
|
||||||
assert(block.piece_index < t->torrent_file().num_pieces());
|
assert(block.piece_index < t->torrent_file().num_pieces());
|
||||||
assert(block.block_index >= 0);
|
assert(block.block_index >= 0);
|
||||||
assert(block.block_index < t->torrent_file().piece_size(block.piece_index));
|
assert(block.block_index < t->torrent_file().piece_size(block.piece_index));
|
||||||
assert(!t->picker().is_requested(block));
|
assert(!t->picker().is_requested(block) || (t->picker().num_peers(block) > 0));
|
||||||
|
|
||||||
piece_picker::piece_state_t state;
|
piece_picker::piece_state_t state;
|
||||||
peer_speed_t speed = peer_speed();
|
peer_speed_t speed = peer_speed();
|
||||||
|
@ -1336,7 +1294,7 @@ namespace libtorrent
|
||||||
else if (speed == medium) state = piece_picker::medium;
|
else if (speed == medium) state = piece_picker::medium;
|
||||||
else state = piece_picker::slow;
|
else state = piece_picker::slow;
|
||||||
|
|
||||||
t->picker().mark_as_downloading(block, m_remote, state);
|
t->picker().mark_as_downloading(block, peer_info_struct(), state);
|
||||||
|
|
||||||
m_request_queue.push_back(block);
|
m_request_queue.push_back(block);
|
||||||
}
|
}
|
||||||
|
@ -1354,17 +1312,22 @@ namespace libtorrent
|
||||||
assert(block.piece_index < t->torrent_file().num_pieces());
|
assert(block.piece_index < t->torrent_file().num_pieces());
|
||||||
assert(block.block_index >= 0);
|
assert(block.block_index >= 0);
|
||||||
assert(block.block_index < t->torrent_file().piece_size(block.piece_index));
|
assert(block.block_index < t->torrent_file().piece_size(block.piece_index));
|
||||||
assert(t->picker().is_requested(block));
|
|
||||||
|
|
||||||
t->picker().abort_download(block);
|
// if all the peers that requested this block has been
|
||||||
|
// cancelled, then just ignore the cancel.
|
||||||
|
if (!t->picker().is_requested(block)) return;
|
||||||
|
|
||||||
std::deque<piece_block>::iterator it
|
std::deque<piece_block>::iterator it
|
||||||
= std::find(m_download_queue.begin(), m_download_queue.end(), block);
|
= std::find(m_download_queue.begin(), m_download_queue.end(), block);
|
||||||
if (it == m_download_queue.end())
|
if (it == m_download_queue.end())
|
||||||
{
|
{
|
||||||
it = std::find(m_request_queue.begin(), m_request_queue.end(), block);
|
it = std::find(m_request_queue.begin(), m_request_queue.end(), block);
|
||||||
assert(it != m_request_queue.end());
|
// when a multi block is received, it is cancelled
|
||||||
|
// from all peers, so if this one hasn't requested
|
||||||
|
// the block, just ignore to cancel it.
|
||||||
if (it == m_request_queue.end()) return;
|
if (it == m_request_queue.end()) return;
|
||||||
|
|
||||||
|
t->picker().abort_download(block);
|
||||||
m_request_queue.erase(it);
|
m_request_queue.erase(it);
|
||||||
// since we found it in the request queue, it means it hasn't been
|
// since we found it in the request queue, it means it hasn't been
|
||||||
// sent yet, so we don't have to send a cancel.
|
// sent yet, so we don't have to send a cancel.
|
||||||
|
@ -1373,6 +1336,7 @@ namespace libtorrent
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_download_queue.erase(it);
|
m_download_queue.erase(it);
|
||||||
|
t->picker().abort_download(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
int block_offset = block.block_index * t->block_size();
|
int block_offset = block.block_index * t->block_size();
|
||||||
|
@ -1858,8 +1822,6 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_statistics.second_tick(tick_interval);
|
|
||||||
|
|
||||||
// If the client sends more data
|
// If the client sends more data
|
||||||
// we send it data faster, otherwise, slower.
|
// we send it data faster, otherwise, slower.
|
||||||
// It will also depend on how much data the
|
// It will also depend on how much data the
|
||||||
|
|
|
@ -48,8 +48,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/torrent.hpp"
|
#include "libtorrent/torrent.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TORRENT_PIECE_PICKER_INVARIANT_CHECK INVARIANT_CHECK
|
//#define TORRENT_PIECE_PICKER_INVARIANT_CHECK INVARIANT_CHECK
|
||||||
//#define TORRENT_PIECE_PICKER_INVARIANT_CHECK
|
#define TORRENT_PIECE_PICKER_INVARIANT_CHECK
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -116,11 +116,10 @@ namespace libtorrent
|
||||||
for (std::vector<downloading_piece>::const_iterator i
|
for (std::vector<downloading_piece>::const_iterator i
|
||||||
= unfinished.begin(); i != unfinished.end(); ++i)
|
= unfinished.begin(); i != unfinished.end(); ++i)
|
||||||
{
|
{
|
||||||
tcp::endpoint peer;
|
|
||||||
for (int j = 0; j < m_blocks_per_piece; ++j)
|
for (int j = 0; j < m_blocks_per_piece; ++j)
|
||||||
{
|
{
|
||||||
if (i->info[j].state == block_info::state_finished)
|
if (i->info[j].state == block_info::state_finished)
|
||||||
mark_as_finished(piece_block(i->index, j), peer);
|
mark_as_finished(piece_block(i->index, j), 0);
|
||||||
}
|
}
|
||||||
if (is_piece_finished(i->index))
|
if (is_piece_finished(i->index))
|
||||||
{
|
{
|
||||||
|
@ -197,12 +196,13 @@ namespace libtorrent
|
||||||
int block_index = num_downloads * m_blocks_per_piece;
|
int block_index = num_downloads * m_blocks_per_piece;
|
||||||
if (int(m_block_info.size()) < block_index + m_blocks_per_piece)
|
if (int(m_block_info.size()) < block_index + m_blocks_per_piece)
|
||||||
{
|
{
|
||||||
|
block_info* base = &m_block_info[0];
|
||||||
m_block_info.resize(block_index + m_blocks_per_piece);
|
m_block_info.resize(block_index + m_blocks_per_piece);
|
||||||
if (!m_downloads.empty() && &m_block_info[0] != m_downloads.front().info)
|
if (!m_downloads.empty() && &m_block_info[0] != base)
|
||||||
{
|
{
|
||||||
// this means the memory was reallocated, update the pointers
|
// this means the memory was reallocated, update the pointers
|
||||||
for (int i = 0; i < int(m_downloads.size()); ++i)
|
for (int i = 0; i < int(m_downloads.size()); ++i)
|
||||||
m_downloads[i].info = &m_block_info[i * m_blocks_per_piece];
|
m_downloads[i].info = &m_block_info[m_downloads[i].info - base];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_downloads.push_back(downloading_piece());
|
m_downloads.push_back(downloading_piece());
|
||||||
|
@ -210,30 +210,27 @@ namespace libtorrent
|
||||||
ret.info = &m_block_info[block_index];
|
ret.info = &m_block_info[block_index];
|
||||||
for (int i = 0; i < m_blocks_per_piece; ++i)
|
for (int i = 0; i < m_blocks_per_piece; ++i)
|
||||||
{
|
{
|
||||||
ret.info[i].num_downloads = 0;
|
ret.info[i].num_peers = 0;
|
||||||
ret.info[i].state = block_info::state_none;
|
ret.info[i].state = block_info::state_none;
|
||||||
ret.info[i].peer = tcp::endpoint();
|
ret.info[i].peer = 0;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::erase_download_piece(std::vector<downloading_piece>::iterator i)
|
void piece_picker::erase_download_piece(std::vector<downloading_piece>::iterator i)
|
||||||
{
|
{
|
||||||
if (i != m_downloads.end() - 1)
|
std::vector<downloading_piece>::iterator other = std::find_if(
|
||||||
|
m_downloads.begin(), m_downloads.end()
|
||||||
|
, bind(&downloading_piece::info, _1)
|
||||||
|
== &m_block_info[(m_downloads.size() - 1) * m_blocks_per_piece]);
|
||||||
|
assert(other != m_downloads.end());
|
||||||
|
|
||||||
|
if (i != other)
|
||||||
{
|
{
|
||||||
int remove_index = i - m_downloads.begin();
|
std::copy(other->info, other->info + m_blocks_per_piece, i->info);
|
||||||
int last_index = m_downloads.size() - 1;
|
other->info = i->info;
|
||||||
assert(remove_index < last_index);
|
|
||||||
|
|
||||||
assert(int(m_block_info.size()) >= last_index * m_blocks_per_piece + m_blocks_per_piece);
|
|
||||||
std::copy(m_block_info.begin() + (last_index * m_blocks_per_piece)
|
|
||||||
, m_block_info.begin() + (last_index * m_blocks_per_piece + m_blocks_per_piece)
|
|
||||||
, m_block_info.begin() + (remove_index * m_blocks_per_piece));
|
|
||||||
m_downloads[remove_index] = m_downloads[last_index];
|
|
||||||
m_downloads[remove_index].info = &m_block_info[remove_index * m_blocks_per_piece];
|
|
||||||
}
|
}
|
||||||
|
m_downloads.erase(i);
|
||||||
m_downloads.pop_back();
|
|
||||||
}
|
}
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
|
@ -243,6 +240,17 @@ namespace libtorrent
|
||||||
|
|
||||||
assert(m_piece_info.empty() || m_piece_info[0].empty());
|
assert(m_piece_info.empty() || m_piece_info[0].empty());
|
||||||
|
|
||||||
|
if (!m_downloads.empty())
|
||||||
|
{
|
||||||
|
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin();
|
||||||
|
i != m_downloads.end() - 1; ++i)
|
||||||
|
{
|
||||||
|
downloading_piece const& dp = *i;
|
||||||
|
downloading_piece const& next = *(i + 1);
|
||||||
|
assert(dp.finished + dp.writing >= next.finished + next.writing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (t != 0)
|
if (t != 0)
|
||||||
assert((int)m_piece_map.size() == t->torrent_file().num_pieces());
|
assert((int)m_piece_map.size() == t->torrent_file().num_pieces());
|
||||||
|
|
||||||
|
@ -594,6 +602,20 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_picker::sort_piece(std::vector<downloading_piece>::iterator dp)
|
||||||
|
{
|
||||||
|
assert(m_piece_map[dp->index].downloading);
|
||||||
|
int complete = dp->writing + dp->finished;
|
||||||
|
for (std::vector<downloading_piece>::iterator i = dp, j(dp-1);
|
||||||
|
i != m_downloads.begin(); --i, --j)
|
||||||
|
{
|
||||||
|
assert(j >= m_downloads.begin());
|
||||||
|
if (j->finished + j->writing >= complete) return;
|
||||||
|
using std::swap;
|
||||||
|
swap(*j, *i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void piece_picker::restore_piece(int index)
|
void piece_picker::restore_piece(int index)
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||||
|
@ -1001,10 +1023,10 @@ namespace libtorrent
|
||||||
// prefer_whole_pieces can be set if this peer should download
|
// prefer_whole_pieces can be set if this peer should download
|
||||||
// whole pieces rather than trying to download blocks from the
|
// whole pieces rather than trying to download blocks from the
|
||||||
// same piece as other peers.
|
// same piece as other peers.
|
||||||
// the endpoint is the address of the peer we're picking pieces
|
// the void* is the pointer to the policy::peer of the peer we're
|
||||||
// from. This is used when downloading whole pieces, to only
|
// picking pieces from. This is used when downloading whole pieces,
|
||||||
// pick from the same piece the same peer is downloading from.
|
// to only pick from the same piece the same peer is downloading
|
||||||
// state is supposed to be set to fast if the peer is downloading
|
// from. state is supposed to be set to fast if the peer is downloading
|
||||||
// relatively fast, by some notion. Slow peers will prefer not
|
// relatively fast, by some notion. Slow peers will prefer not
|
||||||
// to pick blocks from the same pieces as fast peers, and vice
|
// to pick blocks from the same pieces as fast peers, and vice
|
||||||
// versa. Downloading pieces are marked as being fast, medium
|
// versa. Downloading pieces are marked as being fast, medium
|
||||||
|
@ -1012,7 +1034,7 @@ namespace libtorrent
|
||||||
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, int num_blocks, bool prefer_whole_pieces
|
, int num_blocks, bool prefer_whole_pieces
|
||||||
, tcp::endpoint peer, piece_state_t speed) const
|
, void* peer, piece_state_t speed, bool rarest_first) const
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||||
assert(num_blocks > 0);
|
assert(num_blocks > 0);
|
||||||
|
@ -1029,6 +1051,22 @@ namespace libtorrent
|
||||||
// downloaded to
|
// downloaded to
|
||||||
std::vector<piece_block> backup_blocks;
|
std::vector<piece_block> backup_blocks;
|
||||||
|
|
||||||
|
bool ignore_downloading_pieces = false;
|
||||||
|
if (!prefer_whole_pieces)
|
||||||
|
{
|
||||||
|
std::vector<int> downloading_pieces;
|
||||||
|
downloading_pieces.reserve(m_downloads.size());
|
||||||
|
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
|
||||||
|
, end(m_downloads.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
downloading_pieces.push_back(i->index);
|
||||||
|
}
|
||||||
|
num_blocks = add_interesting_blocks(downloading_pieces, pieces
|
||||||
|
, interesting_blocks, backup_blocks, num_blocks
|
||||||
|
, prefer_whole_pieces, peer, speed, ignore_downloading_pieces);
|
||||||
|
ignore_downloading_pieces = true;
|
||||||
|
}
|
||||||
|
|
||||||
// this loop will loop from pieces with priority 1 and up
|
// this loop will loop from pieces with priority 1 and up
|
||||||
// until we either reach the end of the piece list or
|
// until we either reach the end of the piece list or
|
||||||
// has filled the interesting_blocks with num_blocks
|
// has filled the interesting_blocks with num_blocks
|
||||||
|
@ -1050,9 +1088,40 @@ namespace libtorrent
|
||||||
if (bucket->empty()) continue;
|
if (bucket->empty()) continue;
|
||||||
num_blocks = add_interesting_blocks(*bucket, pieces
|
num_blocks = add_interesting_blocks(*bucket, pieces
|
||||||
, interesting_blocks, backup_blocks, num_blocks
|
, interesting_blocks, backup_blocks, num_blocks
|
||||||
, prefer_whole_pieces, peer, speed);
|
, prefer_whole_pieces, peer, speed, ignore_downloading_pieces);
|
||||||
assert(num_blocks >= 0);
|
assert(num_blocks >= 0);
|
||||||
if (num_blocks == 0) return;
|
if (num_blocks == 0) return;
|
||||||
|
if (rarest_first) continue;
|
||||||
|
|
||||||
|
// we're not using rarest first (only for the first
|
||||||
|
// bucket, since that's where the currently downloading
|
||||||
|
// pieces are)
|
||||||
|
while (num_blocks > 0)
|
||||||
|
{
|
||||||
|
int start_piece = rand() % m_piece_map.size();
|
||||||
|
int piece = start_piece;
|
||||||
|
while (!pieces[piece]
|
||||||
|
|| m_piece_map[piece].index == piece_pos::we_have_index
|
||||||
|
|| m_piece_map[piece].priority(m_sequenced_download_threshold) < 2)
|
||||||
|
{
|
||||||
|
++piece;
|
||||||
|
if (piece == int(m_piece_map.size())) piece = 0;
|
||||||
|
// could not find any more pieces
|
||||||
|
if (piece == start_piece) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(m_piece_map[piece].downloading == false);
|
||||||
|
|
||||||
|
int num_blocks_in_piece = blocks_in_piece(piece);
|
||||||
|
|
||||||
|
if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks)
|
||||||
|
num_blocks_in_piece = num_blocks;
|
||||||
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||||
|
interesting_blocks.push_back(piece_block(piece, j));
|
||||||
|
num_blocks -= (std::min)(num_blocks_in_piece, num_blocks);
|
||||||
|
}
|
||||||
|
if (num_blocks == 0) return;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(num_blocks > 0);
|
assert(num_blocks > 0);
|
||||||
|
@ -1063,22 +1132,40 @@ namespace libtorrent
|
||||||
+ (std::min)(num_blocks, (int)backup_blocks.size()));
|
+ (std::min)(num_blocks, (int)backup_blocks.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_picker::clear_peer(void* peer)
|
||||||
|
{
|
||||||
|
for (std::vector<block_info>::iterator i = m_block_info.begin()
|
||||||
|
, end(m_block_info.end()); i != end; ++i)
|
||||||
|
if (i->peer == peer) i->peer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool exclusively_requested_from(piece_picker::downloading_piece const& p
|
// the first bool is true if this is the only peer that has requested and downloaded
|
||||||
, int num_blocks_in_piece, tcp::endpoint peer)
|
// blocks from this piece.
|
||||||
|
// the second bool is true if this is the only active peer that is requesting
|
||||||
|
// and downloading blocks from this piece. Active means having a connection.
|
||||||
|
boost::tuple<bool, bool> requested_from(piece_picker::downloading_piece const& p
|
||||||
|
, int num_blocks_in_piece, void* peer)
|
||||||
{
|
{
|
||||||
|
bool exclusive = true;
|
||||||
|
bool exclusive_active = true;
|
||||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||||
{
|
{
|
||||||
piece_picker::block_info const& info = p.info[j];
|
piece_picker::block_info const& info = p.info[j];
|
||||||
if (info.state != piece_picker::block_info::state_none
|
if (info.state != piece_picker::block_info::state_none
|
||||||
&& info.peer != peer
|
&& info.peer != peer)
|
||||||
&& info.peer != tcp::endpoint())
|
|
||||||
{
|
{
|
||||||
return false;
|
exclusive = false;
|
||||||
|
if (info.state == piece_picker::block_info::state_requested
|
||||||
|
&& info.peer != 0)
|
||||||
|
{
|
||||||
|
exclusive_active = false;
|
||||||
|
return boost::make_tuple(exclusive, exclusive_active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
return boost::make_tuple(exclusive, exclusive_active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1087,7 +1174,8 @@ namespace libtorrent
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, std::vector<piece_block>& backup_blocks
|
, std::vector<piece_block>& backup_blocks
|
||||||
, int num_blocks, bool prefer_whole_pieces
|
, int num_blocks, bool prefer_whole_pieces
|
||||||
, tcp::endpoint peer, piece_state_t speed) const
|
, void* peer, piece_state_t speed
|
||||||
|
, bool ignore_downloading_pieces) const
|
||||||
{
|
{
|
||||||
// if we have less than 1% of the pieces, ignore speed priorities and just try
|
// if we have less than 1% of the pieces, ignore speed priorities and just try
|
||||||
// to finish any downloading piece
|
// to finish any downloading piece
|
||||||
|
@ -1106,6 +1194,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_piece_map[*i].downloading == 1)
|
if (m_piece_map[*i].downloading == 1)
|
||||||
{
|
{
|
||||||
|
if (ignore_downloading_pieces) continue;
|
||||||
std::vector<downloading_piece>::const_iterator p
|
std::vector<downloading_piece>::const_iterator p
|
||||||
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i));
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i));
|
||||||
assert(p != m_downloads.end());
|
assert(p != m_downloads.end());
|
||||||
|
@ -1113,8 +1202,10 @@ namespace libtorrent
|
||||||
// is true if all the other pieces that are currently
|
// is true if all the other pieces that are currently
|
||||||
// requested from this piece are from the same
|
// requested from this piece are from the same
|
||||||
// peer as 'peer'.
|
// peer as 'peer'.
|
||||||
bool only_same_peer = exclusively_requested_from(*p
|
bool exclusive;
|
||||||
, num_blocks_in_piece, peer);
|
bool exclusive_active;
|
||||||
|
boost::tie(exclusive, exclusive_active)
|
||||||
|
= requested_from(*p, num_blocks_in_piece, peer);
|
||||||
|
|
||||||
// this means that this partial piece has
|
// this means that this partial piece has
|
||||||
// been downloaded/requested partially from
|
// been downloaded/requested partially from
|
||||||
|
@ -1123,7 +1214,7 @@ namespace libtorrent
|
||||||
// blocks to the backup list. If the prioritized
|
// blocks to the backup list. If the prioritized
|
||||||
// blocks aren't enough, blocks from this list
|
// blocks aren't enough, blocks from this list
|
||||||
// will be picked.
|
// will be picked.
|
||||||
if (prefer_whole_pieces && !only_same_peer)
|
if (prefer_whole_pieces && !exclusive)
|
||||||
{
|
{
|
||||||
if (int(backup_blocks.size()) >= num_blocks) continue;
|
if (int(backup_blocks.size()) >= num_blocks) continue;
|
||||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||||
|
@ -1157,7 +1248,7 @@ namespace libtorrent
|
||||||
// if the state of the piece is none (the
|
// if the state of the piece is none (the
|
||||||
// piece will in that case change state).
|
// piece will in that case change state).
|
||||||
if (p->state != none && p->state != speed
|
if (p->state != none && p->state != speed
|
||||||
&& !only_same_peer
|
&& !exclusive_active
|
||||||
&& !ignore_speed_categories)
|
&& !ignore_speed_categories)
|
||||||
{
|
{
|
||||||
if (int(backup_blocks.size()) >= num_blocks) continue;
|
if (int(backup_blocks.size()) >= num_blocks) continue;
|
||||||
|
@ -1193,9 +1284,7 @@ namespace libtorrent
|
||||||
if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks)
|
if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks)
|
||||||
num_blocks_in_piece = num_blocks;
|
num_blocks_in_piece = num_blocks;
|
||||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||||
{
|
|
||||||
interesting_blocks.push_back(piece_block(*i, j));
|
interesting_blocks.push_back(piece_block(*i, j));
|
||||||
}
|
|
||||||
num_blocks -= (std::min)(num_blocks_in_piece, num_blocks);
|
num_blocks -= (std::min)(num_blocks_in_piece, num_blocks);
|
||||||
}
|
}
|
||||||
assert(num_blocks >= 0);
|
assert(num_blocks >= 0);
|
||||||
|
@ -1281,7 +1370,7 @@ namespace libtorrent
|
||||||
|
|
||||||
|
|
||||||
void piece_picker::mark_as_downloading(piece_block block
|
void piece_picker::mark_as_downloading(piece_block block
|
||||||
, const tcp::endpoint& peer, piece_state_t state)
|
, void* peer, piece_state_t state)
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||||
|
|
||||||
|
@ -1303,6 +1392,7 @@ namespace libtorrent
|
||||||
block_info& info = dp.info[block.block_index];
|
block_info& info = dp.info[block.block_index];
|
||||||
info.state = block_info::state_requested;
|
info.state = block_info::state_requested;
|
||||||
info.peer = peer;
|
info.peer = peer;
|
||||||
|
info.num_peers = 1;
|
||||||
++dp.requested;
|
++dp.requested;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1311,14 +1401,38 @@ namespace libtorrent
|
||||||
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
||||||
assert(i != m_downloads.end());
|
assert(i != m_downloads.end());
|
||||||
block_info& info = i->info[block.block_index];
|
block_info& info = i->info[block.block_index];
|
||||||
assert(info.state == block_info::state_none);
|
assert(info.state == block_info::state_none
|
||||||
|
|| (info.state == block_info::state_requested
|
||||||
|
&& (info.num_peers > 0)));
|
||||||
info.peer = peer;
|
info.peer = peer;
|
||||||
|
if (info.state != block_info::state_requested)
|
||||||
|
{
|
||||||
info.state = block_info::state_requested;
|
info.state = block_info::state_requested;
|
||||||
++i->requested;
|
++i->requested;
|
||||||
|
}
|
||||||
|
++info.num_peers;
|
||||||
if (i->state == none) i->state = state;
|
if (i->state == none) i->state = state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int piece_picker::num_peers(piece_block block) const
|
||||||
|
{
|
||||||
|
assert(block.piece_index >= 0);
|
||||||
|
assert(block.block_index >= 0);
|
||||||
|
assert(block.piece_index < (int)m_piece_map.size());
|
||||||
|
assert(block.block_index < blocks_in_piece(block.piece_index));
|
||||||
|
|
||||||
|
piece_pos const& p = m_piece_map[block.piece_index];
|
||||||
|
if (!p.downloading) return 0;
|
||||||
|
|
||||||
|
std::vector<downloading_piece>::const_iterator i
|
||||||
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
||||||
|
assert(i != m_downloads.end());
|
||||||
|
|
||||||
|
block_info const& info = i->info[block.block_index];
|
||||||
|
return info.num_peers;
|
||||||
|
}
|
||||||
|
|
||||||
void piece_picker::get_availability(std::vector<int>& avail) const
|
void piece_picker::get_availability(std::vector<int>& avail) const
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||||
|
@ -1330,7 +1444,7 @@ namespace libtorrent
|
||||||
*j = i->peer_count;
|
*j = i->peer_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::mark_as_writing(piece_block block, tcp::endpoint const& peer)
|
void piece_picker::mark_as_writing(piece_block block, void* peer)
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||||
|
|
||||||
|
@ -1339,41 +1453,21 @@ namespace libtorrent
|
||||||
assert(block.piece_index < (int)m_piece_map.size());
|
assert(block.piece_index < (int)m_piece_map.size());
|
||||||
assert(block.block_index < blocks_in_piece(block.piece_index));
|
assert(block.block_index < blocks_in_piece(block.piece_index));
|
||||||
|
|
||||||
piece_pos& p = m_piece_map[block.piece_index];
|
assert(m_piece_map[block.piece_index].downloading);
|
||||||
assert(p.downloading);
|
|
||||||
|
|
||||||
/* if (p.downloading == 0)
|
|
||||||
{
|
|
||||||
int prio = p.priority(m_sequenced_download_threshold);
|
|
||||||
p.downloading = 1;
|
|
||||||
if (prio > 0) move(prio, p.index);
|
|
||||||
else assert(p.priority(m_sequenced_download_threshold) == 0);
|
|
||||||
|
|
||||||
downloading_piece& dp = add_download_piece();
|
|
||||||
dp.state = none;
|
|
||||||
dp.index = block.piece_index;
|
|
||||||
block_info& info = dp.info[block.block_index];
|
|
||||||
info.peer = peer;
|
|
||||||
if (info.state == block_info::state_requested) --dp.requested;
|
|
||||||
assert(dp.requested >= 0);
|
|
||||||
assert (info.state != block_info::state_finished);
|
|
||||||
assert (info.state != block_info::state_writing);
|
|
||||||
if (info.state != block_info::state_requested) ++dp.writing;
|
|
||||||
info.state = block_info::state_writing;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*/ {
|
|
||||||
std::vector<downloading_piece>::iterator i
|
std::vector<downloading_piece>::iterator i
|
||||||
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
||||||
assert(i != m_downloads.end());
|
assert(i != m_downloads.end());
|
||||||
block_info& info = i->info[block.block_index];
|
block_info& info = i->info[block.block_index];
|
||||||
info.peer == peer;
|
info.peer = peer;
|
||||||
assert(info.state == block_info::state_requested);
|
assert(info.state == block_info::state_requested);
|
||||||
if (info.state == block_info::state_requested) --i->requested;
|
if (info.state == block_info::state_requested) --i->requested;
|
||||||
assert(i->requested >= 0);
|
assert(i->requested >= 0);
|
||||||
assert (info.state != block_info::state_writing);
|
assert(info.state != block_info::state_writing);
|
||||||
++i->writing;
|
++i->writing;
|
||||||
info.state = block_info::state_writing;
|
info.state = block_info::state_writing;
|
||||||
|
if (info.num_peers > 0) --info.num_peers;
|
||||||
|
assert(info.num_peers >= 0);
|
||||||
|
|
||||||
if (i->requested == 0)
|
if (i->requested == 0)
|
||||||
{
|
{
|
||||||
|
@ -1381,10 +1475,10 @@ namespace libtorrent
|
||||||
// remove the fast/slow state from it
|
// remove the fast/slow state from it
|
||||||
i->state = none;
|
i->state = none;
|
||||||
}
|
}
|
||||||
}
|
sort_piece(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::mark_as_finished(piece_block block, tcp::endpoint const& peer)
|
void piece_picker::mark_as_finished(piece_block block, void* peer)
|
||||||
{
|
{
|
||||||
assert(block.piece_index >= 0);
|
assert(block.piece_index >= 0);
|
||||||
assert(block.block_index >= 0);
|
assert(block.block_index >= 0);
|
||||||
|
@ -1397,7 +1491,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||||
|
|
||||||
assert(peer == tcp::endpoint());
|
assert(peer == 0);
|
||||||
int prio = p.priority(m_sequenced_download_threshold);
|
int prio = p.priority(m_sequenced_download_threshold);
|
||||||
p.downloading = 1;
|
p.downloading = 1;
|
||||||
if (prio > 0) move(prio, p.index);
|
if (prio > 0) move(prio, p.index);
|
||||||
|
@ -1409,9 +1503,11 @@ namespace libtorrent
|
||||||
block_info& info = dp.info[block.block_index];
|
block_info& info = dp.info[block.block_index];
|
||||||
info.peer = peer;
|
info.peer = peer;
|
||||||
assert(info.state == block_info::state_none);
|
assert(info.state == block_info::state_none);
|
||||||
// if (info.state == block_info::state_writing) --dp.writing;
|
if (info.state != block_info::state_finished)
|
||||||
// assert(dp.writing >= 0);
|
{
|
||||||
if (info.state != block_info::state_finished) ++dp.finished;
|
++dp.finished;
|
||||||
|
sort_piece(m_downloads.end() - 1);
|
||||||
|
}
|
||||||
info.state = block_info::state_finished;
|
info.state = block_info::state_finished;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1424,22 +1520,23 @@ namespace libtorrent
|
||||||
block_info& info = i->info[block.block_index];
|
block_info& info = i->info[block.block_index];
|
||||||
info.peer = peer;
|
info.peer = peer;
|
||||||
assert(info.state == block_info::state_writing
|
assert(info.state == block_info::state_writing
|
||||||
|| peer == tcp::endpoint());
|
|| peer == 0);
|
||||||
if (info.state == block_info::state_writing) --i->writing;
|
|
||||||
assert(i->writing >= 0);
|
assert(i->writing >= 0);
|
||||||
++i->finished;
|
++i->finished;
|
||||||
info.state = block_info::state_finished;
|
if (info.state == block_info::state_writing)
|
||||||
|
|
||||||
if (i->requested == 0)
|
|
||||||
{
|
{
|
||||||
// there are no blocks requested in this piece.
|
--i->writing;
|
||||||
// remove the fast/slow state from it
|
info.state = block_info::state_finished;
|
||||||
i->state = none;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info.state = block_info::state_finished;
|
||||||
|
sort_piece(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::get_downloaders(std::vector<tcp::endpoint>& d, int index) const
|
void piece_picker::get_downloaders(std::vector<void*>& d, int index) const
|
||||||
{
|
{
|
||||||
assert(index >= 0 && index <= (int)m_piece_map.size());
|
assert(index >= 0 && index <= (int)m_piece_map.size());
|
||||||
std::vector<downloading_piece>::const_iterator i
|
std::vector<downloading_piece>::const_iterator i
|
||||||
|
@ -1453,22 +1550,21 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<tcp::endpoint> piece_picker::get_downloader(piece_block block) const
|
void* piece_picker::get_downloader(piece_block block) const
|
||||||
{
|
{
|
||||||
std::vector<downloading_piece>::const_iterator i = std::find_if(
|
std::vector<downloading_piece>::const_iterator i = std::find_if(
|
||||||
m_downloads.begin()
|
m_downloads.begin()
|
||||||
, m_downloads.end()
|
, m_downloads.end()
|
||||||
, has_index(block.piece_index));
|
, has_index(block.piece_index));
|
||||||
|
|
||||||
if (i == m_downloads.end())
|
if (i == m_downloads.end()) return 0;
|
||||||
return boost::optional<tcp::endpoint>();
|
|
||||||
|
|
||||||
assert(block.block_index >= 0);
|
assert(block.block_index >= 0);
|
||||||
|
|
||||||
if (i->info[block.block_index].state == block_info::state_none)
|
if (i->info[block.block_index].state == block_info::state_none)
|
||||||
return boost::optional<tcp::endpoint>();
|
return 0;
|
||||||
|
|
||||||
return boost::optional<tcp::endpoint>(i->info[block.block_index].peer);
|
return i->info[block.block_index].peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::abort_download(piece_block block)
|
void piece_picker::abort_download(piece_block block)
|
||||||
|
@ -1491,6 +1587,11 @@ namespace libtorrent
|
||||||
, m_downloads.end(), has_index(block.piece_index));
|
, m_downloads.end(), has_index(block.piece_index));
|
||||||
assert(i != m_downloads.end());
|
assert(i != m_downloads.end());
|
||||||
|
|
||||||
|
block_info& info = i->info[block.block_index];
|
||||||
|
--info.num_peers;
|
||||||
|
assert(info.num_peers >= 0);
|
||||||
|
if (info.num_peers > 0) return;
|
||||||
|
|
||||||
if (i->info[block.block_index].state == block_info::state_finished
|
if (i->info[block.block_index].state == block_info::state_finished
|
||||||
|| i->info[block.block_index].state == block_info::state_writing)
|
|| i->info[block.block_index].state == block_info::state_writing)
|
||||||
{
|
{
|
||||||
|
@ -1501,11 +1602,11 @@ namespace libtorrent
|
||||||
assert(i->info[block.block_index].state == block_info::state_requested);
|
assert(i->info[block.block_index].state == block_info::state_requested);
|
||||||
|
|
||||||
// clear this block as being downloaded
|
// clear this block as being downloaded
|
||||||
i->info[block.block_index].state = block_info::state_none;
|
info.state = block_info::state_none;
|
||||||
--i->requested;
|
--i->requested;
|
||||||
|
|
||||||
// clear the downloader of this block
|
// clear the downloader of this block
|
||||||
i->info[block.block_index].peer = tcp::endpoint();
|
info.peer = 0;
|
||||||
|
|
||||||
// if there are no other blocks in this piece
|
// if there are no other blocks in this piece
|
||||||
// that's being downloaded, remove it from the list
|
// that's being downloaded, remove it from the list
|
||||||
|
|
|
@ -54,6 +54,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/invariant_check.hpp"
|
#include "libtorrent/invariant_check.hpp"
|
||||||
#include "libtorrent/time.hpp"
|
#include "libtorrent/time.hpp"
|
||||||
#include "libtorrent/aux_/session_impl.hpp"
|
#include "libtorrent/aux_/session_impl.hpp"
|
||||||
|
#include "libtorrent/piece_picker.hpp"
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#include "libtorrent/bt_peer_connection.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -135,14 +140,14 @@ namespace
|
||||||
|
|
||||||
struct match_peer_ip
|
struct match_peer_ip
|
||||||
{
|
{
|
||||||
match_peer_ip(tcp::endpoint const& ip)
|
match_peer_ip(address const& ip)
|
||||||
: m_ip(ip)
|
: m_ip(ip)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool operator()(policy::peer const& p) const
|
bool operator()(policy::peer const& p) const
|
||||||
{ return p.ip.address() == m_ip.address(); }
|
{ return p.ip.address() == m_ip; }
|
||||||
|
|
||||||
tcp::endpoint const& m_ip;
|
address const& m_ip;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct match_peer_id
|
struct match_peer_id
|
||||||
|
@ -184,11 +189,11 @@ namespace libtorrent
|
||||||
// infinite loop, fighting to request the same blocks.
|
// infinite loop, fighting to request the same blocks.
|
||||||
void request_a_block(
|
void request_a_block(
|
||||||
torrent& t
|
torrent& t
|
||||||
, peer_connection& c
|
, peer_connection& c)
|
||||||
, std::vector<peer_connection*> ignore)
|
|
||||||
{
|
{
|
||||||
assert(!t.is_seed());
|
assert(!t.is_seed());
|
||||||
assert(!c.has_peer_choked());
|
assert(!c.has_peer_choked());
|
||||||
|
assert(c.peer_info_struct() != 0 || !dynamic_cast<bt_peer_connection*>(&c));
|
||||||
int num_requests = c.desired_queue_size()
|
int num_requests = c.desired_queue_size()
|
||||||
- (int)c.download_queue().size()
|
- (int)c.download_queue().size()
|
||||||
- (int)c.request_queue().size();
|
- (int)c.request_queue().size();
|
||||||
|
@ -205,6 +210,8 @@ namespace libtorrent
|
||||||
bool prefer_whole_pieces = c.prefer_whole_pieces()
|
bool prefer_whole_pieces = c.prefer_whole_pieces()
|
||||||
|| (c.peer_info_struct() && c.peer_info_struct()->on_parole);
|
|| (c.peer_info_struct() && c.peer_info_struct()->on_parole);
|
||||||
|
|
||||||
|
bool rarest_first = t.num_pieces() >= t.settings().initial_picker_threshold;
|
||||||
|
|
||||||
if (!prefer_whole_pieces)
|
if (!prefer_whole_pieces)
|
||||||
{
|
{
|
||||||
prefer_whole_pieces = c.statistics().download_payload_rate()
|
prefer_whole_pieces = c.statistics().download_payload_rate()
|
||||||
|
@ -233,7 +240,8 @@ namespace libtorrent
|
||||||
// for this peer. If we're downloading one piece in 20 seconds
|
// for this peer. If we're downloading one piece in 20 seconds
|
||||||
// then use this mode.
|
// then use this mode.
|
||||||
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
||||||
, num_requests, prefer_whole_pieces, c.remote(), state);
|
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
||||||
|
, state, rarest_first);
|
||||||
|
|
||||||
// this vector is filled with the interesting pieces
|
// this vector is filled with the interesting pieces
|
||||||
// that some other peer is currently downloading
|
// that some other peer is currently downloading
|
||||||
|
@ -248,10 +256,18 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
if (p.is_requested(*i))
|
if (p.is_requested(*i))
|
||||||
{
|
{
|
||||||
|
// don't request pieces we already have in our request queue
|
||||||
|
const std::deque<piece_block>& dq = c.download_queue();
|
||||||
|
const std::deque<piece_block>& rq = c.request_queue();
|
||||||
|
if (std::find(dq.begin(), dq.end(), *i) != dq.end()
|
||||||
|
|| std::find(rq.begin(), rq.end(), *i) != rq.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
busy_pieces.push_back(*i);
|
busy_pieces.push_back(*i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(p.num_peers(*i) == 0);
|
||||||
// ok, we found a piece that's not being downloaded
|
// ok, we found a piece that's not being downloaded
|
||||||
// by somebody else. request it from this peer
|
// by somebody else. request it from this peer
|
||||||
// and return
|
// and return
|
||||||
|
@ -259,139 +275,26 @@ namespace libtorrent
|
||||||
num_requests--;
|
num_requests--;
|
||||||
}
|
}
|
||||||
|
|
||||||
c.send_block_requests();
|
|
||||||
|
|
||||||
// in this case, we could not find any blocks
|
// in this case, we could not find any blocks
|
||||||
// that was free. If we couldn't find any busy
|
// that was free. If we couldn't find any busy
|
||||||
// blocks as well, we cannot download anything
|
// blocks as well, we cannot download anything
|
||||||
// more from this peer.
|
// more from this peer.
|
||||||
|
|
||||||
if (busy_pieces.empty()) return;
|
if (busy_pieces.empty() || num_requests == 0)
|
||||||
|
|
||||||
// first look for blocks that are just queued
|
|
||||||
// and not actually sent to us yet
|
|
||||||
// (then we can cancel those and request them
|
|
||||||
// from this peer instead)
|
|
||||||
|
|
||||||
while (num_requests > 0)
|
|
||||||
{
|
{
|
||||||
peer_connection* peer = 0;
|
c.send_block_requests();
|
||||||
|
return;
|
||||||
const int initial_queue_size = (int)c.download_queue().size()
|
|
||||||
+ (int)c.request_queue().size();
|
|
||||||
|
|
||||||
// This peer's weight will be the minimum, to prevent
|
|
||||||
// cancelling requests from a faster peer.
|
|
||||||
float min_weight = initial_queue_size == 0
|
|
||||||
? std::numeric_limits<float>::max()
|
|
||||||
: c.statistics().download_payload_rate() / initial_queue_size;
|
|
||||||
|
|
||||||
// find the peer with the lowest download
|
|
||||||
// speed that also has a piece that this
|
|
||||||
// peer could send us
|
|
||||||
for (torrent::peer_iterator i = t.begin();
|
|
||||||
i != t.end(); ++i)
|
|
||||||
{
|
|
||||||
// don't try to take over blocks from ourself
|
|
||||||
if (i->second == &c)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// ignore all peers in the ignore list
|
|
||||||
if (std::find(ignore.begin(), ignore.end(), i->second) != ignore.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const std::deque<piece_block>& download_queue = i->second->download_queue();
|
|
||||||
const std::deque<piece_block>& request_queue = i->second->request_queue();
|
|
||||||
const int queue_size = (int)i->second->download_queue().size()
|
|
||||||
+ (int)i->second->request_queue().size();
|
|
||||||
|
|
||||||
bool in_request_queue = std::find_first_of(
|
|
||||||
busy_pieces.begin()
|
|
||||||
, busy_pieces.end()
|
|
||||||
, request_queue.begin()
|
|
||||||
, request_queue.end()) != busy_pieces.end();
|
|
||||||
|
|
||||||
bool in_download_queue = std::find_first_of(
|
|
||||||
busy_pieces.begin()
|
|
||||||
, busy_pieces.end()
|
|
||||||
, download_queue.begin()
|
|
||||||
, download_queue.end()) != busy_pieces.end();
|
|
||||||
|
|
||||||
// if the block is in the request queue rather than the download queue
|
|
||||||
// (i.e. the request message hasn't been sent yet) lower the weight in
|
|
||||||
// order to prioritize it. Taking over a block in the request queue is
|
|
||||||
// free in terms of redundant download. A block that already has been
|
|
||||||
// requested is likely to be in transit already, and would in that case
|
|
||||||
// mean redundant data to receive.
|
|
||||||
const float weight = (queue_size == 0)
|
|
||||||
? std::numeric_limits<float>::max()
|
|
||||||
: i->second->statistics().download_payload_rate() / queue_size
|
|
||||||
* in_request_queue ? .1f : 1.f;
|
|
||||||
|
|
||||||
// if the peer's (i) weight is less than the lowest we've found so
|
|
||||||
// far (weight == priority) and it has blocks in its request-
|
|
||||||
// or download queue that we could request from this peer (c),
|
|
||||||
// replace the currently lowest ranking peer.
|
|
||||||
if (weight < min_weight && (in_request_queue || in_download_queue))
|
|
||||||
{
|
|
||||||
peer = i->second;
|
|
||||||
min_weight = weight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peer == 0)
|
std::random_shuffle(busy_pieces.begin(), busy_pieces.end());
|
||||||
{
|
|
||||||
// we probably couldn't request the block because
|
|
||||||
// we are ignoring some peers
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find a suitable block to take over from this peer
|
// find the block with the fewest requests to it
|
||||||
|
std::vector<piece_block>::iterator i = std::min_element(
|
||||||
|
busy_pieces.begin(), busy_pieces.end()
|
||||||
|
, bind(&piece_picker::num_peers, boost::cref(p), _1) <
|
||||||
|
bind(&piece_picker::num_peers, boost::cref(p), _2));
|
||||||
|
|
||||||
std::deque<piece_block>::const_reverse_iterator common_block =
|
c.add_request(*i);
|
||||||
std::find_first_of(
|
|
||||||
peer->request_queue().rbegin()
|
|
||||||
, peer->request_queue().rend()
|
|
||||||
, busy_pieces.begin()
|
|
||||||
, busy_pieces.end());
|
|
||||||
|
|
||||||
if (common_block == peer->request_queue().rend())
|
|
||||||
{
|
|
||||||
common_block = std::find_first_of(
|
|
||||||
peer->download_queue().rbegin()
|
|
||||||
, peer->download_queue().rend()
|
|
||||||
, busy_pieces.begin()
|
|
||||||
, busy_pieces.end());
|
|
||||||
assert(common_block != peer->download_queue().rend());
|
|
||||||
}
|
|
||||||
|
|
||||||
piece_block block = *common_block;
|
|
||||||
|
|
||||||
// the one we interrupted may need to request a new piece.
|
|
||||||
// make sure it doesn't take over a block from the peer
|
|
||||||
// that just took over its block (that would cause an
|
|
||||||
// infinite recursion)
|
|
||||||
peer->cancel_request(block);
|
|
||||||
c.add_request(block);
|
|
||||||
ignore.push_back(&c);
|
|
||||||
if (!peer->has_peer_choked() && !t.is_seed())
|
|
||||||
{
|
|
||||||
request_a_block(t, *peer, ignore);
|
|
||||||
peer->send_block_requests();
|
|
||||||
}
|
|
||||||
|
|
||||||
num_requests--;
|
|
||||||
|
|
||||||
const int queue_size = (int)c.download_queue().size()
|
|
||||||
+ (int)c.request_queue().size();
|
|
||||||
const float weight = queue_size == 0
|
|
||||||
? std::numeric_limits<float>::max()
|
|
||||||
: c.statistics().download_payload_rate() / queue_size;
|
|
||||||
|
|
||||||
// this peer doesn't have a faster connection than the
|
|
||||||
// slowest peer. Don't take over any blocks
|
|
||||||
if (weight <= min_weight) break;
|
|
||||||
}
|
|
||||||
c.send_block_requests();
|
c.send_block_requests();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,6 +583,10 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_torrent->is_paused()) return;
|
if (m_torrent->is_paused()) return;
|
||||||
|
|
||||||
|
piece_picker* p = 0;
|
||||||
|
if (m_torrent->has_picker())
|
||||||
|
p = &m_torrent->picker();
|
||||||
|
|
||||||
ptime now = time_now();
|
ptime now = time_now();
|
||||||
// remove old disconnected peers from the list
|
// remove old disconnected peers from the list
|
||||||
for (iterator i = m_peers.begin(); i != m_peers.end();)
|
for (iterator i = m_peers.begin(); i != m_peers.end();)
|
||||||
|
@ -689,6 +596,7 @@ namespace libtorrent
|
||||||
&& i->connected != min_time()
|
&& i->connected != min_time()
|
||||||
&& now - i->connected > minutes(120))
|
&& now - i->connected > minutes(120))
|
||||||
{
|
{
|
||||||
|
if (p) p->clear_peer(&(*i));
|
||||||
m_peers.erase(i++);
|
m_peers.erase(i++);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -949,7 +857,7 @@ namespace libtorrent
|
||||||
i = std::find_if(
|
i = std::find_if(
|
||||||
m_peers.begin()
|
m_peers.begin()
|
||||||
, m_peers.end()
|
, m_peers.end()
|
||||||
, match_peer_ip(c.remote()));
|
, match_peer_ip(c.remote().address()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i != m_peers.end())
|
if (i != m_peers.end())
|
||||||
|
@ -974,20 +882,28 @@ namespace libtorrent
|
||||||
"connection in favour of this one");
|
"connection in favour of this one");
|
||||||
#endif
|
#endif
|
||||||
i->connection->disconnect();
|
i->connection->disconnect();
|
||||||
|
#ifndef NDEBUG
|
||||||
|
check_invariant();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we don't have ny info about this peer.
|
// we don't have any info about this peer.
|
||||||
// add a new entry
|
// add a new entry
|
||||||
assert(c.remote() == c.get_socket()->remote_endpoint());
|
assert(c.remote() == c.get_socket()->remote_endpoint());
|
||||||
|
|
||||||
peer p(c.remote(), peer::not_connectable, 0);
|
peer p(c.remote(), peer::not_connectable, 0);
|
||||||
m_peers.push_back(p);
|
m_peers.push_back(p);
|
||||||
i = boost::prior(m_peers.end());
|
i = boost::prior(m_peers.end());
|
||||||
|
#ifndef NDEBUG
|
||||||
|
check_invariant();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(m_torrent->connection_for(c.remote()) == &c);
|
||||||
|
|
||||||
c.set_peer_info(&*i);
|
c.set_peer_info(&*i);
|
||||||
assert(i->connection == 0);
|
assert(i->connection == 0);
|
||||||
c.add_stat(i->prev_amount_download, i->prev_amount_upload);
|
c.add_stat(i->prev_amount_download, i->prev_amount_upload);
|
||||||
|
@ -1037,7 +953,7 @@ namespace libtorrent
|
||||||
i = std::find_if(
|
i = std::find_if(
|
||||||
m_peers.begin()
|
m_peers.begin()
|
||||||
, m_peers.end()
|
, m_peers.end()
|
||||||
, match_peer_ip(remote));
|
, match_peer_ip(remote.address()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == m_peers.end())
|
if (i == m_peers.end())
|
||||||
|
@ -1324,7 +1240,7 @@ namespace libtorrent
|
||||||
if (c.failed())
|
if (c.failed())
|
||||||
{
|
{
|
||||||
++i->failcount;
|
++i->failcount;
|
||||||
i->connected = time_now();
|
// i->connected = time_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the share ratio is 0 (infinite), the
|
// if the share ratio is 0 (infinite), the
|
||||||
|
@ -1393,17 +1309,26 @@ namespace libtorrent
|
||||||
for (const_iterator i = m_peers.begin();
|
for (const_iterator i = m_peers.begin();
|
||||||
i != m_peers.end(); ++i)
|
i != m_peers.end(); ++i)
|
||||||
{
|
{
|
||||||
|
peer const& p = *i;
|
||||||
if (!m_torrent->settings().allow_multiple_connections_per_ip)
|
if (!m_torrent->settings().allow_multiple_connections_per_ip)
|
||||||
assert(unique_test.find(i->ip.address()) == unique_test.end());
|
assert(unique_test.find(p.ip.address()) == unique_test.end());
|
||||||
unique_test.insert(i->ip.address());
|
unique_test.insert(p.ip.address());
|
||||||
++total_connections;
|
++total_connections;
|
||||||
if (!i->connection) continue;
|
if (!p.connection) continue;
|
||||||
assert(i->connection->peer_info_struct() == 0
|
if (!m_torrent->settings().allow_multiple_connections_per_ip)
|
||||||
|| i->connection->peer_info_struct() == &*i);
|
{
|
||||||
|
std::vector<peer_connection*> conns;
|
||||||
|
m_torrent->connection_for(p.ip.address(), conns);
|
||||||
|
assert(std::find_if(conns.begin(), conns.end()
|
||||||
|
, boost::bind(std::equal_to<peer_connection*>(), _1, p.connection))
|
||||||
|
!= conns.end());
|
||||||
|
}
|
||||||
|
assert(p.connection->peer_info_struct() == 0
|
||||||
|
|| p.connection->peer_info_struct() == &p);
|
||||||
++nonempty_connections;
|
++nonempty_connections;
|
||||||
if (!i->connection->is_disconnecting())
|
if (!p.connection->is_disconnecting())
|
||||||
++connected_peers;
|
++connected_peers;
|
||||||
if (!i->connection->is_choked()) ++actual_unchoked;
|
if (!p.connection->is_choked()) ++actual_unchoked;
|
||||||
}
|
}
|
||||||
// assert(actual_unchoked <= m_torrent->m_uploads_quota.given);
|
// assert(actual_unchoked <= m_torrent->m_uploads_quota.given);
|
||||||
assert(actual_unchoked == m_num_unchoked);
|
assert(actual_unchoked == m_num_unchoked);
|
||||||
|
@ -1419,6 +1344,33 @@ namespace libtorrent
|
||||||
++num_torrent_peers;
|
++num_torrent_peers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_torrent->has_picker())
|
||||||
|
{
|
||||||
|
piece_picker& p = m_torrent->picker();
|
||||||
|
std::vector<piece_picker::downloading_piece> downloaders = p.get_download_queue();
|
||||||
|
|
||||||
|
std::set<void*> peer_set;
|
||||||
|
std::vector<void*> peers;
|
||||||
|
for (std::vector<piece_picker::downloading_piece>::iterator i = downloaders.begin()
|
||||||
|
, end(downloaders.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
p.get_downloaders(peers, i->index);
|
||||||
|
std::copy(peers.begin(), peers.end()
|
||||||
|
, std::insert_iterator<std::set<void*> >(peer_set, peer_set.begin()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::set<void*>::iterator i = peer_set.begin()
|
||||||
|
, end(peer_set.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
policy::peer* p = static_cast<policy::peer*>(*i);
|
||||||
|
if (p == 0) continue;
|
||||||
|
std::list<peer>::const_iterator k = m_peers.begin();
|
||||||
|
for (; k != m_peers.end(); ++k)
|
||||||
|
if (&(*k) == p) break;
|
||||||
|
assert(k != m_peers.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this invariant is a bit complicated.
|
// this invariant is a bit complicated.
|
||||||
// the usual case should be that connected_peers
|
// the usual case should be that connected_peers
|
||||||
// == num_torrent_peers. But when there's an incoming
|
// == num_torrent_peers. But when there's an incoming
|
||||||
|
|
|
@ -75,6 +75,22 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/aux_/session_impl.hpp"
|
#include "libtorrent/aux_/session_impl.hpp"
|
||||||
#include "libtorrent/kademlia/dht_tracker.hpp"
|
#include "libtorrent/kademlia/dht_tracker.hpp"
|
||||||
|
|
||||||
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
|
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// openssl requires this to clean up internal
|
||||||
|
// structures it allocates
|
||||||
|
struct openssl_cleanup
|
||||||
|
{
|
||||||
|
~openssl_cleanup() { CRYPTO_cleanup_all_ex_data(); }
|
||||||
|
} openssl_global_destructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
using boost::shared_ptr;
|
using boost::shared_ptr;
|
||||||
using boost::weak_ptr;
|
using boost::weak_ptr;
|
||||||
using boost::bind;
|
using boost::bind;
|
||||||
|
@ -1584,6 +1600,8 @@ namespace detail
|
||||||
|
|
||||||
boost::shared_ptr<torrent> t = find_torrent(ih).lock();
|
boost::shared_ptr<torrent> t = find_torrent(ih).lock();
|
||||||
if (!t) return;
|
if (!t) return;
|
||||||
|
// don't add peers from lsd to private torrents
|
||||||
|
if (t->torrent_file().priv()) return;
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
(*m_logger) << time_now_string()
|
(*m_logger) << time_now_string()
|
||||||
|
|
|
@ -1019,7 +1019,11 @@ namespace libtorrent
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(fsinfo.f_fstypename, "hfs")
|
||||||
|
|| !strcmp(fsinfo.f_fstypename, "ufs"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
|
@ -1037,7 +1041,9 @@ namespace libtorrent
|
||||||
case 0xEF53: // EXT2 and EXT3
|
case 0xEF53: // EXT2 and EXT3
|
||||||
case 0x00011954: // UFS
|
case 0x00011954: // UFS
|
||||||
case 0x52654973: // ReiserFS
|
case 0x52654973: // ReiserFS
|
||||||
|
case 0x52345362: // Reiser4
|
||||||
case 0x58465342: // XFS
|
case 0x58465342: // XFS
|
||||||
|
case 0x65735546: // NTFS-3G
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,7 +204,7 @@ namespace libtorrent
|
||||||
m_initial_done = 0;
|
m_initial_done = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_uploads_quota.min = 2;
|
m_uploads_quota.min = 0;
|
||||||
m_connections_quota.min = 2;
|
m_connections_quota.min = 2;
|
||||||
// this will be corrected the next time the main session
|
// this will be corrected the next time the main session
|
||||||
// distributes resources, i.e. on average in 0.5 seconds
|
// distributes resources, i.e. on average in 0.5 seconds
|
||||||
|
@ -277,7 +277,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (name) m_name.reset(new std::string(name));
|
if (name) m_name.reset(new std::string(name));
|
||||||
|
|
||||||
m_uploads_quota.min = 2;
|
m_uploads_quota.min = 0;
|
||||||
m_connections_quota.min = 2;
|
m_connections_quota.min = 2;
|
||||||
// this will be corrected the next time the main session
|
// this will be corrected the next time the main session
|
||||||
// distributes resources, i.e. on average in 0.5 seconds
|
// distributes resources, i.e. on average in 0.5 seconds
|
||||||
|
@ -395,6 +395,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
boost::weak_ptr<torrent> self(shared_from_this());
|
boost::weak_ptr<torrent> self(shared_from_this());
|
||||||
|
|
||||||
|
if (!m_torrent_file.priv())
|
||||||
|
{
|
||||||
// announce on local network every 5 minutes
|
// announce on local network every 5 minutes
|
||||||
m_announce_timer.expires_from_now(minutes(5));
|
m_announce_timer.expires_from_now(minutes(5));
|
||||||
m_announce_timer.async_wait(m_ses.m_strand.wrap(
|
m_announce_timer.async_wait(m_ses.m_strand.wrap(
|
||||||
|
@ -402,6 +404,13 @@ namespace libtorrent
|
||||||
|
|
||||||
// announce with the local discovery service
|
// announce with the local discovery service
|
||||||
m_ses.announce_lsd(m_torrent_file.info_hash());
|
m_ses.announce_lsd(m_torrent_file.info_hash());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_announce_timer.expires_from_now(minutes(15));
|
||||||
|
m_announce_timer.async_wait(m_ses.m_strand.wrap(
|
||||||
|
bind(&torrent::on_announce_disp, self, _1)));
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
if (!m_ses.m_dht) return;
|
if (!m_ses.m_dht) return;
|
||||||
|
@ -914,13 +923,13 @@ namespace libtorrent
|
||||||
// increase the total amount of failed bytes
|
// increase the total amount of failed bytes
|
||||||
m_total_failed_bytes += m_torrent_file.piece_size(index);
|
m_total_failed_bytes += m_torrent_file.piece_size(index);
|
||||||
|
|
||||||
std::vector<tcp::endpoint> downloaders;
|
std::vector<void*> downloaders;
|
||||||
m_picker->get_downloaders(downloaders, index);
|
m_picker->get_downloaders(downloaders, index);
|
||||||
|
|
||||||
// decrease the trust point of all peers that sent
|
// decrease the trust point of all peers that sent
|
||||||
// parts of this piece.
|
// parts of this piece.
|
||||||
// first, build a set of all peers that participated
|
// first, build a set of all peers that participated
|
||||||
std::set<tcp::endpoint> peers;
|
std::set<void*> peers;
|
||||||
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
|
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
@ -931,19 +940,28 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (std::set<tcp::endpoint>::iterator i = peers.begin()
|
for (std::set<void*>::iterator i = peers.begin()
|
||||||
, end(peers.end()); i != end; ++i)
|
, end(peers.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
peer_iterator p = m_connections.find(*i);
|
policy::peer* p = static_cast<policy::peer*>(*i);
|
||||||
if (p == m_connections.end()) continue;
|
if (p == 0) continue;
|
||||||
peer_connection& peer = *p->second;
|
#ifndef NDEBUG
|
||||||
peer.received_invalid_data(index);
|
if (!settings().allow_multiple_connections_per_ip)
|
||||||
|
{
|
||||||
|
std::vector<peer_connection*> conns;
|
||||||
|
connection_for(p->ip.address(), conns);
|
||||||
|
assert(p->connection == 0
|
||||||
|
|| std::find_if(conns.begin(), conns.end()
|
||||||
|
, boost::bind(std::equal_to<peer_connection*>(), _1, p->connection))
|
||||||
|
!= conns.end());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (p->connection) p->connection->received_invalid_data(index);
|
||||||
|
|
||||||
// either, we have received too many failed hashes
|
// either, we have received too many failed hashes
|
||||||
// or this was the only peer that sent us this piece.
|
// or this was the only peer that sent us this piece.
|
||||||
// TODO: make this a changable setting
|
// TODO: make this a changable setting
|
||||||
if ((peer.peer_info_struct()
|
if (p->trust_points <= -7
|
||||||
&& peer.peer_info_struct()->trust_points <= -7)
|
|
||||||
|| peers.size() == 1)
|
|| peers.size() == 1)
|
||||||
{
|
{
|
||||||
// we don't trust this peer anymore
|
// we don't trust this peer anymore
|
||||||
|
@ -951,31 +969,22 @@ namespace libtorrent
|
||||||
if (m_ses.m_alerts.should_post(alert::info))
|
if (m_ses.m_alerts.should_post(alert::info))
|
||||||
{
|
{
|
||||||
m_ses.m_alerts.post_alert(peer_ban_alert(
|
m_ses.m_alerts.post_alert(peer_ban_alert(
|
||||||
p->first
|
p->ip
|
||||||
, get_handle()
|
, get_handle()
|
||||||
, "banning peer because of too many corrupt pieces"));
|
, "banning peer because of too many corrupt pieces"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark the peer as banned
|
// mark the peer as banned
|
||||||
policy::peer* peerinfo = p->second->peer_info_struct();
|
p->banned = true;
|
||||||
if (peerinfo)
|
|
||||||
{
|
|
||||||
peerinfo->banned = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// it might be a web seed
|
|
||||||
if (web_peer_connection const* wpc
|
|
||||||
= dynamic_cast<web_peer_connection const*>(p->second))
|
|
||||||
{
|
|
||||||
remove_url_seed(wpc->url());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (p->connection)
|
||||||
|
{
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||||
(*p->second->m_logger) << "*** BANNING PEER 'too many corrupt pieces'\n";
|
(*p->connection->m_logger) << "*** BANNING PEER [ " << p->ip
|
||||||
|
<< " ] 'too many corrupt pieces'\n";
|
||||||
#endif
|
#endif
|
||||||
p->second->disconnect();
|
p->connection->disconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1028,12 +1037,12 @@ namespace libtorrent
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
assert(index < m_torrent_file.num_pieces());
|
assert(index < m_torrent_file.num_pieces());
|
||||||
|
|
||||||
std::vector<tcp::endpoint> downloaders;
|
std::vector<void*> downloaders;
|
||||||
m_picker->get_downloaders(downloaders, index);
|
m_picker->get_downloaders(downloaders, index);
|
||||||
|
|
||||||
// increase the trust point of all peers that sent
|
// increase the trust point of all peers that sent
|
||||||
// parts of this piece.
|
// parts of this piece.
|
||||||
std::set<tcp::endpoint> peers;
|
std::set<void*> peers;
|
||||||
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
|
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
|
||||||
|
|
||||||
if (!m_have_pieces[index])
|
if (!m_have_pieces[index])
|
||||||
|
@ -1047,12 +1056,16 @@ namespace libtorrent
|
||||||
for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
|
for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
|
||||||
try { i->second->announce_piece(index); } catch (std::exception&) {}
|
try { i->second->announce_piece(index); } catch (std::exception&) {}
|
||||||
|
|
||||||
for (std::set<tcp::endpoint>::iterator i = peers.begin()
|
for (std::set<void*>::iterator i = peers.begin()
|
||||||
, end(peers.end()); i != end; ++i)
|
, end(peers.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
peer_iterator p = m_connections.find(*i);
|
policy::peer* p = static_cast<policy::peer*>(*i);
|
||||||
if (p == m_connections.end()) continue;
|
if (p == 0) continue;
|
||||||
p->second->received_valid_data(index);
|
p->on_parole = false;
|
||||||
|
++p->trust_points;
|
||||||
|
// TODO: make this limit user settable
|
||||||
|
if (p->trust_points > 20) p->trust_points = 20;
|
||||||
|
if (p->connection) p->connection->received_valid_data(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
@ -1364,6 +1377,15 @@ namespace libtorrent
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent::cancel_block(piece_block block)
|
||||||
|
{
|
||||||
|
for (peer_iterator i = m_connections.begin()
|
||||||
|
, end(m_connections.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
i->second->cancel_request(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void torrent::remove_peer(peer_connection* p) try
|
void torrent::remove_peer(peer_connection* p) try
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -1900,6 +1922,8 @@ namespace libtorrent
|
||||||
if (pp) p->add_extension(pp);
|
if (pp) p->add_extension(pp);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
assert(connection_for(p->remote()) == p);
|
||||||
|
assert(ci->second == p);
|
||||||
m_policy->new_connection(*ci->second);
|
m_policy->new_connection(*ci->second);
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
|
@ -1995,8 +2019,6 @@ namespace libtorrent
|
||||||
, int block_size
|
, int block_size
|
||||||
, bool non_prioritized)
|
, bool non_prioritized)
|
||||||
{
|
{
|
||||||
assert(m_bandwidth_limit[channel].max_assignable() >= block_size);
|
|
||||||
|
|
||||||
m_ses.m_bandwidth_manager[channel]->request_bandwidth(p
|
m_ses.m_bandwidth_manager[channel]->request_bandwidth(p
|
||||||
, block_size, non_prioritized);
|
, block_size, non_prioritized);
|
||||||
m_bandwidth_limit[channel].assign(block_size);
|
m_bandwidth_limit[channel].assign(block_size);
|
||||||
|
@ -2321,14 +2343,30 @@ namespace libtorrent
|
||||||
// size_type download = m_stat.total_payload_download();
|
// size_type download = m_stat.total_payload_download();
|
||||||
// size_type done = boost::get<0>(bytes_done());
|
// size_type done = boost::get<0>(bytes_done());
|
||||||
// assert(download >= done - m_initial_done);
|
// assert(download >= done - m_initial_done);
|
||||||
|
std::map<piece_block, int> num_requests;
|
||||||
for (const_peer_iterator i = begin(); i != end(); ++i)
|
for (const_peer_iterator i = begin(); i != end(); ++i)
|
||||||
{
|
{
|
||||||
peer_connection const& p = *i->second;
|
peer_connection const& p = *i->second;
|
||||||
|
for (std::deque<piece_block>::const_iterator i = p.request_queue().begin()
|
||||||
|
, end(p.request_queue().end()); i != end; ++i)
|
||||||
|
++num_requests[*i];
|
||||||
|
for (std::deque<piece_block>::const_iterator i = p.download_queue().begin()
|
||||||
|
, end(p.download_queue().end()); i != end; ++i)
|
||||||
|
++num_requests[*i];
|
||||||
torrent* associated_torrent = p.associated_torrent().lock().get();
|
torrent* associated_torrent = p.associated_torrent().lock().get();
|
||||||
if (associated_torrent != this)
|
if (associated_torrent != this)
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_picker())
|
||||||
|
{
|
||||||
|
for (std::map<piece_block, int>::iterator i = num_requests.begin()
|
||||||
|
, end(num_requests.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
assert(m_picker->num_peers(i->first) == i->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (valid_metadata())
|
if (valid_metadata())
|
||||||
{
|
{
|
||||||
assert(m_abort || int(m_have_pieces.size()) == m_torrent_file.num_pieces());
|
assert(m_abort || int(m_have_pieces.size()) == m_torrent_file.num_pieces());
|
||||||
|
@ -2479,7 +2517,7 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_paused = false;
|
m_paused = false;
|
||||||
m_uploads_quota.min = 2;
|
m_uploads_quota.min = 0;
|
||||||
m_connections_quota.min = 2;
|
m_connections_quota.min = 2;
|
||||||
m_uploads_quota.max = std::numeric_limits<int>::max();
|
m_uploads_quota.max = std::numeric_limits<int>::max();
|
||||||
m_connections_quota.max = std::numeric_limits<int>::max();
|
m_connections_quota.max = std::numeric_limits<int>::max();
|
||||||
|
@ -2498,6 +2536,7 @@ namespace libtorrent
|
||||||
|
|
||||||
m_connections_quota.used = (int)m_connections.size();
|
m_connections_quota.used = (int)m_connections.size();
|
||||||
m_uploads_quota.used = m_policy->num_uploads();
|
m_uploads_quota.used = m_policy->num_uploads();
|
||||||
|
m_uploads_quota.max = (int)m_connections.size();
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
for (extension_list_t::iterator i = m_extensions.begin()
|
for (extension_list_t::iterator i = m_extensions.begin()
|
||||||
|
@ -2674,6 +2713,8 @@ namespace libtorrent
|
||||||
!boost::bind(&peer_connection::is_connecting
|
!boost::bind(&peer_connection::is_connecting
|
||||||
, boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1)));
|
, boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1)));
|
||||||
|
|
||||||
|
st.compact_mode = m_compact_mode;
|
||||||
|
|
||||||
st.num_complete = m_complete;
|
st.num_complete = m_complete;
|
||||||
st.num_incomplete = m_incomplete;
|
st.num_incomplete = m_incomplete;
|
||||||
st.paused = m_paused;
|
st.paused = m_paused;
|
||||||
|
@ -2712,6 +2753,10 @@ namespace libtorrent
|
||||||
= m_trackers[m_last_working_tracker].url;
|
= m_trackers[m_last_working_tracker].url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
st.num_uploads = m_uploads_quota.used;
|
||||||
|
st.uploads_limit = m_uploads_quota.given;
|
||||||
|
st.num_connections = m_connections_quota.used;
|
||||||
|
st.connections_limit = m_connections_quota.given;
|
||||||
// if we don't have any metadata, stop here
|
// if we don't have any metadata, stop here
|
||||||
|
|
||||||
if (!valid_metadata())
|
if (!valid_metadata())
|
||||||
|
|
|
@ -765,17 +765,61 @@ namespace libtorrent
|
||||||
const std::vector<piece_picker::downloading_piece>& q
|
const std::vector<piece_picker::downloading_piece>& q
|
||||||
= p.get_download_queue();
|
= p.get_download_queue();
|
||||||
|
|
||||||
|
int block_size = t->block_size();
|
||||||
|
|
||||||
for (std::vector<piece_picker::downloading_piece>::const_iterator i
|
for (std::vector<piece_picker::downloading_piece>::const_iterator i
|
||||||
= q.begin(); i != q.end(); ++i)
|
= q.begin(); i != q.end(); ++i)
|
||||||
{
|
{
|
||||||
partial_piece_info pi;
|
partial_piece_info pi;
|
||||||
pi.piece_state = (partial_piece_info::state_t)i->state;
|
pi.piece_state = (partial_piece_info::state_t)i->state;
|
||||||
pi.blocks_in_piece = p.blocks_in_piece(i->index);
|
pi.blocks_in_piece = p.blocks_in_piece(i->index);
|
||||||
|
int piece_size = t->torrent_file().piece_size(i->index);
|
||||||
for (int j = 0; j < pi.blocks_in_piece; ++j)
|
for (int j = 0; j < pi.blocks_in_piece; ++j)
|
||||||
{
|
{
|
||||||
pi.blocks[j].peer = i->info[j].peer;
|
block_info& bi = pi.blocks[j];
|
||||||
pi.blocks[j].num_downloads = i->info[j].num_downloads;
|
bi.state = i->info[j].state;
|
||||||
pi.blocks[j].state = i->info[j].state;
|
bi.block_size = j < pi.blocks_in_piece - 1 ? block_size
|
||||||
|
: piece_size - (j * block_size);
|
||||||
|
bool complete = bi.state == block_info::writing
|
||||||
|
|| bi.state == block_info::finished;
|
||||||
|
if (i->info[j].peer == 0)
|
||||||
|
{
|
||||||
|
bi.peer = tcp::endpoint();
|
||||||
|
bi.bytes_progress = complete ? bi.block_size : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
policy::peer* p = static_cast<policy::peer*>(i->info[j].peer);
|
||||||
|
if (p->connection)
|
||||||
|
{
|
||||||
|
bi.peer = p->connection->remote();
|
||||||
|
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;
|
||||||
|
assert(bi.bytes_progress <= bi.block_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bi.bytes_progress = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bi.bytes_progress = complete ? bi.block_size : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bi.peer = p->ip;
|
||||||
|
bi.bytes_progress = complete ? bi.block_size : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pi.blocks[j].num_peers = i->info[j].num_peers;
|
||||||
}
|
}
|
||||||
pi.piece_index = i->index;
|
pi.piece_index = i->index;
|
||||||
queue.push_back(pi);
|
queue.push_back(pi);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue