diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 8dfc2b805..ad02606e7 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -219,6 +219,7 @@ namespace libtorrent std::vector const& get_bitfield() const; std::vector const& allowed_fast(); + std::vector const& suggested_pieces() const { return m_suggested_pieces; } void timed_out(); // this will cause this peer_connection to be disconnected. @@ -303,6 +304,7 @@ namespace libtorrent void incoming_have_all(); void incoming_have_none(); void incoming_allowed_fast(int index); + void incoming_suggest(int index); // the following functions appends messages // to the send buffer @@ -493,6 +495,11 @@ namespace libtorrent // the time we sent a request to // this peer the last time ptime m_last_request; + // the time we received the last + // piece request from the peer + ptime m_last_incoming_request; + // the time when we unchoked this peer + ptime m_last_unchoke; int m_packet_size; int m_recv_pos; @@ -590,7 +597,7 @@ namespace libtorrent std::deque m_requests; // the blocks we have reserved in the piece - // picker and will send to this peer. + // picker and will request from this peer. std::deque m_request_queue; // the queue of blocks we have requested @@ -718,6 +725,10 @@ namespace libtorrent // requested (regardless of choke state) std::vector m_allowed_fast; + // pieces that has been suggested to be + // downloaded from this peer + std::vector m_suggested_pieces; + // the number of bytes send to the disk-io // thread that hasn't yet been completely written. int m_outstanding_writing_bytes; diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 2a4347778..1b1de3a81 100755 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -1062,8 +1062,14 @@ namespace libtorrent if (!m_supports_fast) throw protocol_error("got 'suggest_piece' without FAST extension support"); - // just ignore for now - return; + m_statistics.received_bytes(0, received); + if (!packet_finished()) return; + + buffer::const_interval recv_buffer = receive_buffer(); + + const char* ptr = recv_buffer.begin + 1; + int piece = detail::read_uint32(ptr); + incoming_suggest(piece); } void bt_peer_connection::on_have_all(int received) diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index c7bd3dc5e..8255478bc 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -77,6 +77,8 @@ namespace libtorrent , m_timeout(m_ses.settings().peer_timeout) , m_last_piece(time_now()) , m_last_request(time_now()) + , m_last_incoming_request(min_time()) + , m_last_unchoke(min_time()) , m_packet_size(0) , m_recv_pos(0) , m_current_send_buffer(0) @@ -155,6 +157,8 @@ namespace libtorrent , m_timeout(m_ses.settings().peer_timeout) , m_last_piece(time_now()) , m_last_request(time_now()) + , m_last_incoming_request(min_time()) + , m_last_unchoke(min_time()) , m_packet_size(0) , m_recv_pos(0) , m_current_send_buffer(0) @@ -396,7 +400,12 @@ namespace libtorrent { // dont announce during handshake if (in_handshake()) return; - + + // remove suggested pieces that we have + std::vector::iterator i = std::find( + m_suggested_pieces.begin(), m_suggested_pieces.end(), index); + if (i != m_suggested_pieces.end()) m_suggested_pieces.erase(i); + // optimization, don't send have messages // to peers that already have the piece if (!m_ses.settings().send_redundant_have @@ -724,6 +733,33 @@ namespace libtorrent } } + // ----------------------------- + // -------- REJECT PIECE ------- + // ----------------------------- + + void peer_connection::incoming_suggest(int index) + { + INVARIANT_CHECK; + +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() + << " <== SUGGEST_PIECE [ piece: " << index << " ]\n"; +#endif + boost::shared_ptr t = m_torrent.lock(); + if (!t) return; + + if (t->have_piece(index)) return; + + if (m_suggested_pieces.size() > 9) + m_suggested_pieces.erase(m_suggested_pieces.begin()); + m_suggested_pieces.push_back(index); + +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() + << " ** SUGGEST_PIECE [ piece: " << index << " added to set: " << m_suggested_pieces.size() << " ]\n"; +#endif + } + // ----------------------------- // ---------- UNCHOKE ---------- // ----------------------------- @@ -1097,6 +1133,7 @@ namespace libtorrent else { m_requests.push_back(r); + m_last_incoming_request = time_now(); fill_send_buffer(); } } @@ -1702,6 +1739,7 @@ namespace libtorrent INVARIANT_CHECK; if (!m_choked) return; + m_last_unchoke = time_now(); write_unchoke(); m_choked = false; @@ -2863,9 +2901,20 @@ namespace libtorrent // if the peer hasn't said a thing for a certain // time, it is considered to have timed out time_duration d; - d = time_now() - m_last_receive; + d = now - m_last_receive; if (d > seconds(m_timeout)) return true; + // disconnect peers that we unchoked, but + // they didn't send a request within 20 seconds. + // but only if we're a seed + boost::shared_ptr t = m_torrent.lock(); + d = now - (std::max)(m_last_unchoke, m_last_incoming_request); + if (m_requests.empty() + && !m_choked + && m_peer_interested + && t && t->is_seed() + && d > seconds(20)) return true; + // TODO: as long as we have less than 95% of the // global (or local) connection limit, connections should // never time out for another reason diff --git a/src/policy.cpp b/src/policy.cpp index 5683b74e5..4302c2890 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -258,6 +258,21 @@ namespace libtorrent } else { + if (!c.suggested_pieces().empty()) + { + // if the peer has suggested us to download certain pieces + // try to pick among those primarily + std::vector const& suggested = c.suggested_pieces(); + + p.add_interesting_blocks(suggested, c.get_bitfield() + , interesting_pieces, busy_pieces, num_requests + , prefer_whole_pieces, c.peer_info_struct(), state + , false); + interesting_pieces.insert(interesting_pieces.end() + , busy_pieces.begin(), busy_pieces.end()); + busy_pieces.clear(); + } + // picks the interesting pieces from this peer // the integer is the number of pieces that // should be guaranteed to be available for download @@ -266,9 +281,11 @@ namespace libtorrent // the last argument is if we should prefer whole pieces // for this peer. If we're downloading one piece in 20 seconds // then use this mode. - p.pick_pieces(c.get_bitfield(), interesting_pieces - , num_requests, prefer_whole_pieces, c.peer_info_struct() - , state, rarest_first); + if (int(interesting_pieces.size()) < num_requests) + p.pick_pieces(c.get_bitfield(), interesting_pieces + , num_requests, prefer_whole_pieces, c.peer_info_struct() + , state, rarest_first); + busy_pieces.reserve(10); }