fixed potential hang issue when receiving faster than we can handle the incoming messages

This commit is contained in:
Arvid Norberg 2010-08-28 19:44:50 +00:00
parent 2ac1e69205
commit 18a3d545b0
2 changed files with 31 additions and 11 deletions

View File

@ -561,11 +561,11 @@ namespace libtorrent
size_type downloaded_since_unchoke() const size_type downloaded_since_unchoke() const
{ return m_statistics.total_payload_download() - m_downloaded_at_last_unchoke; } { return m_statistics.total_payload_download() - m_downloaded_at_last_unchoke; }
void setup_receive(); enum sync_t { read_async, read_sync };
void setup_receive(sync_t sync = read_sync);
protected: protected:
enum sync_t { read_async, read_sync };
size_t try_read(sync_t s, error_code& ec); size_t try_read(sync_t s, error_code& ec);
virtual void get_specific_peer_info(peer_info& p) const = 0; virtual void get_specific_peer_info(peer_info& p) const = 0;
@ -966,6 +966,10 @@ namespace libtorrent
// requesting too many pieces while being choked // requesting too many pieces while being choked
boost::uint8_t m_choke_rejects; boost::uint8_t m_choke_rejects;
// counts the number of recursive calls to on_receive_data
// used to limit recursion
boost::uint8_t m_read_recurse:5;
// if this is true, the disconnection // if this is true, the disconnection
// timestamp is not updated when the connection // timestamp is not updated when the connection
// is closed. This means the time until we can // is closed. This means the time until we can

View File

@ -129,6 +129,7 @@ namespace libtorrent
, m_prefer_whole_pieces(0) , m_prefer_whole_pieces(0)
, m_desired_queue_size(2) , m_desired_queue_size(2)
, m_choke_rejects(0) , m_choke_rejects(0)
, m_read_recurse(0)
, m_fast_reconnect(false) , m_fast_reconnect(false)
, m_active(true) , m_active(true)
, m_peer_interested(false) , m_peer_interested(false)
@ -266,6 +267,7 @@ namespace libtorrent
, m_prefer_whole_pieces(0) , m_prefer_whole_pieces(0)
, m_desired_queue_size(2) , m_desired_queue_size(2)
, m_choke_rejects(0) , m_choke_rejects(0)
, m_read_recurse(0)
, m_fast_reconnect(false) , m_fast_reconnect(false)
, m_active(false) , m_active(false)
, m_peer_interested(false) , m_peer_interested(false)
@ -4332,7 +4334,7 @@ namespace libtorrent
m_channel_state[upload_channel] = peer_info::bw_network; m_channel_state[upload_channel] = peer_info::bw_network;
} }
void peer_connection::setup_receive() void peer_connection::setup_receive(sync_t sync)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -4384,19 +4386,29 @@ namespace libtorrent
// from being at or exceeding the limit down to below the limit // from being at or exceeding the limit down to below the limit
return; return;
} }
error_code ec; error_code ec;
size_t bytes_transferred = try_read(read_sync, ec);
if (ec == asio::error::would_block) if (sync == read_sync && m_read_recurse < 10)
{ {
try_read(read_async, ec); size_t bytes_transferred = try_read(read_sync, ec);
if (ec != asio::error::would_block)
{
++m_read_recurse;
m_channel_state[download_channel] = peer_info::bw_network;
on_receive_data(ec, bytes_transferred);
--m_read_recurse;
return;
}
} }
else
#ifdef TORRENT_VERBOSE_LOGGING
if (m_read_recurse >= 10)
{ {
m_channel_state[download_channel] = peer_info::bw_network; (*m_logger) << time_now_string() << " *** reached recursion limit\n";
on_receive_data(ec, bytes_transferred);
} }
#endif
try_read(read_async, ec);
} }
size_t peer_connection::try_read(sync_t s, error_code& ec) size_t peer_connection::try_read(sync_t s, error_code& ec)
@ -4680,6 +4692,7 @@ namespace libtorrent
} }
int max_receive = 0; int max_receive = 0;
int num_loops = 0;
do do
{ {
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
@ -4731,6 +4744,8 @@ namespace libtorrent
if (m_recv_pos >= m_soft_packet_size) m_soft_packet_size = 0; if (m_recv_pos >= m_soft_packet_size) m_soft_packet_size = 0;
if (num_loops > 20) break;
error_code ec; error_code ec;
bytes_transferred = try_read(read_sync, ec); bytes_transferred = try_read(read_sync, ec);
if (ec && ec != asio::error::would_block) if (ec && ec != asio::error::would_block)
@ -4741,6 +4756,7 @@ namespace libtorrent
} }
if (ec == asio::error::would_block) break; if (ec == asio::error::would_block) break;
bytes_in_loop += bytes_transferred; bytes_in_loop += bytes_transferred;
++num_loops;
} }
while (bytes_transferred > 0); while (bytes_transferred > 0);
@ -4751,7 +4767,7 @@ namespace libtorrent
} }
m_statistics.trancieve_ip_packet(bytes_in_loop, m_remote.address().is_v6()); m_statistics.trancieve_ip_packet(bytes_in_loop, m_remote.address().is_v6());
setup_receive(); setup_receive(read_async);
} }
bool peer_connection::can_write() const bool peer_connection::can_write() const