diff --git a/ChangeLog b/ChangeLog index c5222fcc9..cda69295e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * feature to disable DHT, PEX and LSD per torrent * fix issue where trackers from magnet links were not included in create_torrent() * make peer_info::client a byte array in python binding * pick contiguous pieces from peers with high download rate diff --git a/bindings/python/src/session.cpp b/bindings/python/src/session.cpp index d73f9b435..8d6c7cdd6 100644 --- a/bindings/python/src/session.cpp +++ b/bindings/python/src/session.cpp @@ -871,6 +871,9 @@ void bind_session() s.attr("stop_when_ready") = torrent_flags::stop_when_ready; s.attr("override_trackers") = torrent_flags::override_trackers; s.attr("override_web_seeds") = torrent_flags::override_web_seeds; + s.attr("disable_dht") = torrent_flags::disable_dht; + s.attr("disable_lsd") = torrent_flags::disable_lsd; + s.attr("disable_pex") = torrent_flags::disable_pex; s.attr("default_flags") = torrent_flags::default_flags; } diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 01eb315e8..d02e3b80f 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -1548,7 +1548,11 @@ namespace libtorrent { // whenever something is downloaded bool m_need_save_resume_data:1; - // 2 bits here + // when this is true, this torrent participates in the DHT + bool m_enable_dht:1; + + // when this is true, this torrent participates in local service discovery + bool m_enable_lsd:1; // ---- @@ -1573,12 +1577,13 @@ namespace libtorrent { // the number of unchoked peers in this torrent unsigned int m_num_uploads:24; - // 1 bit here - // rotating sequence number for LSD announces sent out. // used to only use IP broadcast for every 8th lsd announce std::uint8_t m_lsd_seq:3; + // when this is true, this torrent supports peer exchange + bool m_enable_pex:1; + // this is set to true if the torrent was started without // metadata. It is used to save metadata in the resume file // by default for such torrents. It does not necessarily diff --git a/include/libtorrent/torrent_flags.hpp b/include/libtorrent/torrent_flags.hpp index 1f9783115..6019bec8f 100644 --- a/include/libtorrent/torrent_flags.hpp +++ b/include/libtorrent/torrent_flags.hpp @@ -241,6 +241,18 @@ namespace torrent_flags { constexpr torrent_flags_t TORRENT_DEPRECATED_MEMBER merge_resume_http_seeds = 18_bit; #endif + // set this flag to disable DHT for this torrent. This lets you have the DHT + // enabled for the whole client, and still have specific torrents not + // participating in it. i.e. not announcing to the DHT nor picking up peers + // from it. + constexpr torrent_flags_t disable_dht = 19_bit; + + // set this flag to disable local service discovery for this torrent. + constexpr torrent_flags_t disable_lsd = 20_bit; + + // set this flag to disable peer exchange for this torrent. + constexpr torrent_flags_t disable_pex = 21_bit; + constexpr torrent_flags_t all = torrent_flags_t::all(); // internal diff --git a/src/torrent.cpp b/src/torrent.cpp index 0cbed4004..de666ec75 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -203,10 +203,13 @@ bool is_downloading_state(int const st) , m_super_seeding(p.flags & torrent_flags::super_seeding) , m_stop_when_ready(p.flags & torrent_flags::stop_when_ready) , m_need_save_resume_data(p.flags & torrent_flags::need_save_resume) + , m_enable_dht(!bool(p.flags & torrent_flags::disable_dht)) + , m_enable_lsd(!bool(p.flags & torrent_flags::disable_lsd)) , m_max_uploads((1 << 24) - 1) , m_save_resume_flags() , m_num_uploads(0) , m_lsd_seq(0) + , m_enable_pex(!bool(p.flags & torrent_flags::disable_pex)) , m_magnet_link(false) , m_apply_ip_filter(p.flags & torrent_flags::apply_ip_filter) , m_pending_active_change(false) @@ -787,6 +790,7 @@ bool is_downloading_state(int const st) bool torrent::should_announce_dht() const { TORRENT_ASSERT(is_single_thread()); + if (!m_enable_dht) return false; if (!m_ses.announce_dht()) return false; if (!m_ses.dht()) return false; @@ -970,6 +974,12 @@ bool is_downloading_state(int const st) ret |= torrent_flags::sequential_download; if (m_stop_when_ready) ret |= torrent_flags::stop_when_ready; + if (!m_enable_dht) + ret |= torrent_flags::disable_dht; + if (!m_enable_lsd) + ret |= torrent_flags::disable_lsd; + if (!m_enable_pex) + ret |= torrent_flags::disable_pex; return ret; } @@ -1002,6 +1012,12 @@ bool is_downloading_state(int const st) set_sequential_download(bool(flags & torrent_flags::sequential_download)); if (mask & torrent_flags::stop_when_ready) stop_when_ready(bool(flags & torrent_flags::stop_when_ready)); + if (mask & torrent_flags::disable_dht) + m_enable_dht = !bool(flags & torrent_flags::disable_dht); + if (mask & torrent_flags::disable_lsd) + m_enable_lsd = !bool(flags & torrent_flags::disable_lsd); + if (mask & torrent_flags::disable_pex) + m_enable_pex = !bool(flags & torrent_flags::disable_pex); } void torrent::set_share_mode(bool s) @@ -2542,6 +2558,7 @@ bool is_downloading_state(int const st) void torrent::lsd_announce() { if (m_abort) return; + if (!m_enable_lsd) return; // if the files haven't been checked yet, we're // not ready for peers. Except, if we don't have metadata, @@ -2607,6 +2624,9 @@ bool is_downloading_state(int const st) if (m_paused) debug_log("DHT: torrent paused, no DHT announce"); + if (!m_enable_dht) + debug_log("DHT: torrent has DHT disabled flag"); + #if TORRENT_ABI_VERSION == 1 // deprecated in 1.2 if (!m_torrent_file->is_valid() && !m_url.empty()) diff --git a/src/ut_pex.cpp b/src/ut_pex.cpp index d2c8d9491..96bc06404 100644 --- a/src/ut_pex.cpp +++ b/src/ut_pex.cpp @@ -100,6 +100,8 @@ namespace libtorrent { namespace { // max_peer_entries limits the packet size void tick() override { + if (m_torrent.flags() & torrent_flags::disable_pex) return; + time_point const now = aux::time_now(); if (now - seconds(60) < m_last_msg) return; m_last_msg = now; @@ -260,6 +262,8 @@ namespace libtorrent { namespace { if (msg != extension_index) return false; if (m_message_index == 0) return false; + if (m_torrent.flags() & torrent_flags::disable_pex) return true; + if (length > 500 * 1024) { m_pc.disconnect(errors::pex_message_too_large, operation_t::bittorrent, peer_connection_interface::peer_error); @@ -463,6 +467,8 @@ namespace libtorrent { namespace { void send_ut_peer_diff() { + if (m_torrent.flags() & torrent_flags::disable_pex) return; + // if there's no change in out peer set, don't send anything if (m_tp.peers_in_msg() == 0) return; @@ -507,6 +513,8 @@ namespace libtorrent { namespace { void send_ut_peer_list() { + if (m_torrent.flags() & torrent_flags::disable_pex) return; + entry pex; // leave the dropped string empty pex["dropped"].string(); diff --git a/test/test_flags.cpp b/test/test_flags.cpp index cae8388a6..570a5ff04 100644 --- a/test/test_flags.cpp +++ b/test/test_flags.cpp @@ -166,3 +166,25 @@ TORRENT_TEST(flag_stop_when_ready) //test_set_after_add(torrent_flags::stop_when_ready); test_unset_after_add(torrent_flags::stop_when_ready); } + +TORRENT_TEST(flag_disable_dht) +{ + test_add_and_get_flags(torrent_flags::disable_dht); + test_set_after_add(torrent_flags::disable_dht); + test_unset_after_add(torrent_flags::disable_dht); +} + + +TORRENT_TEST(flag_disable_lsd) +{ + test_add_and_get_flags(torrent_flags::disable_lsd); + test_set_after_add(torrent_flags::disable_lsd); + test_unset_after_add(torrent_flags::disable_lsd); +} + +TORRENT_TEST(flag_disable_pex) +{ + test_add_and_get_flags(torrent_flags::disable_pex); + test_set_after_add(torrent_flags::disable_pex); + test_unset_after_add(torrent_flags::disable_pex); +}