diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 0062cc486..a947f4a26 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -561,11 +561,11 @@ namespace libtorrent size_type downloaded_since_unchoke() const { 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: - enum sync_t { read_async, read_sync }; size_t try_read(sync_t s, error_code& ec); virtual void get_specific_peer_info(peer_info& p) const = 0; @@ -966,6 +966,10 @@ namespace libtorrent // requesting too many pieces while being choked 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 // timestamp is not updated when the connection // is closed. This means the time until we can diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 5803baf23..7102dd39b 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -129,6 +129,7 @@ namespace libtorrent , m_prefer_whole_pieces(0) , m_desired_queue_size(2) , m_choke_rejects(0) + , m_read_recurse(0) , m_fast_reconnect(false) , m_active(true) , m_peer_interested(false) @@ -266,6 +267,7 @@ namespace libtorrent , m_prefer_whole_pieces(0) , m_desired_queue_size(2) , m_choke_rejects(0) + , m_read_recurse(0) , m_fast_reconnect(false) , m_active(false) , m_peer_interested(false) @@ -4332,7 +4334,7 @@ namespace libtorrent m_channel_state[upload_channel] = peer_info::bw_network; } - void peer_connection::setup_receive() + void peer_connection::setup_receive(sync_t sync) { INVARIANT_CHECK; @@ -4384,19 +4386,29 @@ namespace libtorrent // from being at or exceeding the limit down to below the limit return; } - 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; - on_receive_data(ec, bytes_transferred); + (*m_logger) << time_now_string() << " *** reached recursion limit\n"; } +#endif + try_read(read_async, ec); } size_t peer_connection::try_read(sync_t s, error_code& ec) @@ -4680,6 +4692,7 @@ namespace libtorrent } int max_receive = 0; + int num_loops = 0; do { #ifdef TORRENT_VERBOSE_LOGGING @@ -4731,6 +4744,8 @@ namespace libtorrent if (m_recv_pos >= m_soft_packet_size) m_soft_packet_size = 0; + if (num_loops > 20) break; + error_code ec; bytes_transferred = try_read(read_sync, ec); if (ec && ec != asio::error::would_block) @@ -4741,6 +4756,7 @@ namespace libtorrent } if (ec == asio::error::would_block) break; bytes_in_loop += bytes_transferred; + ++num_loops; } while (bytes_transferred > 0); @@ -4751,7 +4767,7 @@ namespace libtorrent } 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