diff --git a/ChangeLog b/ChangeLog index 7438867cd..dd7d1813b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -88,6 +88,7 @@ incoming connection * added more detailed instrumentation of the disk I/O thread + * add support for dont-have extension message * fix for set_piece_deadline * add reset_piece_deadline function * fix merkle tree torrent assert diff --git a/include/libtorrent/bt_peer_connection.hpp b/include/libtorrent/bt_peer_connection.hpp index 2bd6ab9de..4c003ec0d 100644 --- a/include/libtorrent/bt_peer_connection.hpp +++ b/include/libtorrent/bt_peer_connection.hpp @@ -106,7 +106,8 @@ namespace libtorrent { upload_only_msg = 2, holepunch_msg = 3, - share_mode_msg = 4 + share_mode_msg = 4, + dont_have_msg = 5, }; ~bt_peer_connection(); @@ -383,6 +384,9 @@ private: // the message ID for holepunch messages boost::uint8_t m_holepunch_id; + // the message ID for don't-have message + boost::uint8_t m_dont_have_id; + // the message ID for share mode message // 0 if not supported boost::uint8_t m_share_mode_id; diff --git a/include/libtorrent/error_code.hpp b/include/libtorrent/error_code.hpp index 88907ffa3..b4f555665 100644 --- a/include/libtorrent/error_code.hpp +++ b/include/libtorrent/error_code.hpp @@ -167,7 +167,7 @@ namespace libtorrent invalid_lt_tracker_message, too_frequent_pex, no_metadata, - reserved110, + invalid_dont_have, reserved111, reserved112, reserved113, diff --git a/include/libtorrent/extensions.hpp b/include/libtorrent/extensions.hpp index 15797f318..7532bd839 100644 --- a/include/libtorrent/extensions.hpp +++ b/include/libtorrent/extensions.hpp @@ -184,6 +184,9 @@ namespace libtorrent virtual bool on_have(int index) { return false; } + virtual bool on_dont_have(int index) + { return false; } + virtual bool on_bitfield(bitfield const& bitfield) { return false; } diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index d6b1b3c63..749089637 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -458,6 +458,7 @@ namespace libtorrent void incoming_interested(); void incoming_not_interested(); void incoming_have(int piece_index); + void incoming_dont_have(int piece_index); void incoming_bitfield(bitfield const& bits); void incoming_request(peer_request const& r); void incoming_piece(peer_request const& p, disk_buffer_holder& data); diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index deb68df77..ad590dd99 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -102,6 +102,7 @@ namespace libtorrent #ifndef TORRENT_DISABLE_EXTENSIONS , m_upload_only_id(0) , m_holepunch_id(0) + , m_dont_have_id(0) , m_share_mode_id(0) , m_supports_extensions(false) #endif @@ -138,6 +139,7 @@ namespace libtorrent #ifndef TORRENT_DISABLE_EXTENSIONS , m_upload_only_id(0) , m_holepunch_id(0) + , m_dont_have_id(0) , m_share_mode_id(0) , m_supports_extensions(false) #endif @@ -1605,6 +1607,13 @@ namespace libtorrent if (extended_id == upload_only_msg) { if (!packet_finished()) return; + if (packet_size() != 1) + { +#ifdef TORRENT_VERBOSE_LOGGING + peer_log("<== UPLOAD_ONLY [ ERROR: unexpected packet size: %d ]", packet_size()); +#endif + return; + } bool ul = detail::read_uint8(recv_buffer.begin) != 0; #ifdef TORRENT_VERBOSE_LOGGING peer_log("<== UPLOAD_ONLY [ %s ]", (ul?"true":"false")); @@ -1616,6 +1625,13 @@ namespace libtorrent if (extended_id == share_mode_msg) { if (!packet_finished()) return; + if (packet_size() != 1) + { +#ifdef TORRENT_VERBOSE_LOGGING + peer_log("<== SHARE_MODE [ ERROR: unexpected packet size: %d ]", packet_size()); +#endif + return; + } bool sm = detail::read_uint8(recv_buffer.begin) != 0; #ifdef TORRENT_VERBOSE_LOGGING peer_log("<== SHARE_MODE [ %s ]", (sm?"true":"false")); @@ -1634,6 +1650,21 @@ namespace libtorrent return; } + if (extended_id == dont_have_msg) + { + if (!packet_finished()) return; + if (packet_size() != 4) + { +#ifdef TORRENT_VERBOSE_LOGGING + peer_log("<== DONT_HAVE [ ERROR: unexpected packet size: %d ]", packet_size()); +#endif + return; + } + int piece = detail::read_uint32(recv_buffer.begin) != 0; + incoming_dont_have(piece); + return; + } + #ifdef TORRENT_VERBOSE_LOGGING if (packet_finished()) peer_log("<== EXTENSION MESSAGE [ msg: %d size: %d ]" @@ -1698,6 +1729,7 @@ namespace libtorrent { m_upload_only_id = boost::uint8_t(m->dict_find_int_value("upload_only", 0)); m_holepunch_id = boost::uint8_t(m->dict_find_int_value("ut_holepunch", 0)); + m_dont_have_id = boost::uint8_t(m->dict_find_int_value("lt_donthave", 0)); } #endif @@ -2082,6 +2114,7 @@ namespace libtorrent m["upload_only"] = upload_only_msg; m["ut_holepunch"] = holepunch_msg; m["share_mode"] = share_mode_msg; + m["lt_donthave"] = dont_have_msg; int complete_ago = -1; if (t->last_seen_complete() > 0) complete_ago = t->time_since_complete(); diff --git a/src/error_code.cpp b/src/error_code.cpp index 113fcfdae..aba13d363 100644 --- a/src/error_code.cpp +++ b/src/error_code.cpp @@ -159,7 +159,7 @@ namespace libtorrent "invalid lt_tracker message", "pex messages sent too frequent (possible attack)", "torrent has no metadata", - "", + "invalid dont-have message", "", "", "", diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 4db29c171..33b0aa0eb 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -1746,6 +1746,65 @@ namespace libtorrent } } + // ----------------------------- + // -------- DONT HAVE ---------- + // ----------------------------- + + void peer_connection::incoming_dont_have(int index) + { + INVARIANT_CHECK; + + boost::shared_ptr t = m_torrent.lock(); + TORRENT_ASSERT(t); + +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_dont_have(index)) return; + } +#endif + + if (is_disconnecting()) return; + +#ifdef TORRENT_VERBOSE_LOGGING + peer_log("<== DONT_HAVE [ piece: %d ]", index); +#endif + + if (is_disconnecting()) return; + + // if we got an invalid message, abort + if (index >= int(m_have_piece.size()) || index < 0) + { + disconnect(errors::invalid_dont_have, 2); + return; + } + + if (!m_have_piece[index]) + { +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING + peer_log(" got redundant DONT_HAVE message for index: %d", index); +#endif + return; + } + + bool was_seed = is_seed(); + m_have_piece.clear_bit(index); + TORRENT_ASSERT(m_num_pieces > 0); + --m_num_pieces; + + // only update the piece_picker if + // we have the metadata and if + // we're not a seed (in which case + // we won't have a piece picker) + if (!t->valid_metadata()) return; + + t->peer_lost(index); + + if (was_seed) + t->get_policy().set_seed(m_peer_info, false); + } + // ----------------------------- // --------- BITFIELD ---------- // -----------------------------