diff --git a/ChangeLog b/ChangeLog index 1dca747ea..e5db9c4ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 1.1.0 release + * support filtering which parts of session state are loaded by load_state() * deprecate support for adding torrents by HTTP URL * allow specifying which tracker to scrape in scrape_tracker * tracker response alerts from user initiated announces/scrapes are now diff --git a/bindings/python/src/session.cpp b/bindings/python/src/session.cpp index 1ee47db8f..57ff83a1a 100644 --- a/bindings/python/src/session.cpp +++ b/bindings/python/src/session.cpp @@ -529,18 +529,18 @@ namespace } #endif - void load_state(lt::session& ses, entry const& st) - { - allow_threading_guard guard; + void load_state(lt::session& ses, entry const& st, boost::uint32_t flags) + { + allow_threading_guard guard; - std::vector buf; - bencode(std::back_inserter(buf), st); - bdecode_node e; - error_code ec; - bdecode(&buf[0], &buf[0] + buf.size(), e, ec); - TORRENT_ASSERT(!ec); - ses.load_state(e); - } + std::vector buf; + bencode(std::back_inserter(buf), st); + bdecode_node e; + error_code ec; + bdecode(&buf[0], &buf[0] + buf.size(), e, ec); + TORRENT_ASSERT(!ec); + ses.load_state(e, flags); + } #ifndef TORRENT_DISABLE_DHT void dht_get_mutable_item(lt::session& ses, std::string key, std::string salt) @@ -799,7 +799,7 @@ void bind_session() .def("get_pe_settings", allow_threads(<::session::get_pe_settings)) #endif #endif - .def("load_state", &load_state) + .def("load_state", &load_state, (arg("entry"), arg("flags") = 0xffffffff)) .def("save_state", &save_state, (arg("entry"), arg("flags") = 0xffffffff)) .def("pop_alerts", &pop_alerts) .def("wait_for_alert", &wait_for_alert @@ -888,8 +888,8 @@ void bind_session() .value("save_dht_settings", lt::session::save_dht_settings) .value("save_dht_state", lt::session::save_dht_state) .value("save_encryption_settings", lt::session:: save_encryption_settings) - .value("save_as_map", lt::session::save_as_map) #ifndef TORRENT_NO_DEPRECATE + .value("save_as_map", lt::session::save_as_map) .value("save_i2p_proxy", lt::session::save_i2p_proxy) .value("save_proxy", lt::session::save_proxy) .value("save_dht_proxy", lt::session::save_dht_proxy) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index cfff11bb1..90a403b10 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -1576,6 +1576,9 @@ int main(int argc, char* argv[]) } ses.set_ip_filter(loaded_ip_filter); + ses.set_load_function(&load_torrent); + + error_code ec; #ifndef TORRENT_DISABLE_DHT dht_settings dht; @@ -1593,18 +1596,15 @@ int main(int argc, char* argv[]) ses.add_dht_router(std::make_pair( std::string("router.bitcomet.com"), 6881)); } -#endif - - ses.set_load_function(&load_torrent); std::vector in; - error_code ec; if (load_file(".ses_state", in, ec) == 0) { bdecode_node e; if (bdecode(&in[0], &in[0] + in.size(), e, ec) == 0) - ses.load_state(e); + ses.load_state(e, session::save_dht_state); } +#endif for (std::vector::iterator i = magnet_links.begin() , end(magnet_links.end()); i != end; ++i) @@ -2348,15 +2348,19 @@ int main(int argc, char* argv[]) } if (g_log_file) fclose(g_log_file); + + // we're just saving the DHT state +#ifndef TORRENT_DISABLE_DHT printf("\nsaving session state\n"); { entry session_state; - ses.save_state(session_state); + ses.save_state(session_state, session::save_dht_state); std::vector out; bencode(std::back_inserter(out), session_state); save_file(".ses_state", out); } +#endif printf("closing session"); diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index c155301fb..76d30ffb3 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -495,7 +495,7 @@ namespace libtorrent void announce_lsd(sha1_hash const& ih, int port, bool broadcast = false) TORRENT_OVERRIDE; void save_state(entry* e, boost::uint32_t flags) const; - void load_state(bdecode_node const* e); + void load_state(bdecode_node const* e, boost::uint32_t flags); bool has_connection(peer_connection* p) const TORRENT_OVERRIDE; void insert_peer(boost::shared_ptr const& c) TORRENT_OVERRIDE; diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp index f16ca0814..effb8f78f 100644 --- a/include/libtorrent/entry.hpp +++ b/include/libtorrent/entry.hpp @@ -229,7 +229,7 @@ namespace libtorrent // The const version of ``operator[]`` will only return a reference to an // existing element at the given key. If the key is not found, it will // throw ``libtorrent::type_error``. - entry& operator[](char const* key); + entry& operator[](char const* key); entry& operator[](std::string const& key); #ifndef BOOST_NO_EXCEPTIONS const entry& operator[](char const* key) const; diff --git a/include/libtorrent/session_handle.hpp b/include/libtorrent/session_handle.hpp index bd5f816a7..d387d4c9f 100644 --- a/include/libtorrent/session_handle.hpp +++ b/include/libtorrent/session_handle.hpp @@ -92,13 +92,11 @@ namespace libtorrent save_dht_state = 0x004, // save pe_settings - save_encryption_settings = 0x020, - - // internal - save_as_map = 0x040 + save_encryption_settings = 0x020 #ifndef TORRENT_NO_DEPRECATE , + save_as_map = 0x040, // saves RSS feeds save_feeds = 0x080, save_proxy = 0x008, @@ -118,11 +116,11 @@ namespace libtorrent // ``load_state`` expects a bdecode_node which can be built from a bencoded // buffer with bdecode(). // - // The ``flags`` arguments passed in to ``save_state`` can be used to - // filter which parts of the session state to save. By default, all state - // is saved (except for the individual torrents). see save_state_flags_t + // The ``flags`` argument is used to filter which parts of the session + // state to save or load. By default, all state is saved/restored (except + // for the individual torrents). see save_state_flags_t void save_state(entry& e, boost::uint32_t flags = 0xffffffff) const; - void load_state(bdecode_node const& e); + void load_state(bdecode_node const& e, boost::uint32_t flags = 0xffffffff); // .. note:: // these calls are potentially expensive and won't scale well with @@ -547,12 +545,14 @@ namespace libtorrent // deprecated in 0.15 // use load_state and save_state instead TORRENT_DEPRECATED - void load_state(entry const& ses_state); + void load_state(entry const& ses_state + , boost::uint32_t flags = 0xffffffff); TORRENT_DEPRECATED entry state() const; // deprecated in 1.1 TORRENT_DEPRECATED - void load_state(lazy_entry const& ses_state); + void load_state(lazy_entry const& ses_state + , boost::uint32_t flags = 0xffffffff); #endif // TORRENT_NO_DEPRECATE // Sets a filter that will be used to reject and accept incoming as well diff --git a/src/session_handle.cpp b/src/session_handle.cpp index cf359759b..f6d656f70 100644 --- a/src/session_handle.cpp +++ b/src/session_handle.cpp @@ -102,11 +102,12 @@ namespace libtorrent TORRENT_SYNC_CALL2(save_state, &e, flags); } - void session_handle::load_state(bdecode_node const& e) + void session_handle::load_state(bdecode_node const& e + , boost::uint32_t const flags) { // this needs to be synchronized since the lifespan // of e is tied to the caller - TORRENT_SYNC_CALL1(load_state, &e); + TORRENT_SYNC_CALL2(load_state, &e, flags); } void session_handle::get_torrent_status(std::vector* ret @@ -505,7 +506,8 @@ namespace libtorrent void session_handle::load_country_db(wchar_t const*) {} #endif // TORRENT_USE_WSTRING - void session_handle::load_state(entry const& ses_state) + void session_handle::load_state(entry const& ses_state + , boost::uint32_t const flags) { if (ses_state.type() == entry::undefined_t) return; std::vector buf; @@ -521,7 +523,7 @@ namespace libtorrent #ifndef BOOST_NO_EXCEPTIONS if (ret != 0) throw libtorrent_exception(ec); #endif - TORRENT_SYNC_CALL1(load_state, &e); + TORRENT_SYNC_CALL2(load_state, &e, flags); } entry session_handle::state() const @@ -531,7 +533,8 @@ namespace libtorrent return ret; } - void session_handle::load_state(lazy_entry const& ses_state) + void session_handle::load_state(lazy_entry const& ses_state + , boost::uint32_t const flags) { if (ses_state.type() == lazy_entry::none_t) return; std::pair buf = ses_state.data_section(); @@ -546,7 +549,7 @@ namespace libtorrent #ifndef BOOST_NO_EXCEPTIONS if (ret != 0) throw libtorrent_exception(ec); #endif - TORRENT_SYNC_CALL1(load_state, &e); + TORRENT_SYNC_CALL2(load_state, &e, flags); } #endif // TORRENT_NO_DEPRECATE diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 82a0477a9..510f0fb66 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -698,12 +698,16 @@ namespace aux { void session_impl::save_state(entry* eptr, boost::uint32_t flags) const { TORRENT_ASSERT(is_single_thread()); - TORRENT_UNUSED(flags); // potentially unused entry& e = *eptr; + // make it a dict + e.dict(); - entry::dictionary_type& sett = e["settings"].dict(); - save_settings_to_dict(m_settings, sett); + if (flags & session::save_settings) + { + entry::dictionary_type& sett = e["settings"].dict(); + save_settings_to_dict(m_settings, sett); + } #ifndef TORRENT_DISABLE_DHT if (flags & session::save_dht_settings) @@ -765,7 +769,8 @@ namespace aux { return proxy_settings(m_settings); } - void session_impl::load_state(bdecode_node const* e) + void session_impl::load_state(bdecode_node const* e + , boost::uint32_t const flags = 0xffffffff) { TORRENT_ASSERT(is_single_thread()); @@ -775,77 +780,86 @@ namespace aux { #ifndef TORRENT_DISABLE_DHT bool need_update_dht = false; // load from the old settings names - settings = e->dict_find_dict("dht"); - if (settings) + if (flags & session::save_dht_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(); - val = settings.dict_find_int("restrict_search_ips"); - if (val) m_dht_settings.restrict_search_ips = val.int_value(); - val = settings.dict_find_int("extended_routing_table"); - if (val) m_dht_settings.extended_routing_table = val.int_value(); - val = settings.dict_find_int("aggressive_lookups"); - if (val) m_dht_settings.aggressive_lookups = val.int_value(); - val = settings.dict_find_int("privacy_lookups"); - if (val) m_dht_settings.privacy_lookups = val.int_value(); - val = settings.dict_find_int("enforce_node_id"); - if (val) m_dht_settings.enforce_node_id = val.int_value(); - val = settings.dict_find_int("ignore_dark_internet"); - if (val) m_dht_settings.ignore_dark_internet = val.int_value(); - 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(); - val = settings.dict_find_int("item_lifetime"); - if (val) m_dht_settings.item_lifetime = val.int_value(); + 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(); + val = settings.dict_find_int("restrict_search_ips"); + if (val) m_dht_settings.restrict_search_ips = val.int_value(); + val = settings.dict_find_int("extended_routing_table"); + if (val) m_dht_settings.extended_routing_table = val.int_value(); + val = settings.dict_find_int("aggressive_lookups"); + if (val) m_dht_settings.aggressive_lookups = val.int_value(); + val = settings.dict_find_int("privacy_lookups"); + if (val) m_dht_settings.privacy_lookups = val.int_value(); + val = settings.dict_find_int("enforce_node_id"); + if (val) m_dht_settings.enforce_node_id = val.int_value(); + val = settings.dict_find_int("ignore_dark_internet"); + if (val) m_dht_settings.ignore_dark_internet = val.int_value(); + 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(); + val = settings.dict_find_int("item_lifetime"); + if (val) m_dht_settings.item_lifetime = val.int_value(); + } } - settings = e->dict_find_dict("dht state"); - if (settings) + if (flags & session::save_dht_state) { - m_dht_state = settings; - need_update_dht = true; + settings = e->dict_find_dict("dht state"); + if (settings) + { + m_dht_state = settings; + need_update_dht = true; + } } #endif #ifndef TORRENT_NO_DEPRECATE bool need_update_proxy = false; - settings = e->dict_find_dict("proxy"); - if (settings) + if (flags & session::save_proxy) { - bdecode_node val; - val = settings.dict_find_int("port"); - if (val) m_settings.set_int(settings_pack::proxy_port, val.int_value()); - val = settings.dict_find_int("type"); - if (val) m_settings.set_int(settings_pack::proxy_type, val.int_value()); - val = settings.dict_find_int("proxy_hostnames"); - if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val.int_value()); - val = settings.dict_find_int("proxy_peer_connections"); - if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val.int_value()); - val = settings.dict_find_string("hostname"); - if (val) m_settings.set_str(settings_pack::proxy_hostname, val.string_value()); - val = settings.dict_find_string("password"); - if (val) m_settings.set_str(settings_pack::proxy_password, val.string_value()); - val = settings.dict_find_string("username"); - if (val) m_settings.set_str(settings_pack::proxy_username, val.string_value()); - need_update_proxy = true; + settings = e->dict_find_dict("proxy"); + if (settings) + { + bdecode_node val; + val = settings.dict_find_int("port"); + if (val) m_settings.set_int(settings_pack::proxy_port, val.int_value()); + val = settings.dict_find_int("type"); + if (val) m_settings.set_int(settings_pack::proxy_type, val.int_value()); + val = settings.dict_find_int("proxy_hostnames"); + if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val.int_value()); + val = settings.dict_find_int("proxy_peer_connections"); + if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val.int_value()); + val = settings.dict_find_string("hostname"); + if (val) m_settings.set_str(settings_pack::proxy_hostname, val.string_value()); + val = settings.dict_find_string("password"); + if (val) m_settings.set_str(settings_pack::proxy_password, val.string_value()); + val = settings.dict_find_string("username"); + if (val) m_settings.set_str(settings_pack::proxy_username, val.string_value()); + need_update_proxy = true; + } } settings = e->dict_find_dict("encryption"); @@ -862,39 +876,49 @@ namespace aux { if (val) m_settings.set_int(settings_pack::allowed_enc_level, val.int_value()); } - settings = e->dict_find_list("feeds"); - if (settings) + if (flags & session::save_feeds) { - m_feeds.reserve(settings.list_size()); - for (int i = 0; i < settings.list_size(); ++i) + settings = e->dict_find_list("feeds"); + if (settings) { - if (settings.list_at(i).type() != bdecode_node::dict_t) continue; - boost::shared_ptr f(new_feed(*this, feed_settings())); - f->load_state(settings.list_at(i)); - f->update_feed(); - m_feeds.push_back(f); + m_feeds.reserve(settings.list_size()); + for (int i = 0; i < settings.list_size(); ++i) + { + if (settings.list_at(i).type() != bdecode_node::dict_t) continue; + boost::shared_ptr f(new_feed(*this, feed_settings())); + f->load_state(settings.list_at(i)); + f->update_feed(); + m_feeds.push_back(f); + } + update_rss_feeds(); } - update_rss_feeds(); } #endif - settings = e->dict_find_dict("settings"); - if (settings) - { - // apply_settings_pack will update dht and proxy - boost::shared_ptr pack = load_pack_from_dict(settings); - apply_settings_pack(pack); - } - else + if (flags & session::save_settings) { + settings = e->dict_find_dict("settings"); + if (settings) + { + // apply_settings_pack will update dht and proxy + boost::shared_ptr pack = load_pack_from_dict(settings); + apply_settings_pack(pack); #ifndef TORRENT_DISABLE_DHT - if (need_update_dht) update_dht(); + need_update_dht = false; #endif #ifndef TORRENT_NO_DEPRECATE - if (need_update_proxy) update_proxy(); + need_update_proxy = false; #endif + } } +#ifndef TORRENT_DISABLE_DHT + if (need_update_dht) update_dht(); +#endif +#ifndef TORRENT_NO_DEPRECATE + if (need_update_proxy) update_proxy(); +#endif + #ifndef TORRENT_DISABLE_EXTENSIONS for (ses_extension_list_t::iterator i = m_ses_extensions.begin() , end(m_ses_extensions.end()); i != end; ++i) diff --git a/test/test_session.cpp b/test/test_session.cpp index 7b30365bc..2c6e4d745 100644 --- a/test/test_session.cpp +++ b/test/test_session.cpp @@ -38,6 +38,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/session_stats.hpp" #include "libtorrent/performance_counters.hpp" +#include "libtorrent/bdecode.hpp" +#include "libtorrent/bencode.hpp" using namespace libtorrent; namespace lt = libtorrent; @@ -105,4 +107,107 @@ TORRENT_TEST(session_stats) TEST_EQUAL(stats[i].value_index, i); } } +#if __cplusplus >= 201103L + +template +void test_save_restore(Set setup, Save s, Default d, Load l) +{ + entry st; + { + settings_pack p; + setup(p); + lt::session ses(p); + s(ses, st); + } + + { + settings_pack p; + d(p); + lt::session ses(p); + // the loading function takes a bdecode_node, so we have to transform the + // entry + printf("%s\n", st.to_string().c_str()); + std::vector buf; + bencode(std::back_inserter(buf), st); + bdecode_node state; + error_code ec; + int ret = bdecode(buf.data(), buf.data() + buf.size() + , state, ec, nullptr, 100, 1000); + TEST_EQUAL(ret, 0); + if (ec) + { + printf("bdecode: %s\n", ec.message().c_str()); + printf("%s\n", std::string(buf.data(), buf.size()).c_str()); + } + TEST_CHECK(!ec); + l(ses, state); + } +} + +TORRENT_TEST(save_restore_state) +{ + test_save_restore( + [](settings_pack& p) { + // set the cache size + p.set_int(settings_pack::cache_size, 1337); + }, + [](lt::session& ses, entry& st) { + ses.save_state(st); + }, + [](settings_pack& p) { + p.set_int(settings_pack::cache_size, 90); + }, + [](lt::session& ses, bdecode_node& st) { + ses.load_state(st); + // make sure we loaded the cache size correctly + settings_pack sett = ses.get_settings(); + TEST_EQUAL(sett.get_int(settings_pack::cache_size), 1337); + }); +} + +TORRENT_TEST(save_restore_state_save_filter) +{ + test_save_restore( + [](settings_pack& p) { + // set the cache size + p.set_int(settings_pack::cache_size, 1337); + }, + [](lt::session& ses, entry& st) { + // save everything _but_ the settings + ses.save_state(st, ~session::save_settings); + }, + [](settings_pack& p) { + p.set_int(settings_pack::cache_size, 90); + }, + [](lt::session& ses, bdecode_node& st) { + ses.load_state(st); + // make sure whatever we loaded did not include the cache size + settings_pack sett = ses.get_settings(); + TEST_EQUAL(sett.get_int(settings_pack::cache_size), 90); + }); +} + +TORRENT_TEST(save_restore_state_load_filter) +{ + test_save_restore( + [](settings_pack& p) { + // set the cache size + p.set_int(settings_pack::cache_size, 1337); + }, + [](lt::session& ses, entry& st) { + // save everything + ses.save_state(st); + }, + [](settings_pack& p) { + p.set_int(settings_pack::cache_size, 90); + }, + [](lt::session& ses, bdecode_node& st) { + // load everything _but_ the settings + ses.load_state(st, ~session::save_settings); + settings_pack sett = ses.get_settings(); + TEST_EQUAL(sett.get_int(settings_pack::cache_size), 90); + }); +} + +#endif