introduced a stricter timeout on piece requests and snubbing. exposed some more data about this through the peer_info. Fixes #40
This commit is contained in:
@@ -2457,6 +2457,7 @@ It contains the following fields::
|
|||||||
on_parole = 0x200,
|
on_parole = 0x200,
|
||||||
seed = 0x400,
|
seed = 0x400,
|
||||||
optimistic_unchoke = 0x800,
|
optimistic_unchoke = 0x800,
|
||||||
|
snubbed = 0x1000,
|
||||||
rc4_encrypted = 0x100000,
|
rc4_encrypted = 0x100000,
|
||||||
plaintext_encrypted = 0x200000
|
plaintext_encrypted = 0x200000
|
||||||
};
|
};
|
||||||
@@ -2492,6 +2493,7 @@ It contains the following fields::
|
|||||||
|
|
||||||
time_duration last_request;
|
time_duration last_request;
|
||||||
time_duration last_active;
|
time_duration last_active;
|
||||||
|
int request_timeout;
|
||||||
|
|
||||||
int send_buffer_size;
|
int send_buffer_size;
|
||||||
int used_send_buffer;
|
int used_send_buffer;
|
||||||
@@ -2587,17 +2589,10 @@ any combination of the enums above. The following table describes each flag:
|
|||||||
| | doesn't within some period of time, it will be choked |
|
| | doesn't within some period of time, it will be choked |
|
||||||
| | and another peer will be optimistically unchoked. |
|
| | and another peer will be optimistically unchoked. |
|
||||||
+-------------------------+-------------------------------------------------------+
|
+-------------------------+-------------------------------------------------------+
|
||||||
| ``writing`` | The peer is currently waiting for a write operation |
|
| ``snubbed`` | This peer has recently failed to send a block within |
|
||||||
| | on the socket to complete. |
|
| | the request timeout from when the request was sent. |
|
||||||
+-------------------------+-------------------------------------------------------+
|
| | We're currently picking one block at a time from this |
|
||||||
| ``reading`` | The peer is currently waiting for a read operation |
|
| | peer. |
|
||||||
| | on the socket to complete. |
|
|
||||||
+-------------------------+-------------------------------------------------------+
|
|
||||||
| ``waiting_write_quota`` | The peer is currently waiting for the bandwidth- |
|
|
||||||
| | manager to hand out more write quota to this peer. |
|
|
||||||
+-------------------------+-------------------------------------------------------+
|
|
||||||
| ``waiting_read_quota`` | The peer is currently waiting for the bandwidth- |
|
|
||||||
| | manager to hand out more read quota to this peer. |
|
|
||||||
+-------------------------+-------------------------------------------------------+
|
+-------------------------+-------------------------------------------------------+
|
||||||
|
|
||||||
__ extension_protocol.html
|
__ extension_protocol.html
|
||||||
@@ -2678,6 +2673,10 @@ receive. -1 means it's unlimited.
|
|||||||
``last_request`` and ``last_active`` is the time since we last sent a request
|
``last_request`` and ``last_active`` is the time since we last sent a request
|
||||||
to this peer and since any transfer occurred with this peer, respectively.
|
to this peer and since any transfer occurred with this peer, respectively.
|
||||||
|
|
||||||
|
``request_timeout`` is the number of seconds until the current front piece request
|
||||||
|
will time out. This timeout can be adjusted through ``session_settings::request_timeout``.
|
||||||
|
-1 means that there is not outstanding request.
|
||||||
|
|
||||||
``send_buffer_size`` and ``used_send_buffer`` is the number of bytes allocated
|
``send_buffer_size`` and ``used_send_buffer`` is the number of bytes allocated
|
||||||
and used for the peer's send buffer, respectively.
|
and used for the peer's send buffer, respectively.
|
||||||
|
|
||||||
|
@@ -317,10 +317,10 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
|
|||||||
#ifndef TORRENT_DISABLE_GEO_IP
|
#ifndef TORRENT_DISABLE_GEO_IP
|
||||||
if (print_as) out << "AS ";
|
if (print_as) out << "AS ";
|
||||||
#endif
|
#endif
|
||||||
out << "down (total | peak ) up (total | peak ) sent-req recv flags source ";
|
out << "down (total | peak ) up (total | peak ) sent-req recv flags source ";
|
||||||
if (print_fails) out << "fail hshf ";
|
if (print_fails) out << "fail hshf ";
|
||||||
if (print_send_bufs) out << "sndb quota rcvb ";
|
if (print_send_bufs) out << "sndb quota rcvb ";
|
||||||
if (print_timers) out << "inactive wait ";
|
if (print_timers) out << "inactive wait timeout ";
|
||||||
out << "disk rtt ";
|
out << "disk rtt ";
|
||||||
if (print_block) out << "block-progress ";
|
if (print_block) out << "block-progress ";
|
||||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||||
@@ -378,6 +378,7 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
|
|||||||
<< ((i->write_state == peer_info::bw_torrent)?'t':
|
<< ((i->write_state == peer_info::bw_torrent)?'t':
|
||||||
(i->write_state == peer_info::bw_global)?'w':
|
(i->write_state == peer_info::bw_global)?'w':
|
||||||
(i->write_state == peer_info::bw_network)?'W':'.')
|
(i->write_state == peer_info::bw_network)?'W':'.')
|
||||||
|
<< ((i->flags & peer_info::snubbed)?'S':'.')
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
<< ((i->flags & peer_info::rc4_encrypted)?'E':
|
<< ((i->flags & peer_info::rc4_encrypted)?'E':
|
||||||
(i->flags & peer_info::plaintext_encrypted)?'e':'.')
|
(i->flags & peer_info::plaintext_encrypted)?'e':'.')
|
||||||
@@ -404,7 +405,8 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
|
|||||||
if (print_timers)
|
if (print_timers)
|
||||||
{
|
{
|
||||||
out << to_string(total_seconds(i->last_active), 8) << " "
|
out << to_string(total_seconds(i->last_active), 8) << " "
|
||||||
<< to_string(total_seconds(i->last_request), 4) << " ";
|
<< to_string(total_seconds(i->last_request), 4) << " "
|
||||||
|
<< to_string(i->request_timeout, 7) << " ";
|
||||||
}
|
}
|
||||||
out << add_suffix(i->pending_disk_bytes) << " "
|
out << add_suffix(i->pending_disk_bytes) << " "
|
||||||
<< to_string(i->rtt, 4) << " ";
|
<< to_string(i->rtt, 4) << " ";
|
||||||
|
@@ -567,6 +567,12 @@ namespace libtorrent
|
|||||||
ptime m_last_receive;
|
ptime m_last_receive;
|
||||||
ptime m_last_sent;
|
ptime m_last_sent;
|
||||||
|
|
||||||
|
// the time when the first entry in the
|
||||||
|
// request queue was requested, increased
|
||||||
|
// for each entry that is popped from the
|
||||||
|
// download queue. Used for request timeout
|
||||||
|
ptime m_requested;
|
||||||
|
|
||||||
// a timestamp when the remote download rate
|
// a timestamp when the remote download rate
|
||||||
// was last updated
|
// was last updated
|
||||||
ptime m_remote_dl_update;
|
ptime m_remote_dl_update;
|
||||||
@@ -823,6 +829,11 @@ namespace libtorrent
|
|||||||
// set to true when this peer is only uploading
|
// set to true when this peer is only uploading
|
||||||
bool m_upload_only:1;
|
bool m_upload_only:1;
|
||||||
|
|
||||||
|
// set to true when a piece request times out. The
|
||||||
|
// result is that the desired pending queue size
|
||||||
|
// is set to 1
|
||||||
|
bool m_snubbed:1;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
public:
|
public:
|
||||||
bool m_in_constructor:1;
|
bool m_in_constructor:1;
|
||||||
|
@@ -56,7 +56,8 @@ namespace libtorrent
|
|||||||
queued = 0x100,
|
queued = 0x100,
|
||||||
on_parole = 0x200,
|
on_parole = 0x200,
|
||||||
seed = 0x400,
|
seed = 0x400,
|
||||||
optimistic_unchoke = 0x800
|
optimistic_unchoke = 0x800,
|
||||||
|
snubbed = 0x1000
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
, rc4_encrypted = 0x100000,
|
, rc4_encrypted = 0x100000,
|
||||||
plaintext_encrypted = 0x200000
|
plaintext_encrypted = 0x200000
|
||||||
@@ -105,6 +106,10 @@ namespace libtorrent
|
|||||||
// time since last download or upload
|
// time since last download or upload
|
||||||
time_duration last_active;
|
time_duration last_active;
|
||||||
|
|
||||||
|
// the number of seconds until the current
|
||||||
|
// pending request times out
|
||||||
|
int request_timeout;
|
||||||
|
|
||||||
// the size of the send buffer for this peer, in bytes
|
// the size of the send buffer for this peer, in bytes
|
||||||
int send_buffer_size;
|
int send_buffer_size;
|
||||||
// the number bytes that's actually used of the send buffer
|
// the number bytes that's actually used of the send buffer
|
||||||
|
@@ -88,6 +88,7 @@ namespace libtorrent
|
|||||||
, stop_tracker_timeout(5)
|
, stop_tracker_timeout(5)
|
||||||
, tracker_maximum_response_length(1024*1024)
|
, tracker_maximum_response_length(1024*1024)
|
||||||
, piece_timeout(10)
|
, piece_timeout(10)
|
||||||
|
, request_timeout(40)
|
||||||
, request_queue_time(3.f)
|
, request_queue_time(3.f)
|
||||||
, max_allowed_in_request_queue(250)
|
, max_allowed_in_request_queue(250)
|
||||||
, max_out_request_queue(200)
|
, max_out_request_queue(200)
|
||||||
@@ -168,6 +169,11 @@ namespace libtorrent
|
|||||||
// it times out if no piece response is returned.
|
// it times out if no piece response is returned.
|
||||||
int piece_timeout;
|
int piece_timeout;
|
||||||
|
|
||||||
|
// the number of seconds one block (16kB) is expected
|
||||||
|
// to be received within. If it's not, the block is
|
||||||
|
// requested from a different peer
|
||||||
|
int request_timeout;
|
||||||
|
|
||||||
// the length of the request queue given in the number
|
// the length of the request queue given in the number
|
||||||
// of seconds it should take for the other end to send
|
// of seconds it should take for the other end to send
|
||||||
// all the pieces. i.e. the actual number of requests
|
// all the pieces. i.e. the actual number of requests
|
||||||
|
@@ -81,6 +81,7 @@ namespace libtorrent
|
|||||||
, m_last_unchoke(min_time())
|
, m_last_unchoke(min_time())
|
||||||
, m_last_receive(time_now())
|
, m_last_receive(time_now())
|
||||||
, m_last_sent(time_now())
|
, m_last_sent(time_now())
|
||||||
|
, m_requested(min_time())
|
||||||
, m_remote_dl_update(time_now())
|
, m_remote_dl_update(time_now())
|
||||||
, m_became_uninterested(time_now())
|
, m_became_uninterested(time_now())
|
||||||
, m_became_uninteresting(time_now())
|
, m_became_uninteresting(time_now())
|
||||||
@@ -126,6 +127,7 @@ namespace libtorrent
|
|||||||
, m_queued(true)
|
, m_queued(true)
|
||||||
, m_request_large_blocks(false)
|
, m_request_large_blocks(false)
|
||||||
, m_upload_only(false)
|
, m_upload_only(false)
|
||||||
|
, m_snubbed(false)
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
, m_in_constructor(true)
|
, m_in_constructor(true)
|
||||||
#endif
|
#endif
|
||||||
@@ -166,7 +168,7 @@ namespace libtorrent
|
|||||||
// incoming connection
|
// incoming connection
|
||||||
peer_connection::peer_connection(
|
peer_connection::peer_connection(
|
||||||
session_impl& ses
|
session_impl& ses
|
||||||
, boost::shared_ptr<socket_type> s
|
, shared_ptr<socket_type> s
|
||||||
, tcp::endpoint const& endp
|
, tcp::endpoint const& endp
|
||||||
, policy::peer* peerinfo)
|
, policy::peer* peerinfo)
|
||||||
:
|
:
|
||||||
@@ -182,6 +184,7 @@ namespace libtorrent
|
|||||||
, m_last_unchoke(min_time())
|
, m_last_unchoke(min_time())
|
||||||
, m_last_receive(time_now())
|
, m_last_receive(time_now())
|
||||||
, m_last_sent(time_now())
|
, m_last_sent(time_now())
|
||||||
|
, m_requested(min_time())
|
||||||
, m_remote_dl_update(time_now())
|
, m_remote_dl_update(time_now())
|
||||||
, m_became_uninterested(time_now())
|
, m_became_uninterested(time_now())
|
||||||
, m_became_uninteresting(time_now())
|
, m_became_uninteresting(time_now())
|
||||||
@@ -226,6 +229,7 @@ namespace libtorrent
|
|||||||
, m_queued(false)
|
, m_queued(false)
|
||||||
, m_request_large_blocks(false)
|
, m_request_large_blocks(false)
|
||||||
, m_upload_only(false)
|
, m_upload_only(false)
|
||||||
|
, m_snubbed(false)
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
, m_in_constructor(true)
|
, m_in_constructor(true)
|
||||||
#endif
|
#endif
|
||||||
@@ -1433,7 +1437,7 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
disconnect("out of memory");
|
disconnect("out of memory");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
disk_buffer_holder holder(m_ses, buffer);
|
disk_buffer_holder holder(m_ses, buffer);
|
||||||
std::memcpy(buffer, data, p.length);
|
std::memcpy(buffer, data, p.length);
|
||||||
incoming_piece(p, holder);
|
incoming_piece(p, holder);
|
||||||
@@ -1562,12 +1566,19 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(*b == block_finished);
|
TORRENT_ASSERT(*b == block_finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (total_seconds(time_now() - m_requested) < m_ses.settings().request_timeout)
|
||||||
|
m_snubbed = false;
|
||||||
|
|
||||||
// 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))
|
||||||
{
|
{
|
||||||
t->received_redundant_data(p.length);
|
t->received_redundant_data(p.length);
|
||||||
|
|
||||||
m_download_queue.erase(b);
|
m_download_queue.erase(b);
|
||||||
|
|
||||||
|
if (!m_download_queue.empty())
|
||||||
|
m_requested = time_now();
|
||||||
|
|
||||||
request_a_block(*t, *this);
|
request_a_block(*t, *this);
|
||||||
send_block_requests();
|
send_block_requests();
|
||||||
return;
|
return;
|
||||||
@@ -1579,6 +1590,9 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(m_channel_state[download_channel] == peer_info::bw_idle);
|
TORRENT_ASSERT(m_channel_state[download_channel] == peer_info::bw_idle);
|
||||||
m_download_queue.erase(b);
|
m_download_queue.erase(b);
|
||||||
|
|
||||||
|
if (!m_download_queue.empty())
|
||||||
|
m_requested = time_now();
|
||||||
|
|
||||||
// did we request this block from any other peers?
|
// did we request this block from any other peers?
|
||||||
bool multi = picker.num_peers(block_finished) > 1;
|
bool multi = picker.num_peers(block_finished) > 1;
|
||||||
picker.mark_as_writing(block_finished, peer_info_struct());
|
picker.mark_as_writing(block_finished, peer_info_struct());
|
||||||
@@ -2073,6 +2087,8 @@ namespace libtorrent
|
|||||||
|
|
||||||
if ((int)m_download_queue.size() >= m_desired_queue_size) return;
|
if ((int)m_download_queue.size() >= m_desired_queue_size) return;
|
||||||
|
|
||||||
|
bool empty_download_queue = m_download_queue.empty();
|
||||||
|
|
||||||
while (!m_request_queue.empty()
|
while (!m_request_queue.empty()
|
||||||
&& (int)m_download_queue.size() < m_desired_queue_size)
|
&& (int)m_download_queue.size() < m_desired_queue_size)
|
||||||
{
|
{
|
||||||
@@ -2166,6 +2182,13 @@ namespace libtorrent
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
m_last_piece = time_now();
|
m_last_piece = time_now();
|
||||||
|
|
||||||
|
if (!m_download_queue.empty()
|
||||||
|
&& empty_download_queue)
|
||||||
|
{
|
||||||
|
// This means we just added a request to this connection
|
||||||
|
m_requested = time_now();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void peer_connection::timed_out()
|
void peer_connection::timed_out()
|
||||||
@@ -2321,6 +2344,8 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
TORRENT_ASSERT(!associated_torrent().expired());
|
TORRENT_ASSERT(!associated_torrent().expired());
|
||||||
|
|
||||||
|
ptime now = time_now();
|
||||||
|
|
||||||
p.download_rate_peak = m_download_rate_peak;
|
p.download_rate_peak = m_download_rate_peak;
|
||||||
p.upload_rate_peak = m_upload_rate_peak;
|
p.upload_rate_peak = m_upload_rate_peak;
|
||||||
p.rtt = m_rtt;
|
p.rtt = m_rtt;
|
||||||
@@ -2333,6 +2358,8 @@ namespace libtorrent
|
|||||||
p.pending_disk_bytes = m_outstanding_writing_bytes;
|
p.pending_disk_bytes = m_outstanding_writing_bytes;
|
||||||
p.send_quota = m_bandwidth_limit[upload_channel].quota_left();
|
p.send_quota = m_bandwidth_limit[upload_channel].quota_left();
|
||||||
p.receive_quota = m_bandwidth_limit[download_channel].quota_left();
|
p.receive_quota = m_bandwidth_limit[download_channel].quota_left();
|
||||||
|
if (m_download_queue.empty()) p.request_timeout = -1;
|
||||||
|
else p.request_timeout = total_seconds(m_requested - now) + m_ses.settings().request_timeout;
|
||||||
#ifndef TORRENT_DISABLE_GEO_IP
|
#ifndef TORRENT_DISABLE_GEO_IP
|
||||||
p.inet_as_name = m_inet_as_name;
|
p.inet_as_name = m_inet_as_name;
|
||||||
#endif
|
#endif
|
||||||
@@ -2377,7 +2404,6 @@ namespace libtorrent
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.pieces = get_bitfield();
|
p.pieces = get_bitfield();
|
||||||
ptime now = time_now();
|
|
||||||
p.last_request = now - m_last_request;
|
p.last_request = now - m_last_request;
|
||||||
p.last_active = now - (std::max)(m_last_sent, m_last_receive);
|
p.last_active = now - (std::max)(m_last_sent, m_last_receive);
|
||||||
|
|
||||||
@@ -2386,6 +2412,7 @@ namespace libtorrent
|
|||||||
get_specific_peer_info(p);
|
get_specific_peer_info(p);
|
||||||
|
|
||||||
p.flags |= is_seed() ? peer_info::seed : 0;
|
p.flags |= is_seed() ? peer_info::seed : 0;
|
||||||
|
p.flags |= m_snubbed ? peer_info::snubbed : 0;
|
||||||
if (peer_info_struct())
|
if (peer_info_struct())
|
||||||
{
|
{
|
||||||
policy::peer* pi = peer_info_struct();
|
policy::peer* pi = peer_info_struct();
|
||||||
@@ -2583,6 +2610,21 @@ namespace libtorrent
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_download_queue.empty()
|
||||||
|
&& now > m_requested + seconds(m_ses.settings().request_timeout))
|
||||||
|
{
|
||||||
|
m_snubbed = true;
|
||||||
|
m_desired_queue_size = 1;
|
||||||
|
piece_picker& picker = t->picker();
|
||||||
|
// the front request timed out!
|
||||||
|
picker.abort_download(m_download_queue[0]);
|
||||||
|
m_download_queue.pop_front();
|
||||||
|
if (!m_download_queue.empty())
|
||||||
|
m_requested = time_now();
|
||||||
|
request_a_block(*t, *this);
|
||||||
|
send_block_requests();
|
||||||
|
}
|
||||||
|
|
||||||
// if we haven't sent something in too long, send a keep-alive
|
// if we haven't sent something in too long, send a keep-alive
|
||||||
keep_alive();
|
keep_alive();
|
||||||
|
|
||||||
@@ -2623,12 +2665,19 @@ namespace libtorrent
|
|||||||
? t->torrent_file().piece_length() : t->block_size();
|
? t->torrent_file().piece_length() : t->block_size();
|
||||||
TORRENT_ASSERT(block_size > 0);
|
TORRENT_ASSERT(block_size > 0);
|
||||||
|
|
||||||
m_desired_queue_size = static_cast<int>(queue_time
|
if (m_snubbed)
|
||||||
* statistics().download_rate() / block_size);
|
{
|
||||||
if (m_desired_queue_size > m_max_out_request_queue)
|
m_desired_queue_size = 1;
|
||||||
m_desired_queue_size = m_max_out_request_queue;
|
}
|
||||||
if (m_desired_queue_size < min_request_queue)
|
else
|
||||||
m_desired_queue_size = min_request_queue;
|
{
|
||||||
|
m_desired_queue_size = static_cast<int>(queue_time
|
||||||
|
* statistics().download_rate() / block_size);
|
||||||
|
if (m_desired_queue_size > m_max_out_request_queue)
|
||||||
|
m_desired_queue_size = m_max_out_request_queue;
|
||||||
|
if (m_desired_queue_size < min_request_queue)
|
||||||
|
m_desired_queue_size = min_request_queue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_download_queue.empty()
|
if (!m_download_queue.empty()
|
||||||
&& now - m_last_piece > seconds(m_ses.settings().piece_timeout))
|
&& now - m_last_piece > seconds(m_ses.settings().piece_timeout))
|
||||||
@@ -2643,6 +2692,9 @@ namespace libtorrent
|
|||||||
<< " " << total_seconds(now - m_last_piece) << "] ***\n";
|
<< " " << total_seconds(now - m_last_piece) << "] ***\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
m_snubbed = true;
|
||||||
|
m_desired_queue_size = 1;
|
||||||
|
|
||||||
if (t->is_seed())
|
if (t->is_seed())
|
||||||
{
|
{
|
||||||
m_download_queue.clear();
|
m_download_queue.clear();
|
||||||
|
Reference in New Issue
Block a user