diff --git a/CMakeLists.txt b/CMakeLists.txt index 7416f87f8..f1f7bf9de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ set(sources # -- kademlia -- set(kademlia_sources + dht_state dht_storage dos_blocker dht_tracker diff --git a/Jamfile b/Jamfile index 0629f3f2d..50607c867 100644 --- a/Jamfile +++ b/Jamfile @@ -690,6 +690,7 @@ SOURCES = ; KADEMLIA_SOURCES = + dht_state dht_storage dht_tracker msg diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index b3878f669..7fb2ece52 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -182,6 +182,7 @@ nobase_include_HEADERS = \ extensions/ut_metadata.hpp \ extensions/ut_pex.hpp \ \ + kademlia/dht_state.hpp \ kademlia/dht_storage.hpp \ kademlia/dht_tracker.hpp \ kademlia/dht_observer.hpp \ diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index ee41bf85e..6248c194a 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -75,6 +75,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/disk_io_job.hpp" // block_cache_reference #include "libtorrent/peer_class_type_filter.hpp" #include "libtorrent/kademlia/dht_observer.hpp" +#include "libtorrent/kademlia/dht_state.hpp" #include "libtorrent/resolver.hpp" #include "libtorrent/invariant_check.hpp" #include "libtorrent/extensions.hpp" @@ -113,11 +114,6 @@ namespace libtorrent class item; } - struct bencode_map_entry; - - typedef std::function dht_extension_handler_t; - struct listen_socket_t { listen_socket_t() @@ -180,7 +176,10 @@ namespace libtorrent struct tracker_logger; #endif - TORRENT_EXPORT std::pair settings_map(); +#ifndef TORRENT_DISABLE_DHT + TORRENT_EXTRA_EXPORT dht_settings read_dht_settings(bdecode_node const& e); + TORRENT_EXTRA_EXPORT entry save_dht_settings(dht_settings const& settings); +#endif // this is the link between the main thread and the // thread started to run the main downloader loop @@ -330,10 +329,11 @@ namespace libtorrent void add_dht_router(std::pair const& node); void set_dht_settings(dht_settings const& s); dht_settings const& get_dht_settings() const { return m_dht_settings; } + void set_dht_state(dht::dht_state const& state); void set_dht_storage(dht::dht_storage_constructor_type sc); void start_dht(); void stop_dht(); - void start_dht(entry const& startup_state); + void start_dht(dht::dht_state const& startup_state); bool has_dht() const override; // this is called for torrents when they are started @@ -928,7 +928,7 @@ namespace libtorrent , tcp::endpoint bind_ep, int flags, error_code& ec); #ifndef TORRENT_DISABLE_DHT - entry m_dht_state; + dht::dht_state m_dht_state; #endif // this is initialized to the unchoke_interval diff --git a/include/libtorrent/kademlia/dht_state.hpp b/include/libtorrent/kademlia/dht_state.hpp new file mode 100644 index 000000000..4ce02e88b --- /dev/null +++ b/include/libtorrent/kademlia/dht_state.hpp @@ -0,0 +1,77 @@ +/* + +Copyright (c) 2016, Arvid Norberg, Alden Torres +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef LIBTORRENT_DHT_STATE_HPP +#define LIBTORRENT_DHT_STATE_HPP + +#include +#include +#include + +#include + +#include + +namespace libtorrent +{ + struct bdecode_node; +} + +namespace libtorrent { +namespace dht +{ + // This structure helps to store and load the state + // of the ``dht_tracker``. + // At this moment the library is only a dual stack + // implementation of the DHT. See BEP38_ + // + // .. _BEP32: http://bittorrent.org/beps/bep_0032.html + struct TORRENT_EXPORT dht_state + { + dht_state() = default; + + // the id of the IPv4 node + node_id nid; + // the id of the IPv6 node + node_id nid6; + + // the bootstrap nodes saved from the IPv4 buckets node + std::vector nodes; + // the bootstrap nodes saved from the IPv6 buckets node + std::vector nodes6; + }; + + TORRENT_EXTRA_EXPORT dht_state read_dht_state(bdecode_node const& e); + TORRENT_EXTRA_EXPORT entry save_dht_state(dht_state const& state); +}} + +#endif // LIBTORRENT_DHT_STATE_HPP diff --git a/include/libtorrent/kademlia/dht_tracker.hpp b/include/libtorrent/kademlia/dht_tracker.hpp index af253c885..a958d0b2c 100644 --- a/include/libtorrent/kademlia/dht_tracker.hpp +++ b/include/libtorrent/kademlia/dht_tracker.hpp @@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include @@ -71,10 +72,10 @@ namespace libtorrent { namespace dht , dht_settings const& settings , counters& cnt , dht_storage_interface& storage - , entry const& state); + , dht_state const& state); virtual ~dht_tracker(); - void start(entry const& bootstrap + void start(dht_state const& bootstrap , find_data::nodes_callback const& f); void stop(); @@ -85,7 +86,7 @@ namespace libtorrent { namespace dht void add_node(udp::endpoint const& node); void add_router_node(udp::endpoint const& node); - entry state() const; + dht_state state() const; enum flags_t { flag_seed = 1, flag_implied_port = 2 }; void get_peers(sha1_hash const& ih diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 94a9ddfd2..5d5fdc47b 100644 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/settings_pack.hpp" #include "libtorrent/session_handle.hpp" #include "libtorrent/session_settings.hpp" +#include "libtorrent/kademlia/dht_state.hpp" #include "libtorrent/kademlia/dht_storage.hpp" #ifndef TORRENT_NO_DEPRECATE @@ -148,9 +149,16 @@ namespace libtorrent libtorrent::dht_settings dht_settings; + dht::dht_state dht_state; + dht::dht_storage_constructor_type dht_storage_constructor; }; + // This function helps to construct a ``session_params`` from a + // bencoded data generated by ``session_handle::save_state`` + TORRENT_EXPORT session_params read_session_params(bdecode_node const& e + , std::uint32_t flags = 0xffffffff); + // The session holds all state that spans multiple torrents. Among other // things it runs the network loop and manages all torrents. Once it's // created, the session object will spawn the main thread that will do all @@ -158,7 +166,7 @@ namespace libtorrent // torrents to participate in. // // You have some control over session configuration through the - // ``session::apply_settings()`` member function. To change one or more + // ``session_handle::apply_settings()`` member function. To change one or more // configuration options, create a settings_pack. object and fill it with // the settings to be set and pass it in to ``session::apply_settings()``. // diff --git a/simulation/test_dht_rate_limit.cpp b/simulation/test_dht_rate_limit.cpp index e671d6602..30942b2c1 100644 --- a/simulation/test_dht_rate_limit.cpp +++ b/simulation/test_dht_rate_limit.cpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/udp_socket.hpp" #include "libtorrent/kademlia/dht_tracker.hpp" +#include "libtorrent/kademlia/dht_state.hpp" #include "libtorrent/performance_counters.hpp" #include "libtorrent/entry.hpp" #include "libtorrent/session_settings.hpp" @@ -109,9 +110,9 @@ TORRENT_TEST(dht_rate_limit) int const num_packets = 2000; counters cnt; - entry state; + dht::dht_state state; std::unique_ptr dht_storage(dht::dht_default_storage_constructor(dhtsett)); - std::shared_ptr dht = std::make_shared( + auto dht = std::make_shared( &o, dht_ios, std::bind(&udp_socket::send, &sock, _1, _2, _3, _4) , dhtsett, cnt, *dht_storage, state); diff --git a/simulation/test_dht_storage.cpp b/simulation/test_dht_storage.cpp index ee9d70279..359adcc41 100644 --- a/simulation/test_dht_storage.cpp +++ b/simulation/test_dht_storage.cpp @@ -68,14 +68,6 @@ namespace return sett; } - sha1_hash to_hash(char const *s) { - std::stringstream hash(s); - sha1_hash ret; - hash >> ret; - TORRENT_ASSERT(!hash.fail()); - return ret; - } - std::unique_ptr create_default_dht_storage( dht_settings const& sett) { diff --git a/src/Makefile.am b/src/Makefile.am index 2bbbdc125..d9066a2be 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,7 @@ lib_LTLIBRARIES = libtorrent-rasterbar.la if ENABLE_DHT KADEMLIA_SOURCES = \ + kademlia/dht_state.cpp \ kademlia/dht_storage.cpp \ kademlia/dht_tracker.cpp \ kademlia/find_data.cpp \ diff --git a/src/kademlia/dht_state.cpp b/src/kademlia/dht_state.cpp new file mode 100644 index 000000000..4c6046afd --- /dev/null +++ b/src/kademlia/dht_state.cpp @@ -0,0 +1,100 @@ +/* + +Copyright (c) 2016, Arvid Norberg, Alden Torres +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/kademlia/dht_state.hpp" + +#include +#include + +namespace libtorrent { +namespace dht +{ +namespace +{ + node_id extract_node_id(bdecode_node const& e, string_view key) + { + if (e.type() != bdecode_node::dict_t) return node_id(); + auto nid = e.dict_find_string_value(key); + if (nid.size() != 20) return node_id(); + return node_id(nid); + } + + entry save_nodes(std::vector const& nodes) + { + entry ret(entry::list_t); + entry::list_type& list = ret.list(); + for (auto const& ep : nodes) + { + std::string node; + std::back_insert_iterator out(node); + detail::write_endpoint(ep, out); + list.push_back(entry(node)); + } + return ret; + } +} // anonymous namespace + + dht_state read_dht_state(bdecode_node const& e) + { + dht_state ret; + + if (e.type() != bdecode_node::dict_t) return ret; + + ret.nid = extract_node_id(e, "node-id"); +#if TORRENT_USE_IPV6 + ret.nid6 = extract_node_id(e, "node-id6"); +#endif + + if (bdecode_node const nodes = e.dict_find_list("nodes")) + detail::read_endpoint_list(nodes, ret.nodes); +#if TORRENT_USE_IPV6 + if (bdecode_node const nodes = e.dict_find_list("nodes6")) + detail::read_endpoint_list(nodes, ret.nodes6); +#endif + + return ret; + } + + entry save_dht_state(dht_state const& state) + { + entry ret(entry::dictionary_t); + ret["node-id"] = state.nid.to_string(); + entry const nodes = save_nodes(state.nodes); + if (!nodes.list().empty()) ret["nodes"] = nodes; +#if TORRENT_USE_IPV6 + ret["node-id6"] = state.nid6.to_string(); + entry const nodes6 = save_nodes(state.nodes6); + if (!nodes6.list().empty()) ret["nodes6"] = nodes6; +#endif + return ret; + } +}} diff --git a/src/kademlia/dht_tracker.cpp b/src/kademlia/dht_tracker.cpp index 1aa22ea80..ce11422c8 100644 --- a/src/kademlia/dht_tracker.cpp +++ b/src/kademlia/dht_tracker.cpp @@ -72,15 +72,6 @@ namespace libtorrent { namespace dht time_duration const key_refresh = duration_cast(minutes(5)); - node_id extract_node_id(entry const& e, std::string const& key) - { - if (e.type() != entry::dictionary_t) return (node_id::min)(); - entry const* nid = e.find_key(key); - if (nid == nullptr || nid->type() != entry::string_t || nid->string().length() != 20) - return (node_id::min)(); - return node_id(nid->string().c_str()); - } - void add_dht_counters(node const& dht, counters& c) { int nodes, replacements, allocated_observers; @@ -101,13 +92,13 @@ namespace libtorrent { namespace dht , dht_settings const& settings , counters& cnt , dht_storage_interface& storage - , entry const& state) + , dht_state const& state) : m_counters(cnt) , m_storage(storage) - , m_dht(udp::v4(), this, settings, extract_node_id(state, "node-id") + , m_dht(udp::v4(), this, settings, state.nid , observer, cnt, m_nodes, storage) #if TORRENT_USE_IPV6 - , m_dht6(udp::v6(), this, settings, extract_node_id(state, "node-id6") + , m_dht6(udp::v6(), this, settings, state.nid6 , observer, cnt, m_nodes, storage) #endif , m_send_fun(send_fun) @@ -161,28 +152,9 @@ namespace libtorrent { namespace dht // defined in node.cpp void nop(); - void dht_tracker::start(entry const& bootstrap + void dht_tracker::start(dht_state const& bootstrap , find_data::nodes_callback const& f) { - std::vector initial_nodes; -#if TORRENT_USE_IPV6 - std::vector initial_nodes6; -#endif - - if (bootstrap.type() == entry::dictionary_t) - { - TORRENT_TRY { - if (entry const* nodes = bootstrap.find_key("nodes")) - read_endpoint_list(nodes, initial_nodes); - } TORRENT_CATCH(std::exception&) {} -#if TORRENT_USE_IPV6 - TORRENT_TRY{ - if (entry const* nodes = bootstrap.find_key("nodes6")) - read_endpoint_list(nodes, initial_nodes6); - } TORRENT_CATCH(std::exception&) {} -#endif - } - error_code ec; refresh_key(ec); @@ -198,9 +170,9 @@ namespace libtorrent { namespace dht m_refresh_timer.expires_from_now(seconds(5), ec); m_refresh_timer.async_wait(std::bind(&dht_tracker::refresh_timeout, self(), _1)); - m_dht.bootstrap(initial_nodes, f); + m_dht.bootstrap(bootstrap.nodes, f); #if TORRENT_USE_IPV6 - m_dht6.bootstrap(initial_nodes6, f); + m_dht6.bootstrap(bootstrap.nodes6, f); #endif } @@ -585,40 +557,33 @@ namespace libtorrent { namespace dht void add_node_fun(void* userdata, node_entry const& e) { - entry* n = static_cast(userdata); - std::string node; - std::back_insert_iterator out(node); - write_endpoint(e.ep(), out); - n->list().push_back(entry(node)); + auto v = static_cast*>(userdata); + v->push_back(e.ep()); } - void save_nodes(entry& ret, node const& dht, std::string const& key) + std::vector save_nodes(node const& dht) { - entry nodes(entry::list_t); - dht.m_table.for_each_node(&add_node_fun, &add_node_fun, &nodes); + std::vector ret; + dht.m_table.for_each_node(&add_node_fun, &add_node_fun, &ret); bucket_t cache; dht.replacement_cache(cache); for (auto const& b : cache) { - std::string node; - std::back_insert_iterator out(node); - write_endpoint(b.ep(), out); - nodes.list().push_back(entry(node)); + ret.push_back(b.ep()); } - if (!nodes.list().empty()) - ret[key] = nodes; + return ret; } } // anonymous namespace - entry dht_tracker::state() const + dht_state dht_tracker::state() const { - entry ret(entry::dictionary_t); - save_nodes(ret, m_dht, "nodes"); - ret["node-id"] = m_dht.nid().to_string(); + dht_state ret; + ret.nid = m_dht.nid(); + ret.nodes = save_nodes(m_dht); #if TORRENT_USE_IPV6 - save_nodes(ret, m_dht6, "nodes6"); - ret["node-id6"] = m_dht6.nid().to_string(); + ret.nid6 = m_dht6.nid(); + ret.nodes6 = save_nodes(m_dht6); #endif return ret; } diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index 4b34d306e..d738384a6 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -212,6 +212,7 @@ void node::bootstrap(std::vector const& nodes for (auto const& n : nodes) { + if (n.protocol() != protocol()) continue; #ifndef TORRENT_DISABLE_LOGGING ++count; #endif @@ -1196,7 +1197,11 @@ node::protocol_descriptor const& node::map_protocol_to_descriptor(udp protocol) } TORRENT_ASSERT_FAIL(); +#ifndef BOOST_NO_EXCEPTIONS throw std::out_of_range("unknown protocol"); +#else + std::terminate(); +#endif } } } // namespace libtorrent::dht diff --git a/src/session.cpp b/src/session.cpp index 73819a605..6156d6504 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -287,6 +287,45 @@ namespace libtorrent // configurations this will give a link error void TORRENT_CFG() {} + session_params read_session_params(bdecode_node const& e, std::uint32_t const flags) + { + session_params params; + + bdecode_node settings; + if (e.type() != bdecode_node::dict_t) return params; + + if (flags & session_handle::save_settings) + { + settings = e.dict_find_dict("settings"); + if (settings) + { + params.settings = load_pack_from_dict(settings); + } + } + +#ifndef TORRENT_DISABLE_DHT + if (flags & session_handle::save_dht_settings) + { + settings = e.dict_find_dict("dht"); + if (settings) + { + params.dht_settings = aux::read_dht_settings(settings); + } + } + + if (flags & session_handle::save_dht_state) + { + settings = e.dict_find_dict("dht state"); + if (settings) + { + params.dht_state = dht::read_dht_state(settings); + } + } +#endif + + return params; + } + void session::start(session_params params, io_service* ios) { bool const internal_executor = ios == nullptr; @@ -308,8 +347,11 @@ namespace libtorrent } #endif - set_dht_settings(params.dht_settings); - set_dht_storage(params.dht_storage_constructor); +#ifndef TORRENT_DISABLE_DHT + m_impl->set_dht_settings(params.dht_settings); + m_impl->set_dht_state(std::move(params.dht_state)); + m_impl->set_dht_storage(params.dht_storage_constructor); +#endif m_impl->start_session(std::move(params.settings)); diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 8ec696843..392b2bee1 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -195,6 +195,82 @@ namespace libtorrent { namespace aux { +#ifndef TORRENT_DISABLE_DHT + dht_settings read_dht_settings(bdecode_node const& e) + { + dht_settings sett; + + if (e.type() != bdecode_node::dict_t) return sett; + + bdecode_node val; + val = e.dict_find_int("max_peers_reply"); + if (val) sett.max_peers_reply = val.int_value(); + val = e.dict_find_int("search_branching"); + if (val) sett.search_branching = val.int_value(); + val = e.dict_find_int("max_fail_count"); + if (val) sett.max_fail_count = val.int_value(); + val = e.dict_find_int("max_torrents"); + if (val) sett.max_torrents = val.int_value(); + val = e.dict_find_int("max_dht_items"); + if (val) sett.max_dht_items = val.int_value(); + val = e.dict_find_int("max_peers"); + if (val) sett.max_peers = val.int_value(); + val = e.dict_find_int("max_torrent_search_reply"); + if (val) sett.max_torrent_search_reply = val.int_value(); + val = e.dict_find_int("restrict_routing_ips"); + if (val) sett.restrict_routing_ips = (val.int_value() != 0); + val = e.dict_find_int("restrict_search_ips"); + if (val) sett.restrict_search_ips = (val.int_value() != 0); + val = e.dict_find_int("extended_routing_table"); + if (val) sett.extended_routing_table = (val.int_value() != 0); + val = e.dict_find_int("aggressive_lookups"); + if (val) sett.aggressive_lookups = (val.int_value() != 0); + val = e.dict_find_int("privacy_lookups"); + if (val) sett.privacy_lookups = (val.int_value() != 0); + val = e.dict_find_int("enforce_node_id"); + if (val) sett.enforce_node_id = (val.int_value() != 0); + val = e.dict_find_int("ignore_dark_internet"); + if (val) sett.ignore_dark_internet = (val.int_value() != 0); + val = e.dict_find_int("block_timeout"); + if (val) sett.block_timeout = val.int_value(); + val = e.dict_find_int("block_ratelimit"); + if (val) sett.block_ratelimit = val.int_value(); + val = e.dict_find_int("read_only"); + if (val) sett.read_only = (val.int_value() != 0); + val = e.dict_find_int("item_lifetime"); + if (val) sett.item_lifetime = val.int_value(); + + return sett; + } + + entry save_dht_settings(dht_settings const& settings) + { + entry e; + entry::dictionary_type& dht_sett = e.dict(); + + dht_sett["max_peers_reply"] = settings.max_peers_reply; + dht_sett["search_branching"] = settings.search_branching; + dht_sett["max_fail_count"] = settings.max_fail_count; + dht_sett["max_torrents"] = settings.max_torrents; + dht_sett["max_dht_items"] = settings.max_dht_items; + dht_sett["max_peers"] = settings.max_peers; + dht_sett["max_torrent_search_reply"] = settings.max_torrent_search_reply; + dht_sett["restrict_routing_ips"] = settings.restrict_routing_ips; + dht_sett["restrict_search_ips"] = settings.restrict_search_ips; + dht_sett["extended_routing_table"] = settings.extended_routing_table; + dht_sett["aggressive_lookups"] = settings.aggressive_lookups; + dht_sett["privacy_lookups"] = settings.privacy_lookups; + dht_sett["enforce_node_id"] = settings.enforce_node_id; + dht_sett["ignore_dark_internet"] = settings.ignore_dark_internet; + dht_sett["block_timeout"] = settings.block_timeout; + dht_sett["block_ratelimit"] = settings.block_ratelimit; + dht_sett["read_only"] = settings.read_only; + dht_sett["item_lifetime"] = settings.item_lifetime; + + return e; + } +#endif // TORRENT_DISABLE_DHT + void session_impl::init_peer_class_filter(bool unlimited_local) { // set the default peer_class_filter to use the local peer class @@ -552,31 +628,12 @@ namespace aux { #ifndef TORRENT_DISABLE_DHT if (flags & session::save_dht_settings) { - entry::dictionary_type& dht_sett = e["dht"].dict(); - - dht_sett["max_peers_reply"] = m_dht_settings.max_peers_reply; - dht_sett["search_branching"] = m_dht_settings.search_branching; - dht_sett["max_fail_count"] = m_dht_settings.max_fail_count; - dht_sett["max_torrents"] = m_dht_settings.max_torrents; - dht_sett["max_dht_items"] = m_dht_settings.max_dht_items; - dht_sett["max_peers"] = m_dht_settings.max_peers; - dht_sett["max_torrent_search_reply"] = m_dht_settings.max_torrent_search_reply; - dht_sett["restrict_routing_ips"] = m_dht_settings.restrict_routing_ips; - dht_sett["restrict_search_ips"] = m_dht_settings.restrict_search_ips; - dht_sett["extended_routing_table"] = m_dht_settings.extended_routing_table; - dht_sett["aggressive_lookups"] = m_dht_settings.aggressive_lookups; - dht_sett["privacy_lookups"] = m_dht_settings.privacy_lookups; - dht_sett["enforce_node_id"] = m_dht_settings.enforce_node_id; - dht_sett["ignore_dark_internet"] = m_dht_settings.ignore_dark_internet; - dht_sett["block_timeout"] = m_dht_settings.block_timeout; - dht_sett["block_ratelimit"] = m_dht_settings.block_ratelimit; - dht_sett["read_only"] = m_dht_settings.read_only; - dht_sett["item_lifetime"] = m_dht_settings.item_lifetime; + e["dht"] = save_dht_settings(m_dht_settings); } if (m_dht && (flags & session::save_dht_state)) { - e["dht state"] = m_dht->state(); + e["dht state"] = dht::save_dht_state(m_dht->state()); } #endif @@ -605,57 +662,21 @@ namespace aux { #ifndef TORRENT_DISABLE_DHT bool need_update_dht = false; - if (flags & session::save_dht_settings) + if (flags & session_handle::save_dht_settings) { settings = e->dict_find_dict("dht"); if (settings) { - bdecode_node val; - val = settings.dict_find_int("max_peers_reply"); - if (val) m_dht_settings.max_peers_reply = val.int_value(); - val = settings.dict_find_int("search_branching"); - if (val) m_dht_settings.search_branching = val.int_value(); - val = settings.dict_find_int("max_fail_count"); - if (val) m_dht_settings.max_fail_count = val.int_value(); - val = settings.dict_find_int("max_torrents"); - if (val) m_dht_settings.max_torrents = val.int_value(); - val = settings.dict_find_int("max_dht_items"); - if (val) m_dht_settings.max_dht_items = val.int_value(); - val = settings.dict_find_int("max_peers"); - if (val) m_dht_settings.max_peers = val.int_value(); - val = settings.dict_find_int("max_torrent_search_reply"); - if (val) m_dht_settings.max_torrent_search_reply = val.int_value(); - val = settings.dict_find_int("restrict_routing_ips"); - if (val) m_dht_settings.restrict_routing_ips = (val.int_value() != 0); - val = settings.dict_find_int("restrict_search_ips"); - if (val) m_dht_settings.restrict_search_ips = (val.int_value() != 0); - val = settings.dict_find_int("extended_routing_table"); - if (val) m_dht_settings.extended_routing_table = (val.int_value() != 0); - val = settings.dict_find_int("aggressive_lookups"); - if (val) m_dht_settings.aggressive_lookups = (val.int_value() != 0); - val = settings.dict_find_int("privacy_lookups"); - if (val) m_dht_settings.privacy_lookups = (val.int_value() != 0); - val = settings.dict_find_int("enforce_node_id"); - if (val) m_dht_settings.enforce_node_id = (val.int_value() != 0); - val = settings.dict_find_int("ignore_dark_internet"); - if (val) m_dht_settings.ignore_dark_internet = (val.int_value() != 0); - val = settings.dict_find_int("block_timeout"); - if (val) m_dht_settings.block_timeout = val.int_value(); - val = settings.dict_find_int("block_ratelimit"); - if (val) m_dht_settings.block_ratelimit = val.int_value(); - val = settings.dict_find_int("read_only"); - if (val) m_dht_settings.read_only = (val.int_value() != 0); - val = settings.dict_find_int("item_lifetime"); - if (val) m_dht_settings.item_lifetime = val.int_value(); + m_dht_settings = read_dht_settings(settings); } } - if (flags & session::save_dht_state) + if (flags & session_handle::save_dht_state) { settings = e->dict_find_dict("dht state"); if (settings) { - m_dht_state = settings; + m_dht_state = dht::read_dht_state(settings); need_update_dht = true; } } @@ -663,7 +684,7 @@ namespace aux { #ifndef TORRENT_NO_DEPRECATE bool need_update_proxy = false; - if (flags & session::save_proxy) + if (flags & session_handle::save_proxy) { settings = e->dict_find_dict("proxy"); if (settings) @@ -702,7 +723,7 @@ namespace aux { } #endif - if (flags & session::save_settings) + if (flags & session_handle::save_settings) { settings = e->dict_find_dict("settings"); if (settings) @@ -5579,7 +5600,7 @@ namespace aux { } } - void session_impl::start_dht(entry const& startup_state) + void session_impl::start_dht(dht::dht_state const& startup_state) { INVARIANT_CHECK; @@ -5590,7 +5611,7 @@ namespace aux { m_dht_storage = m_dht_storage_constructor(m_dht_settings); m_dht = std::make_shared( - static_cast(this) + static_cast(this) , m_io_service , std::bind(&session_impl::send_udp_packet, this, false, _1, _2, _3, _4) , m_dht_settings @@ -5628,6 +5649,11 @@ namespace aux { m_dht_settings = settings; } + void session_impl::set_dht_state(dht::dht_state const& state) + { + m_dht_state = state; + } + void session_impl::set_dht_storage(dht::dht_storage_constructor_type sc) { m_dht_storage_constructor = sc; @@ -5636,14 +5662,20 @@ namespace aux { #ifndef TORRENT_NO_DEPRECATE entry session_impl::dht_state() const { - if (!m_dht) return entry(); - return m_dht->state(); + return m_dht ? dht::save_dht_state(m_dht->state()) : entry(); } void session_impl::start_dht_deprecated(entry const& startup_state) { m_settings.set_bool(settings_pack::enable_dht, true); - start_dht(startup_state); + std::vector tmp; + bencode(std::back_inserter(tmp), startup_state); + + bdecode_node e; + error_code ec; + if (tmp.empty() || bdecode(&tmp[0], &tmp[0] + tmp.size(), e, ec) != 0) + return; + start_dht(dht::read_dht_state(e)); } #endif diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index f70d0ab7e..93264fc1b 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -102,6 +102,13 @@ sha1_hash rand_hash() return ret; } +sha1_hash to_hash(char const* s) +{ + sha1_hash ret; + aux::from_hex({s, 40}, (char*)&ret[0]); + return ret; +} + #if TORRENT_USE_IPV6 address rand_v6() { @@ -1001,6 +1008,14 @@ tcp::endpoint ep(char const* ip, int port) return ret; } +udp::endpoint uep(char const* ip, int port) +{ + error_code ec; + udp::endpoint ret(address::from_string(ip, ec), std::uint16_t(port)); + TEST_CHECK(!ec); + return ret; +} + libtorrent::address addr(char const* ip) { lt::error_code ec; diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index 1c2e23534..c114fb1a4 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -60,6 +60,7 @@ EXPORT libtorrent::tcp::endpoint rand_tcp_ep(); EXPORT libtorrent::udp::endpoint rand_udp_ep(libtorrent::address(&rand_addr)() = rand_v4); EXPORT libtorrent::sha1_hash rand_hash(); +EXPORT libtorrent::sha1_hash to_hash(char const* s); EXPORT std::map get_counters(libtorrent::session& s); @@ -112,6 +113,7 @@ EXPORT void stop_proxy(int port); EXPORT void stop_all_proxies(); EXPORT libtorrent::tcp::endpoint ep(char const* ip, int port); +EXPORT libtorrent::udp::endpoint uep(char const* ip, int port); EXPORT libtorrent::address addr(char const* ip); EXPORT libtorrent::address_v4 addr4(char const* ip); #if TORRENT_USE_IPV6 diff --git a/test/test_dht.cpp b/test/test_dht.cpp index e9224fe99..7550a2c1d 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/session.hpp" #include "libtorrent/kademlia/node.hpp" // for verify_message #include "libtorrent/bencode.hpp" +#include "libtorrent/bdecode.hpp" #include "libtorrent/socket_io.hpp" // for hash_address #include "libtorrent/broadcast_socket.hpp" // for supports_ipv6 #include "libtorrent/performance_counters.hpp" // for counters @@ -63,13 +64,6 @@ using namespace std::placeholders; namespace { -sha1_hash to_hash(char const* s) -{ - sha1_hash ret; - aux::from_hex({s, 40}, (char*)&ret[0]); - return ret; -} - void get_test_keypair(public_key& pk, secret_key& sk) { aux::from_hex({"77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548", 64}, pk.bytes.data()); @@ -3375,6 +3369,43 @@ TORRENT_TEST(compare_ip_cidr) #endif } +TORRENT_TEST(dht_state) +{ + dht_state s; + + s.nid = to_hash("0000000000000000000000000000000000000001"); + s.nodes.push_back(uep("1.1.1.1", 1)); + s.nodes.push_back(uep("2.2.2.2", 2)); + // not important that IPv6 is disabled here + s.nid6 = to_hash("0000000000000000000000000000000000000002"); + s.nodes6.push_back(uep("3.3.3.3", 3)); + s.nodes6.push_back(uep("4.4.4.4", 4)); + + entry const e = save_dht_state(s); + + std::vector tmp; + bencode(std::back_inserter(tmp), e); + + bdecode_node n; + error_code ec; + int r = bdecode(&tmp[0], &tmp[0] + tmp.size(), n, ec); + TEST_CHECK(!r); + + dht_state const s1 = read_dht_state(n); + TEST_EQUAL(s1.nid, s.nid); + TEST_CHECK(s1.nodes == s.nodes); + TEST_EQUAL(s1.nid6, s.nid6); + TEST_CHECK(s1.nodes6 == s.nodes6); + + // empty + bdecode_node n1; + dht_state const s2 = read_dht_state(n1); + TEST_EQUAL(s2.nid, node_id()); + TEST_CHECK(s2.nodes.empty()); + TEST_EQUAL(s2.nid6, node_id()); + TEST_CHECK(s2.nodes6.empty()); +} + // TODO: test obfuscated_get_peers #else diff --git a/test/test_dht_storage.cpp b/test/test_dht_storage.cpp index c7078bedb..1c7e16b12 100644 --- a/test/test_dht_storage.cpp +++ b/test/test_dht_storage.cpp @@ -68,13 +68,6 @@ namespace return sett; } - sha1_hash to_hash(char const *s) { - std::stringstream hash(s); - sha1_hash ret; - hash >> ret; - return ret; - } - bool g_storage_constructor_invoked = false; std::unique_ptr dht_custom_storage_constructor( diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 13ab9bd22..da9fe998a 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -41,13 +41,6 @@ POSSIBILITY OF SUCH DAMAGE. using namespace libtorrent; -sha1_hash to_hash(char const* s) -{ - sha1_hash ret; - aux::from_hex({s, 40}, (char*)&ret[0]); - return ret; -} - address_v4 v4(char const* str) { error_code ec; diff --git a/test/test_session_params.cpp b/test/test_session_params.cpp index 1572df0f4..de0657875 100644 --- a/test/test_session_params.cpp +++ b/test/test_session_params.cpp @@ -33,9 +33,13 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/session.hpp" #include "libtorrent/extensions.hpp" +#include "libtorrent/bencode.hpp" +#include "libtorrent/bdecode.hpp" +#include "libtorrent/hex.hpp" #include "settings.hpp" #include "test.hpp" +#include "setup_transfer.hpp" using namespace libtorrent; using namespace libtorrent::dht; @@ -95,6 +99,52 @@ TORRENT_TEST(custom_dht_storage) TEST_CHECK(ses.is_dht_running() == true); TEST_EQUAL(g_storage_constructor_invoked, true); } + +TORRENT_TEST(dht_state) +{ + settings_pack p = settings(); + p.set_bool(settings_pack::enable_dht, true); + + dht_settings sett; + sett.max_dht_items = 10000; + sett.max_peers = 20000; + + dht_state s; + s.nid = to_hash("0000000000000000000000000000000000000001"); + s.nodes.push_back(uep("1.1.1.1", 1)); + s.nodes.push_back(uep("2.2.2.2", 2)); + // not important that IPv6 is disabled here + s.nid6 = to_hash("0000000000000000000000000000000000000002"); + s.nodes6.push_back(uep("3.3.3.3", 3)); + s.nodes6.push_back(uep("4.4.4.4", 4)); + + session_params params(p); + params.dht_settings = sett; + params.dht_state = s; + + lt::session ses1(params); + TEST_CHECK(ses1.is_dht_running() == true); + entry e; + ses1.save_state(e); + + std::vector tmp; + bencode(std::back_inserter(tmp), e); + + bdecode_node n; + error_code ec; + int r = bdecode(&tmp[0], &tmp[0] + tmp.size(), n, ec); + TEST_CHECK(!r); + + session_params params1 = read_session_params(n); + TEST_EQUAL(params1.dht_settings.max_dht_items, 10000); + TEST_EQUAL(params1.dht_settings.max_peers, 20000); + + // not a chance the nid will be the fake initial ones + TEST_CHECK(params1.dht_state.nid != s.nid); +#if TORRENT_USE_IPV6 + TEST_CHECK(params1.dht_state.nid6 != s.nid6); +#endif +} #endif #ifndef TORRENT_DISABLE_EXTENSIONS