From 0de21dc81555fdfec6e06fce2738170f297690f6 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 12 Mar 2009 17:06:41 +0000 Subject: [PATCH] fixed bug related to ignoring upload slots and made the piece rejection code more robust to handle similar bugs better --- docs/manual.rst | 7 +++++++ include/libtorrent/peer_connection.hpp | 8 ++++++++ include/libtorrent/session_settings.hpp | 5 +++++ src/peer_connection.cpp | 21 +++++++++++++++++++-- src/policy.cpp | 2 +- 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/docs/manual.rst b/docs/manual.rst index fc47a28bc..53eb10dc2 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -3303,6 +3303,8 @@ that will be sent to the tracker. The user-agent is a good way to identify your int max_sparse_regions; bool lock_disk_cache; + + int max_rejects; }; ``user_agent`` this is the client identification to the tracker. @@ -3638,6 +3640,11 @@ to 0 on all platforms except windows. that's in use, will be locked in physical memory, preventing it from being swapped out. +``max_rejects`` is the number of piece requests we will reject in a row +while a peer is choked before the peer is considered abusive and is +disconnected. + + pe_settings =========== diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 2f49799c6..8b799bd68 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -820,6 +820,14 @@ namespace libtorrent // at the remote end. boost::uint8_t m_desired_queue_size; + // the number of piece requests we have rejected + // in a row because the peer is choked. This is + // used to re-send the choked message in case the + // other end keeps requesting pieces while being + // choked, and eventuelly disconnect if it keeps + // requesting too many pieces while being choked + boost::uint8_t m_choke_rejects; + // 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/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index f0be88018..f27d14483 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -159,6 +159,7 @@ namespace libtorrent #ifndef TORRENT_DISABLE_MLOCK , lock_disk_cache(true) #endif + , max_rejects(50) {} // this is the user agent that will be sent to the tracker @@ -523,6 +524,10 @@ namespace libtorrent // be swapped out bool lock_disk_cache; #endif + + // the number of times to reject requests while being + // choked before disconnecting a peer for being malicious + int max_rejects; }; #ifndef TORRENT_DISABLE_DHT diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 26e071860..0d67e8a14 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -117,6 +117,7 @@ namespace libtorrent , m_rtt(0) , m_prefer_whole_pieces(0) , m_desired_queue_size(2) + , m_choke_rejects(0) , m_fast_reconnect(false) , m_active(true) , m_peer_interested(false) @@ -228,6 +229,7 @@ namespace libtorrent , m_rtt(0) , m_prefer_whole_pieces(0) , m_desired_queue_size(2) + , m_choke_rejects(0) , m_fast_reconnect(false) , m_active(false) , m_peer_interested(false) @@ -1166,7 +1168,7 @@ namespace libtorrent #endif m_peer_interested = true; if (is_disconnecting()) return; - if (ignore_unchoke_slots()) write_unchoke(); + if (ignore_unchoke_slots()) send_unchoke(); t->get_policy().interested(*this); } @@ -1209,7 +1211,7 @@ namespace libtorrent m_ses.m_unchoke_time_scaler = 0; } - if (ignore_unchoke_slots()) write_choke(); + if (ignore_unchoke_slots()) send_unchoke(); t->get_policy().not_interested(*this); if (t->super_seeding() && m_superseed_piece != -1) @@ -1611,6 +1613,7 @@ namespace libtorrent if (m_choked && m_accept_fast.find(r.piece) == m_accept_fast.end()) { write_reject_request(r); + ++m_choke_rejects; #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING (*m_logger) << time_now_string() << " *** REJECTING REQUEST [ peer choked and piece not in allowed fast set ]\n"; @@ -1620,9 +1623,22 @@ namespace libtorrent "s: " << r.start << " | " "l: " << r.length << " ]\n"; #endif + + if (m_choke_rejects > m_ses.settings().max_rejects) + { + disconnect("too many piece requests while choked"); + return; + } + else if ((m_choke_rejects & 0xf) == 0) + { + // tell the peer it's choked again + // every 16 requests in a row + write_choke(); + } } else { + m_choke_rejects = 0; m_requests.push_back(r); m_last_incoming_request = time_now(); fill_send_buffer(); @@ -2437,6 +2453,7 @@ namespace libtorrent boost::shared_ptr t = m_torrent.lock(); TORRENT_ASSERT(t); + if (has_peer_choked()) return; if ((int)m_download_queue.size() >= m_desired_queue_size) return; bool empty_download_queue = m_download_queue.empty(); diff --git a/src/policy.cpp b/src/policy.cpp index 68b96f759..1465226d7 100644 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -884,7 +884,7 @@ namespace libtorrent && ses.num_uploads() < ses.max_uploads() && !c.ignore_unchoke_slots() && (m_torrent->ratio() == 0 - || c.share_diff() >= -free_upload_amount + || c.share_diff() >= size_type(-free_upload_amount) || m_torrent->is_finished())) { ses.unchoke_peer(c);