From d505f93d7a9742ca2d48d92378cd21904eb390bb Mon Sep 17 00:00:00 2001 From: arvidn Date: Thu, 10 Dec 2015 01:56:33 -0500 Subject: [PATCH] port sim tests to use the new setup_swarm API --- include/libtorrent/torrent.hpp | 3 +- simulation/setup_swarm.cpp | 154 ++++++++++++----- simulation/setup_swarm.hpp | 49 +++++- simulation/test_auto_manage.cpp | 15 +- simulation/test_http_connection.cpp | 1 - simulation/test_metadata_extension.cpp | 229 ++++++++----------------- simulation/test_pe_crypto.cpp | 155 +++++++++-------- simulation/test_super_seeding.cpp | 8 +- simulation/test_swarm.cpp | 95 ++++++++-- simulation/test_torrent_status.cpp | 120 ++++++------- simulation/test_tracker.cpp | 161 ++++++++--------- simulation/test_trackers_extension.cpp | 190 +++++++++++--------- simulation/test_transfer.cpp | 32 +--- simulation/test_utp.cpp | 170 ++++-------------- src/lt_trackers.cpp | 7 +- src/peer_connection.cpp | 7 +- src/torrent.cpp | 78 ++++----- test/settings.cpp | 5 + 18 files changed, 729 insertions(+), 750 deletions(-) diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 4a3f861e2..86052f3a7 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -243,7 +243,8 @@ namespace libtorrent // set to true when this torrent has been paused but // is waiting to finish all current download requests - // before actually closing all connections + // before actually closing all connections, When in graceful pause mode, + // m_allow_peers is also false. bool m_graceful_pause_mode:1; // state subscription. If set, a pointer to this torrent diff --git a/simulation/setup_swarm.cpp b/simulation/setup_swarm.cpp index 61f8c778e..86154e32e 100644 --- a/simulation/setup_swarm.cpp +++ b/simulation/setup_swarm.cpp @@ -52,14 +52,6 @@ using namespace sim; namespace { - std::string save_path(int swarm_id, int idx) - { - char path[200]; - snprintf(path, sizeof(path), "swarm-%04d-peer-%02d" - , swarm_id, idx); - return path; - } - int transfer_rate(lt::address ip) { // in order to get a heterogeneous network, the last digit in the IP @@ -104,9 +96,22 @@ sim::route dsl_config::outgoing_route(asio::ip::address ip) return sim::route().append(it->second); } -void add_extra_peers(lt::session* ses) +std::string save_path(int swarm_id, int idx) { - auto handles = ses->get_torrents(); + char path[200]; + snprintf(path, sizeof(path), "swarm-%04d-peer-%02d" + , swarm_id, idx); + return path; +} + +lt::address addr(char const* str) +{ + return lt::address::from_string(str); +} + +void add_extra_peers(lt::session& ses) +{ + auto handles = ses.get_torrents(); TEST_EQUAL(handles.size(), 1); auto h = handles[0]; @@ -114,45 +119,72 @@ void add_extra_peers(lt::session* ses) { char ep[30]; snprintf(ep, sizeof(ep), "60.0.0.%d", i + 1); - h.connect_peer(lt::tcp::endpoint( - lt::address_v4::from_string(ep), 6881)); + h.connect_peer(lt::tcp::endpoint(addr(ep), 6881)); } } -lt::torrent_status get_status(lt::session* ses) +lt::torrent_status get_status(lt::session& ses) { - auto handles = ses->get_torrents(); + auto handles = ses.get_torrents(); TEST_EQUAL(handles.size(), 1); auto h = handles[0]; return h.status(); } -bool is_seed(lt::session* ses) +bool has_metadata(lt::session& ses) { - auto handles = ses->get_torrents(); + auto handles = ses.get_torrents(); + TEST_EQUAL(handles.size(), 1); + auto h = handles[0]; + return h.status().has_metadata; +} + +bool is_seed(lt::session& ses) +{ + auto handles = ses.get_torrents(); TEST_EQUAL(handles.size(), 1); auto h = handles[0]; return h.status().is_seeding; } -int completed_pieces(lt::session* ses) +int completed_pieces(lt::session& ses) { - auto handles = ses->get_torrents(); + auto handles = ses.get_torrents(); TEST_EQUAL(handles.size(), 1); auto h = handles[0]; return h.status().num_pieces; } +void utp_only(lt::settings_pack& p) +{ + using namespace libtorrent; + p.set_bool(settings_pack::enable_outgoing_tcp, false); + p.set_bool(settings_pack::enable_incoming_tcp, false); + p.set_bool(settings_pack::enable_outgoing_utp, true); + p.set_bool(settings_pack::enable_incoming_utp, true); +} + +void enable_enc(lt::settings_pack& p) +{ + using namespace libtorrent; + p.set_bool(settings_pack::prefer_rc4, true); + p.set_int(settings_pack::in_enc_policy, settings_pack::pe_forced); + p.set_int(settings_pack::out_enc_policy, settings_pack::pe_forced); + p.set_int(settings_pack::allowed_enc_level, settings_pack::pe_both); +} + void setup_swarm(int num_nodes , swarm_test type , std::function new_session , std::function add_torrent - , std::function on_alert - , std::function terminate) + , std::function on_alert + , std::function terminate) { dsl_config network_cfg; sim::simulation sim{network_cfg}; - setup_swarm(num_nodes, type, sim, new_session, add_torrent, on_alert, terminate); + + setup_swarm(num_nodes, type, sim, new_session + , add_torrent, on_alert, terminate); } void setup_swarm(int num_nodes @@ -160,10 +192,51 @@ void setup_swarm(int num_nodes , sim::simulation& sim , std::function new_session , std::function add_torrent - , std::function on_alert - , std::function terminate) + , std::function on_alert + , std::function terminate) { - asio::io_service ios(sim, asio::ip::address_v4::from_string("0.0.0.0")); + lt::settings_pack pack = settings(); + + lt::add_torrent_params p; + p.flags &= ~lt::add_torrent_params::flag_paused; + p.flags &= ~lt::add_torrent_params::flag_auto_managed; + + setup_swarm(num_nodes, type, sim, pack, p, new_session + , add_torrent, on_alert, terminate); +} + +void setup_swarm(int num_nodes + , swarm_test type + , sim::simulation& sim + , lt::settings_pack const& default_settings + , lt::add_torrent_params const& default_add_torrent + , std::function new_session + , std::function add_torrent + , std::function on_alert + , std::function terminate) +{ + setup_swarm(num_nodes, type, sim + , default_settings + , default_add_torrent + , [](lt::session&) {} + , new_session + , add_torrent + , on_alert + , terminate); +} + +void setup_swarm(int num_nodes + , swarm_test type + , sim::simulation& sim + , lt::settings_pack const& default_settings + , lt::add_torrent_params const& default_add_torrent + , std::function init_session + , std::function new_session + , std::function add_torrent + , std::function on_alert + , std::function terminate) +{ + asio::io_service ios(sim, addr("0.0.0.0")); lt::time_point start_time(lt::clock_type::now()); std::vector > nodes; @@ -189,9 +262,9 @@ void setup_swarm(int num_nodes char ep[30]; snprintf(ep, sizeof(ep), "50.0.%d.%d", (i + 1) >> 8, (i + 1) & 0xff); io_service.push_back(boost::make_shared( - boost::ref(sim), asio::ip::address_v4::from_string(ep))); + boost::ref(sim), addr(ep))); - lt::settings_pack pack = settings(); + lt::settings_pack pack = default_settings; // make sure the sessions have different peer ids lt::peer_id pid; @@ -202,25 +275,19 @@ void setup_swarm(int num_nodes boost::shared_ptr ses = boost::make_shared(pack , boost::ref(*io_service.back())); + init_session(*ses); nodes.push_back(ses); if (i > 0) { // the other sessions should not talk to each other lt::ip_filter filter; - filter.add_rule(lt::address::from_string("0.0.0.0") - , lt::address::from_string("255.255.255.255"), lt::ip_filter::blocked); - - filter.add_rule(lt::address::from_string("50.0.0.1") - , lt::address::from_string("50.0.0.1"), 0); - + filter.add_rule(addr("0.0.0.0"), addr("255.255.255.255"), lt::ip_filter::blocked); + filter.add_rule(addr("50.0.0.1"), addr("50.0.0.1"), 0); ses->set_ip_filter(filter); } - lt::add_torrent_params p; - p.flags &= ~lt::add_torrent_params::flag_paused; - p.flags &= ~lt::add_torrent_params::flag_auto_managed; - + lt::add_torrent_params p = default_add_torrent; if (type == swarm_test::download) { // in download tests, session 0 is a downloader and every other session @@ -269,16 +336,19 @@ void setup_swarm(int num_nodes lt::torrent_handle h = at->handle; // now, connect this torrent to all the others in the swarm - for (int k = 0; k < num_nodes; ++k) + // start at 1 to avoid self-connects + for (int k = 1; k < num_nodes; ++k) { + // TODO: the pattern of creating an address from a format + // string and an integer is common. It should probably be + // factored out into its own function char ep[30]; snprintf(ep, sizeof(ep), "50.0.%d.%d", (k + 1) >> 8, (k + 1) & 0xff); - h.connect_peer(lt::tcp::endpoint( - lt::address_v4::from_string(ep), 6881)); + h.connect_peer(lt::tcp::endpoint(addr(ep), 6881)); } } - on_alert(a, ses); + on_alert(a, *ses); } }); }); @@ -290,13 +360,13 @@ void setup_swarm(int num_nodes { if (ec) return; - bool shut_down = terminate(tick, nodes[0].get()); + bool shut_down = terminate(tick, *nodes[0]); if (type == swarm_test::upload) { shut_down |= std::all_of(nodes.begin() + 1, nodes.end() , [](boost::shared_ptr const& s) - { return is_seed(s.get()); }); + { return is_seed(*s); }); if (tick > 70 * (num_nodes - 1) && !shut_down) { diff --git a/simulation/setup_swarm.hpp b/simulation/setup_swarm.hpp index dc1ec5c22..f2b5fcb06 100644 --- a/simulation/setup_swarm.hpp +++ b/simulation/setup_swarm.hpp @@ -55,21 +55,54 @@ void setup_swarm(int num_nodes , swarm_test type , std::function new_session , std::function add_torrent - , std::function on_alert - , std::function terminate); + , std::function on_alert + , std::function terminate); void setup_swarm(int num_nodes , swarm_test type , sim::simulation& sim , std::function new_session , std::function add_torrent - , std::function on_alert - , std::function terminate); + , std::function on_alert + , std::function terminate); -bool is_seed(lt::session* ses); -int completed_pieces(lt::session* ses); -void add_extra_peers(lt::session* ses); -lt::torrent_status get_status(lt::session* ses); +void setup_swarm(int num_nodes + , swarm_test type + , sim::simulation& sim + , lt::settings_pack const& default_settings + , lt::add_torrent_params const& default_add_torrent + , std::function new_session + , std::function add_torrent + , std::function on_alert + , std::function terminate); + +void setup_swarm(int num_nodes + , swarm_test type + , sim::simulation& sim + , lt::settings_pack const& default_settings + , lt::add_torrent_params const& default_add_torrent + , std::function init_session + , std::function new_session + , std::function add_torrent + , std::function on_alert + , std::function terminate); + +bool has_metadata(lt::session& ses); +bool is_seed(lt::session& ses); +int completed_pieces(lt::session& ses); +void add_extra_peers(lt::session& ses); +lt::torrent_status get_status(lt::session& ses); + +std::string save_path(int swarm_id, int idx); + +// construct an address from string +lt::address addr(char const* str); + +// disable TCP and enable uTP +void utp_only(lt::settings_pack& pack); + +// force encrypted connections +void enable_enc(lt::settings_pack& pack); struct dsl_config : sim::default_config { diff --git a/simulation/test_auto_manage.cpp b/simulation/test_auto_manage.cpp index 38c0262ee..4a11a5fe9 100644 --- a/simulation/test_auto_manage.cpp +++ b/simulation/test_auto_manage.cpp @@ -35,15 +35,16 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/settings_pack.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/deadline_timer.hpp" -#include "swarm_config.hpp" #include "settings.hpp" #include "create_torrent.hpp" #include "simulator/simulator.hpp" #include using namespace sim; +using namespace libtorrent; const int num_torrents = 10; +namespace lt = libtorrent; using sim::asio::ip::address_v4; @@ -96,11 +97,11 @@ void run_test(Settings const& sett, Setup const& setup, Test const& test) TORRENT_TEST(dont_count_slow_torrents) { run_test( - [](settings_pack& sett) { + [](lt::settings_pack& sett) { // session settings - sett.set_bool(settings_pack::dont_count_slow_torrents, true); - sett.set_int(settings_pack::active_downloads, 1); - sett.set_int(settings_pack::active_seeds, 1); + sett.set_bool(lt::settings_pack::dont_count_slow_torrents, true); + sett.set_int(lt::settings_pack::active_downloads, 1); + sett.set_int(lt::settings_pack::active_seeds, 1); }, [](lt::session& ses) { @@ -108,8 +109,8 @@ TORRENT_TEST(dont_count_slow_torrents) for (int i = 0; i < num_torrents; ++i) { lt::add_torrent_params params = create_torrent(i, false); - params.flags |= add_torrent_params::flag_auto_managed; - params.flags |= add_torrent_params::flag_paused; + params.flags |= lt::add_torrent_params::flag_auto_managed; + params.flags |= lt::add_torrent_params::flag_paused; ses.async_add_torrent(params); } }, diff --git a/simulation/test_http_connection.cpp b/simulation/test_http_connection.cpp index 6bb126657..72eb25e74 100644 --- a/simulation/test_http_connection.cpp +++ b/simulation/test_http_connection.cpp @@ -33,7 +33,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "settings.hpp" #include "setup_swarm.hpp" -#include "swarm_config.hpp" #include "simulator/simulator.hpp" #include "simulator/http_server.hpp" #include "simulator/socks_server.hpp" diff --git a/simulation/test_metadata_extension.cpp b/simulation/test_metadata_extension.cpp index 708c62944..81dca856a 100644 --- a/simulation/test_metadata_extension.cpp +++ b/simulation/test_metadata_extension.cpp @@ -32,218 +32,139 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "test_utils.hpp" -#include "swarm_config.hpp" +#include "settings.hpp" +#include "setup_swarm.hpp" #include "libtorrent/session.hpp" -#include "libtorrent/hasher.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/torrent_info.hpp" -#include "libtorrent/thread.hpp" +#include "libtorrent/add_torrent_params.hpp" +#include "libtorrent/magnet_uri.hpp" #include "libtorrent/extensions/metadata_transfer.hpp" #include "libtorrent/extensions/ut_metadata.hpp" -#include - using namespace libtorrent; +namespace lt = libtorrent; enum flags_t { - clear_files = 1, - // disconnect immediately after receiving the metadata (to test that // edge case, it caused a crash once) - disconnect = 2, + disconnect = 1, // force encryption (to make sure the plugin uses the peer_connection // API in a compatible way) - full_encryption = 4, + full_encryption = 2, // have the downloader connect to the seeder // (instead of the other way around) - reverse = 8, + reverse = 4, // only use uTP - utp = 16, + utp = 8, // upload-only mode - upload_only = 32 + upload_only = 16 }; -struct test_swarm_config : swarm_config +void run_metadata_test(int flags) { - test_swarm_config(int flags - , boost::shared_ptr (*plugin)(torrent_handle const&, void*)) - : swarm_config() - , m_flags(flags) - , m_plugin(plugin) - , m_metadata_alerts(0) - {} + int metadata_alerts = 0; - // called for every session that's added - virtual libtorrent::settings_pack add_session(int idx) override + sim::default_config cfg; + sim::simulation sim{cfg}; + + lt::settings_pack default_settings = settings(); + + if (flags & full_encryption) { - settings_pack s = swarm_config::add_session(idx); - - fprintf(stderr, " session %d\n", idx); - - fprintf(stderr, "\n==== test transfer: %s%s%s%s%s%s ====\n\n" - , (m_flags & clear_files) ? "clear-files " : "" - , (m_flags & disconnect) ? "disconnect " : "" - , (m_flags & full_encryption) ? "encryption " : "" - , (m_flags & reverse) ? "reverse " : "" - , (m_flags & utp) ? "utp " : "" - , (m_flags & upload_only) ? "upload_only " : ""); - - s.set_int(settings_pack::out_enc_policy, settings_pack::pe_forced); - s.set_int(settings_pack::in_enc_policy, settings_pack::pe_forced); - s.set_bool(settings_pack::prefer_rc4, m_flags & full_encryption); - - if (m_flags & utp) - { - s.set_bool(settings_pack::enable_incoming_utp, true); - s.set_bool(settings_pack::enable_outgoing_utp, true); - s.set_bool(settings_pack::enable_incoming_tcp, false); - s.set_bool(settings_pack::enable_outgoing_tcp, false); - } - else - { - s.set_bool(settings_pack::enable_incoming_utp, false); - s.set_bool(settings_pack::enable_outgoing_utp, false); - s.set_bool(settings_pack::enable_incoming_tcp, true); - s.set_bool(settings_pack::enable_outgoing_tcp, true); - } - - return s; + enable_enc(default_settings); } - virtual libtorrent::add_torrent_params add_torrent(int idx) override + if (flags & utp) { - add_torrent_params p = swarm_config::add_torrent(idx); - - if (m_flags & reverse) - { - p.save_path = save_path(1 - idx); - } - - if (idx == 1) - { - // this is the guy who should download the metadata. - p.info_hash = p.ti->info_hash(); - p.ti.reset(); - } - - return p; + utp_only(default_settings); } - void on_session_added(int idx, session& ses) override + lt::add_torrent_params default_add_torrent; + if (flags & upload_only) { - ses.add_extension(m_plugin); + default_add_torrent.flags |= add_torrent_params::flag_upload_mode; } - bool on_alert(libtorrent::alert const* alert - , int session_idx - , std::vector const& handles - , libtorrent::session& ses) override - { - if (alert_cast(alert)) - { - m_metadata_alerts += 1; + setup_swarm(2, (flags & reverse) ? swarm_test::upload : swarm_test::download + // add session + , [](lt::settings_pack& pack) {} + // add torrent + , [](lt::add_torrent_params& params) { + // we want to add the torrent via magnet link + params.url = lt::make_magnet_uri(*params.ti); + params.ti.reset(); + params.flags &= ~add_torrent_params::flag_upload_mode; } + // on alert + , [&](lt::alert const* a, lt::session& ses) { - // make sure this function can be called on - // torrents without metadata - if ((m_flags & disconnect) == 0) - { - handles[session_idx].status(); + if (alert_cast(a)) + { + metadata_alerts += 1; + + if (flags & disconnect) + { + ses.remove_torrent(ses.get_torrents()[0]); + } + } } - - if ((m_flags & disconnect) - && session_idx == 1 - && alert_cast(alert)) + // terminate + , [&](int ticks, lt::session& ses) -> bool { - ses.remove_torrent(handles[session_idx]); - return true; - } - return false; - } + if (flags & reverse) + { + return true; + } - virtual void on_torrent_added(int idx, torrent_handle h) override - { - if (idx == 0) return; + if (ticks > 70) + { + TEST_ERROR("timeout"); + return true; + } + if ((flags & upload_only) && has_metadata(ses)) + { + // the other peer is in upload mode and should not have sent any + // actual payload to us + TEST_CHECK(!is_seed(ses)); + return true; + } - if (m_flags & upload_only) - { - h.set_upload_mode(true); - } - } + if (is_seed(ses)) + { + TEST_CHECK((flags & upload_only) == 0); + return true; + } - virtual void on_exit(std::vector const& torrents) override - { - TEST_EQUAL(m_metadata_alerts, 1); - // in this case we should have completed without downloading anything - // because the downloader had upload only set - if (m_flags & upload_only) return; + return false; + }); - swarm_config::on_exit(torrents); - } - -private: - int m_flags; - boost::shared_ptr (*m_plugin)(torrent_handle const&, void*); - int m_metadata_alerts; -}; + TEST_EQUAL(metadata_alerts, 1); +} TORRENT_TEST(ut_metadata_encryption_reverse) { - test_swarm_config cfg(full_encryption | reverse, &create_ut_metadata_plugin); - setup_swarm(2, cfg); + run_metadata_test(full_encryption | reverse); } TORRENT_TEST(ut_metadata_encryption_utp) { - test_swarm_config cfg(full_encryption | utp, &create_ut_metadata_plugin); - setup_swarm(2, cfg); + run_metadata_test(full_encryption | utp); } TORRENT_TEST(ut_metadata_reverse) { - test_swarm_config cfg(reverse, &create_ut_metadata_plugin); - setup_swarm(2, cfg); + run_metadata_test(reverse); } TORRENT_TEST(ut_metadata_upload_only) { - test_swarm_config cfg(upload_only, &create_ut_metadata_plugin); - setup_swarm(2, cfg); + run_metadata_test(upload_only); } -#ifndef TORRENT_NO_DEPRECATE - -// TODO: add more flags combinations? - -TORRENT_TEST(metadata_encryption_reverse) -{ - test_swarm_config cfg(full_encryption | reverse, &create_metadata_plugin); - setup_swarm(2, cfg); -} - -TORRENT_TEST(metadata_encryption_utp) -{ - test_swarm_config cfg(full_encryption | utp, &create_metadata_plugin); - setup_swarm(2, cfg); -} - -TORRENT_TEST(metadata_reverse) -{ - test_swarm_config cfg(reverse, &create_metadata_plugin); - setup_swarm(2, cfg); -} - -TORRENT_TEST(metadata_upload_only) -{ - test_swarm_config cfg(upload_only, &create_metadata_plugin); - setup_swarm(2, cfg); -} - -#endif - diff --git a/simulation/test_pe_crypto.cpp b/simulation/test_pe_crypto.cpp index 46c97c581..c9e2cf342 100644 --- a/simulation/test_pe_crypto.cpp +++ b/simulation/test_pe_crypto.cpp @@ -33,14 +33,13 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include "libtorrent/hasher.hpp" #include "libtorrent/pe_crypto.hpp" #include "libtorrent/session.hpp" -#include "libtorrent/random.hpp" #include "setup_transfer.hpp" -#include "swarm_config.hpp" #include "test.hpp" +#include "settings.hpp" +#include "setup_swarm.hpp" #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) @@ -49,18 +48,14 @@ namespace lt = libtorrent; char const* pe_policy(boost::uint8_t policy) { - using namespace libtorrent; - if (policy == settings_pack::pe_disabled) return "disabled"; else if (policy == settings_pack::pe_enabled) return "enabled"; else if (policy == settings_pack::pe_forced) return "forced"; return "unknown"; } -void display_settings(libtorrent::settings_pack const& s) +void display_pe_settings(libtorrent::settings_pack const& s) { - using namespace libtorrent; - fprintf(stderr, "out_enc_policy - %s\tin_enc_policy - %s\n" , pe_policy(s.get_int(settings_pack::out_enc_policy)) , pe_policy(s.get_int(settings_pack::in_enc_policy))); @@ -72,108 +67,126 @@ void display_settings(libtorrent::settings_pack const& s) , s.get_bool(settings_pack::prefer_rc4) ? "true": "false"); } -struct test_swarm_config : swarm_config +void test_transfer(int enc_policy, int level, bool prefer_rc4) { - test_swarm_config(libtorrent::settings_pack::enc_policy policy - , libtorrent::settings_pack::enc_level level - , bool prefer_rc4) - : swarm_config() - , m_policy(policy) - , m_level(level) - , m_prefer_rc4(prefer_rc4) - {} + lt::settings_pack default_settings = settings(); + default_settings.set_bool(settings_pack::prefer_rc4, prefer_rc4); + default_settings.set_int(settings_pack::in_enc_policy, enc_policy); + default_settings.set_int(settings_pack::out_enc_policy, enc_policy); + default_settings.set_int(settings_pack::allowed_enc_level, level); + display_pe_settings(default_settings); - // called for every session that's added - virtual libtorrent::settings_pack add_session(int idx) override - { - settings_pack s = swarm_config::add_session(idx); + sim::default_config cfg; + sim::simulation sim{cfg}; - fprintf(stderr, " session %d\n", idx); - - s.set_int(settings_pack::out_enc_policy, settings_pack::pe_enabled); - s.set_int(settings_pack::in_enc_policy, settings_pack::pe_enabled); - s.set_int(settings_pack::allowed_enc_level, settings_pack::pe_both); - - if (idx == 1) - { - s.set_int(settings_pack::out_enc_policy, m_policy); - s.set_int(settings_pack::in_enc_policy, m_policy); - s.set_int(settings_pack::allowed_enc_level, m_level); - s.set_bool(settings_pack::prefer_rc4, m_prefer_rc4); + lt::add_torrent_params default_add_torrent; + default_add_torrent.flags &= ~lt::add_torrent_params::flag_paused; + default_add_torrent.flags &= ~lt::add_torrent_params::flag_auto_managed; + setup_swarm(2, swarm_test::download, sim, default_settings, default_add_torrent + // add session + , [](lt::settings_pack& pack) { + pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_enabled); + pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_enabled); + pack.set_int(settings_pack::allowed_enc_level, settings_pack::pe_both); + pack.set_bool(settings_pack::prefer_rc4, false); } - - display_settings(s); - - return s; - } - -private: - libtorrent::settings_pack::enc_policy m_policy; - libtorrent::settings_pack::enc_level m_level; - bool m_prefer_rc4; -}; + // add torrent + , [](lt::add_torrent_params& params) {} + // on alert + , [](lt::alert const* a, lt::session& ses) {} + // terminate + , [](int ticks, lt::session& ses) -> bool + { + if (ticks > 20) + { + TEST_ERROR("timeout"); + return true; + } + return is_seed(ses); + }); +} TORRENT_TEST(pe_disabled) { - using namespace libtorrent; - test_swarm_config cfg(settings_pack::pe_disabled, settings_pack::pe_both, false); - setup_swarm(2, cfg); + test_transfer(settings_pack::pe_disabled, settings_pack::pe_plaintext, false); } TORRENT_TEST(forced_plaintext) { - using namespace libtorrent; - test_swarm_config cfg(settings_pack::pe_forced, settings_pack::pe_both, false); - setup_swarm(2, cfg); + test_transfer(settings_pack::pe_forced, settings_pack::pe_plaintext, false); } TORRENT_TEST(forced_rc4) { - using namespace libtorrent; - test_swarm_config cfg(settings_pack::pe_forced, settings_pack::pe_rc4, false); - setup_swarm(2, cfg); + test_transfer(settings_pack::pe_forced, settings_pack::pe_rc4, true); } TORRENT_TEST(forced_both) { - using namespace libtorrent; - test_swarm_config cfg(settings_pack::pe_forced, settings_pack::pe_both, false); - setup_swarm(2, cfg); + test_transfer(settings_pack::pe_forced, settings_pack::pe_both, false); } TORRENT_TEST(forced_both_prefer_rc4) { - using namespace libtorrent; - test_swarm_config cfg(settings_pack::pe_forced, settings_pack::pe_both, true); - setup_swarm(2, cfg); + test_transfer(settings_pack::pe_forced, settings_pack::pe_both, true); } TORRENT_TEST(enabled_plaintext) { - using namespace libtorrent; - test_swarm_config cfg(settings_pack::pe_enabled, settings_pack::pe_plaintext, false); - setup_swarm(2, cfg); + test_transfer(settings_pack::pe_forced, settings_pack::pe_plaintext, false); } TORRENT_TEST(enabled_rc4) { - using namespace libtorrent; - test_swarm_config cfg(settings_pack::pe_enabled, settings_pack::pe_rc4, false); - setup_swarm(2, cfg); + test_transfer(settings_pack::pe_enabled, settings_pack::pe_rc4, false); } TORRENT_TEST(enabled_both) { - using namespace libtorrent; - test_swarm_config cfg(settings_pack::pe_enabled, settings_pack::pe_both, false); - setup_swarm(2, cfg); + test_transfer(settings_pack::pe_enabled, settings_pack::pe_both, false); } TORRENT_TEST(enabled_both_prefer_rc4) { - using namespace libtorrent; - test_swarm_config cfg(settings_pack::pe_enabled, settings_pack::pe_both, true); - setup_swarm(2, cfg); + test_transfer(settings_pack::pe_enabled, settings_pack::pe_both, true); +} + +// make sure that a peer with encryption disabled cannot talk to a peer with +// encryption forced +TORRENT_TEST(disabled_failing) +{ + lt::settings_pack default_settings = settings(); + default_settings.set_bool(settings_pack::prefer_rc4, false); + default_settings.set_int(settings_pack::in_enc_policy, settings_pack::pe_disabled); + default_settings.set_int(settings_pack::out_enc_policy, settings_pack::pe_disabled); + default_settings.set_int(settings_pack::allowed_enc_level, settings_pack::pe_both); + display_pe_settings(default_settings); + + sim::default_config cfg; + sim::simulation sim{cfg}; + + lt::add_torrent_params default_add_torrent; + default_add_torrent.flags &= ~lt::add_torrent_params::flag_paused; + default_add_torrent.flags &= ~lt::add_torrent_params::flag_auto_managed; + setup_swarm(2, swarm_test::download, sim, default_settings, default_add_torrent + // add session + , [](lt::settings_pack& pack) { + pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_forced); + pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_forced); + pack.set_int(settings_pack::allowed_enc_level, settings_pack::pe_both); + pack.set_bool(settings_pack::prefer_rc4, true); + } + // add torrent + , [](lt::add_torrent_params& params) {} + // on alert + , [](lt::alert const* a, lt::session& ses) {} + // terminate + , [](int ticks, lt::session& ses) -> bool + { + // this download should never succeed + TEST_CHECK(!is_seed(ses)); + return ticks > 120; + }); } #else TORRENT_TEST(disabled) diff --git a/simulation/test_super_seeding.cpp b/simulation/test_super_seeding.cpp index 262a53367..17334c3f0 100644 --- a/simulation/test_super_seeding.cpp +++ b/simulation/test_super_seeding.cpp @@ -47,9 +47,9 @@ TORRENT_TEST(super_seeding) params.flags |= add_torrent_params::flag_super_seeding; } // on alert - , [](lt::alert const* a, lt::session* ses) {} + , [](lt::alert const* a, lt::session& ses) {} // terminate - , [](int ticks, lt::session* ses) -> bool + , [](int ticks, lt::session& ses) -> bool { return true; }); } @@ -65,9 +65,9 @@ TORRENT_TEST(strict_super_seeding) params.flags |= add_torrent_params::flag_super_seeding; } // on alert - , [](lt::alert const* a, lt::session* ses) {} + , [](lt::alert const* a, lt::session& ses) {} // terminate - , [](int ticks, lt::session* ses) -> bool + , [](int ticks, lt::session& ses) -> bool { return true; }); } diff --git a/simulation/test_swarm.cpp b/simulation/test_swarm.cpp index bb05a93b2..d5fa34c93 100644 --- a/simulation/test_swarm.cpp +++ b/simulation/test_swarm.cpp @@ -49,9 +49,9 @@ TORRENT_TEST(seed_mode) params.flags |= add_torrent_params::flag_seed_mode; } // on alert - , [](lt::alert const* a, lt::session* ses) {} + , [](lt::alert const* a, lt::session& ses) {} // terminate - , [](int ticks, lt::session* ses) -> bool + , [](int ticks, lt::session& ses) -> bool { return true; }); } @@ -63,9 +63,9 @@ TORRENT_TEST(plain) // add torrent , [](lt::add_torrent_params& params) {} // on alert - , [](lt::alert const* a, lt::session* ses) {} + , [](lt::alert const* a, lt::session& ses) {} // terminate - , [](int ticks, lt::session* ses) -> bool + , [](int ticks, lt::session& ses) -> bool { if (ticks > 75) { @@ -88,9 +88,9 @@ TORRENT_TEST(suggest) // add torrent , [](lt::add_torrent_params& params) {} // on alert - , [](lt::alert const* a, lt::session* ses) {} + , [](lt::alert const* a, lt::session& ses) {} // terminate - , [](int ticks, lt::session* ses) -> bool + , [](int ticks, lt::session& ses) -> bool { if (ticks > 75) { @@ -116,9 +116,9 @@ TORRENT_TEST(utp_only) // add torrent , [](lt::add_torrent_params& params) {} // on alert - , [](lt::alert const* a, lt::session* ses) {} + , [](lt::alert const* a, lt::session& ses) {} // terminate - , [](int ticks, lt::session* ses) -> bool + , [](int ticks, lt::session& ses) -> bool { if (ticks > 75) { @@ -137,11 +137,18 @@ void test_stop_start_download(swarm_test type, bool graceful) setup_swarm(3, type // add session - , [](lt::settings_pack& pack) {} + , [](lt::settings_pack& pack) { + // this test will pause and resume the torrent immediately, we expect + // to reconnect immediately too, so disable the min reconnect time + // limit. + pack.set_int(settings_pack::min_reconnect_time, 0); + } // add torrent - , [](lt::add_torrent_params& params) {} + , [](lt::add_torrent_params& params) { + + } // on alert - , [&](lt::alert const* a, lt::session* ses) { + , [&](lt::alert const* a, lt::session& ses) { if (lt::alert_cast(a)) add_extra_peers(ses); @@ -149,12 +156,13 @@ void test_stop_start_download(swarm_test type, bool graceful) if (auto tp = lt::alert_cast(a)) { TEST_EQUAL(resumed, false); + printf("\nSTART\n\n"); tp->handle.resume(); resumed = true; } } // terminate - , [&](int ticks, lt::session* ses) -> bool + , [&](int ticks, lt::session& ses) -> bool { if (paused_once == false) { @@ -165,14 +173,16 @@ void test_stop_start_download(swarm_test type, bool graceful) if (limit_reached) { - auto h = ses->get_torrents()[0]; + printf("\nSTOP\n\n"); + auto h = ses.get_torrents()[0]; h.pause(graceful ? torrent_handle::graceful_pause : 0); paused_once = true; } } - const int timeout = (type == swarm_test::upload) ? 64 : 20; + printf("tick: %d\n", ticks); + const int timeout = type == swarm_test::download ? 20 : 91; if (ticks > timeout) { TEST_ERROR("timeout"); @@ -198,6 +208,51 @@ TORRENT_TEST(stop_start_download_graceful) test_stop_start_download(swarm_test::download, true); } +TORRENT_TEST(stop_start_download_graceful_no_peers) +{ + bool paused_once = false; + bool resumed = false; + + setup_swarm(1, swarm_test::download + // add session + , [](lt::settings_pack& pack) {} + // add torrent + , [](lt::add_torrent_params& params) {} + // on alert + , [&](lt::alert const* a, lt::session& ses) { + if (auto tp = lt::alert_cast(a)) + { + TEST_EQUAL(resumed, false); + printf("\nSTART\n\n"); + tp->handle.resume(); + resumed = true; + } + } + // terminate + , [&](int ticks, lt::session& ses) -> bool + { + if (paused_once == false + && ticks == 6) + { + printf("\nSTOP\n\n"); + auto h = ses.get_torrents()[0]; + h.pause(torrent_handle::graceful_pause); + paused_once = true; + } + + printf("tick: %d\n", ticks); + + // when there's only one node (i.e. no peers) we won't ever download + // the torrent. It's just a test to make sure we still get the + // torrent_paused_alert + return ticks > 60; + }); + + TEST_EQUAL(paused_once, true); + TEST_EQUAL(resumed, true); +} + + TORRENT_TEST(stop_start_seed) { test_stop_start_download(swarm_test::upload, false); @@ -220,9 +275,9 @@ TORRENT_TEST(explicit_cache) // add torrent , [](lt::add_torrent_params& params) {} // on alert - , [](lt::alert const* a, lt::session* ses) {} + , [](lt::alert const* a, lt::session& ses) {} // terminate - , [](int ticks, lt::session* ses) -> bool + , [](int ticks, lt::session& ses) -> bool { if (ticks > 75) { @@ -242,9 +297,9 @@ TORRENT_TEST(shutdown) // add torrent , [](lt::add_torrent_params& params) {} // on alert - , [](lt::alert const* a, lt::session* ses) {} + , [](lt::alert const* a, lt::session& ses) {} // terminate - , [](int ticks, lt::session* ses) -> bool + , [](int ticks, lt::session& ses) -> bool { if (completed_pieces(ses) == 0) return false; TEST_EQUAL(is_seed(ses), false); @@ -256,4 +311,8 @@ TORRENT_TEST(shutdown) // outgoing connections // TODO: add test that makes sure a torrent in graceful pause mode won't accept // incoming connections +// TODO: test allow-fast +// TODO: test the different storage allocation modes +// TODO: test contiguous buffers + diff --git a/simulation/test_torrent_status.cpp b/simulation/test_torrent_status.cpp index 17ebeddd0..2addf6905 100644 --- a/simulation/test_torrent_status.cpp +++ b/simulation/test_torrent_status.cpp @@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "test.hpp" -#include "swarm_config.hpp" +#include "setup_swarm.hpp" #include "simulator/simulator.hpp" #include "libtorrent/alert_types.hpp" @@ -40,73 +40,61 @@ using namespace sim; namespace lt = libtorrent; // this is a test for torrent_status time counters are correct -struct test_swarm_config : swarm_config -{ - test_swarm_config() - : swarm_config() - {} - - bool on_alert(libtorrent::alert const* alert - , int session_idx - , std::vector const& handles - , libtorrent::session& ses) override - { - if (torrent_added_alert const* ta = alert_cast(alert)) - { - TEST_CHECK(!m_handle.is_valid()); - m_start_time = lt::clock_type::now(); - m_handle = ta->handle; - } - return false; - } - - virtual void on_exit(std::vector const& torrents) override {} - - virtual bool tick(int t) override - { - // once an hour, verify that the timers seem correct - if ((t % 3600) == 0) - { - lt::time_point now = lt::clock_type::now(); - int since_start = total_seconds(now - m_start_time) - 1; - torrent_status st = m_handle.status(); - TEST_EQUAL(st.active_time, since_start); - TEST_EQUAL(st.seeding_time, since_start); - TEST_EQUAL(st.finished_time, since_start); - - TEST_EQUAL(st.last_scrape, -1); - TEST_EQUAL(st.time_since_upload, -1); - - // checking the torrent counts as downloading - // eventually though, we've forgotten about it and go back to -1 - if (since_start > 65000) - { - TEST_EQUAL(st.time_since_download, -1); - } - else - { - TEST_EQUAL(st.time_since_download, since_start); - } - } - - // simulate 20 hours of uptime. Currently, the session_time and internal - // peer timestamps are 16 bits counting seconds, so they can only - // represent about 18 hours. The clock steps forward in 4 hour increments - // to stay within that range - return t > 20 * 60 * 60; - } - -private: - lt::time_point m_start_time; - lt::torrent_handle m_handle; -}; - TORRENT_TEST(status_timers) { - sim::default_config network_cfg; - sim::simulation sim{network_cfg}; + lt::time_point start_time; + lt::torrent_handle handle; - test_swarm_config cfg; - setup_swarm(1, sim, cfg); + setup_swarm(1, swarm_test::upload + // add session + , [](lt::settings_pack& pack) {} + // add torrent + , [](lt::add_torrent_params& params) {} + // on alert + , [&](lt::alert const* a, lt::session& ses) { + if (auto ta = alert_cast(a)) + { + TEST_CHECK(!handle.is_valid()); + start_time = lt::clock_type::now(); + handle = ta->handle; + } + } + // terminate + , [&](int ticks, lt::session& ses) -> bool + { + + // simulate 20 hours of uptime. Currently, the session_time and internal + // peer timestamps are 16 bits counting seconds, so they can only + // represent about 18 hours. The clock steps forward in 4 hour increments + // to stay within that range + if (ticks > 20 * 60 * 60) + return true; + + // once an hour, verify that the timers seem correct + if ((ticks % 3600) == 0) + { + lt::time_point now = lt::clock_type::now(); + int since_start = total_seconds(now - start_time) - 1; + torrent_status st = handle.status(); + TEST_EQUAL(st.active_time, since_start); + TEST_EQUAL(st.seeding_time, since_start); + TEST_EQUAL(st.finished_time, since_start); + TEST_EQUAL(st.last_scrape, -1); + TEST_EQUAL(st.time_since_upload, -1); + + // checking the torrent counts as downloading + // eventually though, we've forgotten about it and go back to -1 + if (since_start > 65000) + { + TEST_EQUAL(st.time_since_download, -1); + } + else + { + TEST_EQUAL(st.time_since_download, since_start); + } + } + + return false; + }); } diff --git a/simulation/test_tracker.cpp b/simulation/test_tracker.cpp index 0d31e4bdd..72fa2479d 100644 --- a/simulation/test_tracker.cpp +++ b/simulation/test_tracker.cpp @@ -33,11 +33,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "settings.hpp" #include "setup_swarm.hpp" -#include "swarm_config.hpp" #include "simulator/simulator.hpp" #include "simulator/http_server.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/announce_entry.hpp" +#include "libtorrent/session.hpp" using namespace libtorrent; using namespace sim; @@ -48,82 +48,6 @@ using chrono::duration_cast; // seconds const int duration = 10000; -struct test_swarm_config : swarm_config -{ - test_swarm_config(int num_torrents, std::vector* announces=NULL) - : swarm_config() - , m_announces(announces) - , m_num_torrents(num_torrents) - {} - - void on_session_added(int idx, session& ses) override - { - } - - virtual libtorrent::add_torrent_params add_torrent(int idx) override - { - add_torrent_params p = swarm_config::add_torrent(idx); - - // add the tracker to the last torrent (if there's only one, it will be a - // seed from the start, if there are more than one, it will be a torrent - // that downloads the torrent and turns into a seed) - if (m_num_torrents - 1 == idx) - { - p.trackers.push_back("http://2.2.2.2:8080/announce"); - } - - return p; - } - - bool on_alert(libtorrent::alert const* alert - , int session_idx - , std::vector const& handles - , libtorrent::session& ses) override - { - if (m_announces == NULL) return false; - - char type = 0; - if (lt::alert_cast(alert)) - { - type = 'A'; - } - else if (lt::alert_cast(alert)) - { - type = 'E'; - } - else if (lt::alert_cast(alert)) - { - type = 'W'; - } - else if (lt::alert_cast(alert)) - { - type = 'R'; - } - else - { - return false; - } - - char msg[500]; - snprintf(msg, sizeof(msg), "%c: %d %s", type - , int(duration_cast(alert->timestamp().time_since_epoch()).count()) - , alert->message().c_str()); - m_announces->push_back(msg); - - return false; - } - - virtual void on_exit(std::vector const& torrents) override - { - } - - virtual bool tick(int t) override { return t > duration; } - -private: - std::vector* m_announces; - int m_num_torrents; -}; - void test_interval(int interval) { using sim::asio::ip::address_v4; @@ -152,19 +76,42 @@ void test_interval(int interval) return sim::send_response(200, "OK", size) + response; }); - std::vector announce_alerts; - test_swarm_config cfg(1, &announce_alerts); - setup_swarm(1, sim, cfg); + std::vector announce_alerts; + + lt::settings_pack default_settings = settings(); + lt::add_torrent_params default_add_torrent; + + setup_swarm(1, swarm_test::upload, sim, default_settings, default_add_torrent + // add session + , [](lt::settings_pack& pack) { } + // add torrent + , [](lt::add_torrent_params& params) { + params.trackers.push_back("http://2.2.2.2:8080/announce"); + } + // on alert + , [&](lt::alert const* a, lt::session& ses) { + + if (lt::alert_cast(a)) + { + boost::uint32_t seconds = chrono::duration_cast( + a->timestamp() - start).count(); + + announce_alerts.push_back(seconds); + } + } + // terminate + , [](int ticks, lt::session& ses) -> bool { return ticks > duration; }); + + TEST_EQUAL(announce_alerts.size(), announces.size()); int counter = 0; for (int i = 0; i < int(announces.size()); ++i) { TEST_EQUAL(announces[i], counter); + TEST_EQUAL(announce_alerts[i], counter); counter += interval; if (counter > duration + 1) counter = duration + 1; } - - // TODO: verify that announce_alerts seem right as well } TORRENT_TEST(event_completed) @@ -173,38 +120,64 @@ TORRENT_TEST(event_completed) sim::default_config network_cfg; sim::simulation sim{network_cfg}; - lt::time_point start = lt::clock_type::now(); - sim::asio::io_service web_server(sim, address_v4::from_string("2.2.2.2")); // listen on port 8080 sim::http_server http(web_server, 8080); - // the timestamps (in seconds) of all announces - std::vector announces; + // the request strings of all announces + std::vector> announces; const int interval = 500; + lt::time_point start = lt::clock_type::now(); http.register_handler("/announce" - , [&announces,interval,start](std::string method, std::string req + , [&](std::string method, std::string req , std::map&) { TEST_EQUAL(method, "GET"); - announces.push_back(req); + int timestamp = chrono::duration_cast( + lt::clock_type::now() - start).count(); + announces.push_back({timestamp, req}); char response[500]; int size = snprintf(response, sizeof(response), "d8:intervali%de5:peers0:e", interval); return sim::send_response(200, "OK", size) + response; }); - test_swarm_config cfg(2); - setup_swarm(2, sim, cfg); + lt::settings_pack default_settings = settings(); + lt::add_torrent_params default_add_torrent; + + int completion = -1; + + setup_swarm(2, swarm_test::download, sim, default_settings, default_add_torrent + // add session + , [](lt::settings_pack& pack) { } + // add torrent + , [](lt::add_torrent_params& params) { + params.trackers.push_back("http://2.2.2.2:8080/announce"); + } + // on alert + , [&](lt::alert const* a, lt::session& ses) {} + // terminate + , [&](int ticks, lt::session& ses) -> bool + { + if (completion == -1 && is_seed(ses)) + { + completion = chrono::duration_cast( + lt::clock_type::now() - start).count(); + } + + return ticks > duration; + }); // the first announce should be event=started, the second should be // event=completed, then all but the last should have no event and the last // be event=stopped. for (int i = 0; i < int(announces.size()); ++i) { - std::string const& str = announces[i]; + std::string const& str = announces[i].second; + int timestamp = announces[i].first; + const bool has_start = str.find("&event=started") != std::string::npos; const bool has_completed = str.find("&event=completed") @@ -217,6 +190,7 @@ TORRENT_TEST(event_completed) fprintf(stderr, "- %s\n", str.c_str()); + // there is exactly 0 or 1 events. TEST_EQUAL(int(has_start) + int(has_completed) + int(has_stopped) , int(has_event)); @@ -226,8 +200,13 @@ TORRENT_TEST(event_completed) TEST_CHECK(has_start); break; case 1: + { + // the announce should have come approximately the same time we + // completed + TEST_CHECK(abs(completion - timestamp) <= 1); TEST_CHECK(has_completed); break; + } default: if (i == int(announces.size()) - 1) { diff --git a/simulation/test_trackers_extension.cpp b/simulation/test_trackers_extension.cpp index 25c5be374..10cf1eac1 100644 --- a/simulation/test_trackers_extension.cpp +++ b/simulation/test_trackers_extension.cpp @@ -31,98 +31,126 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "setup_swarm.hpp" -#include "swarm_config.hpp" #include "libtorrent/alert.hpp" #include "libtorrent/announce_entry.hpp" +#include "libtorrent/settings_pack.hpp" +#include "libtorrent/add_torrent_params.hpp" +#include "libtorrent/alert_types.hpp" #include "libtorrent/extensions/lt_trackers.hpp" +#include "libtorrent/session.hpp" #include "test.hpp" +#include "settings.hpp" -enum flags -{ - no_metadata = 1 -}; - -struct test_swarm_config : swarm_config -{ - test_swarm_config(int flags) - : swarm_config() - , m_flags(flags) - {} - - void on_session_added(int idx, session& ses) override - { - ses.add_extension(create_lt_trackers_plugin); - } - - virtual libtorrent::add_torrent_params add_torrent(int idx) override - { - add_torrent_params p = swarm_config::add_torrent(idx); - - if (m_flags & no_metadata) - { - p.info_hash = sha1_hash("aaaaaaaaaaaaaaaaaaaa"); - p.ti.reset(); - } - - // make sure neither peer has any content - // TODO: it would be more efficient to not create the content in the first - // place - p.save_path = save_path(1); - - if (idx == 1) - { - p.trackers.push_back("http://test.non-existent.com/announce"); - } - - return p; - } - - bool on_alert(libtorrent::alert const* alert - , int session_idx - , std::vector const& handles - , libtorrent::session& ses) override - { - - if ((m_flags & no_metadata) == 0) - { - if (handles[0].trackers().size() == 1 - && handles[1].trackers().size() == 1) - return true; - } - return false; - } - - virtual void on_exit(std::vector const& torrents) override - { - TEST_CHECK(torrents.size() > 0); - - // a peer that does not have metadata should not exchange trackers, since - // it may be a private torrent - if (m_flags & no_metadata) - { - TEST_EQUAL(torrents[0].trackers().size(), 0); - TEST_EQUAL(torrents[1].trackers().size(), 1); - } - else - { - TEST_EQUAL(torrents[0].trackers().size(), 1); - TEST_EQUAL(torrents[1].trackers().size(), 1); - } - } - -private: - int m_flags; -}; +using namespace libtorrent; TORRENT_TEST(plain) { - test_swarm_config cfg(0); - setup_swarm(2, cfg); + dsl_config network_cfg; + sim::simulation sim{network_cfg}; + + settings_pack pack = settings(); + + add_torrent_params p; + p.flags &= ~lt::add_torrent_params::flag_paused; + p.flags &= ~lt::add_torrent_params::flag_auto_managed; + + // the default torrent has one tracker + // we remove this from session 0 (the one under test) + p.trackers.push_back("http://test.non-existent.com/announce"); + + bool connected = false; + + setup_swarm(2, swarm_test::upload + , sim , pack, p + // init session + , [](lt::session& ses) { + ses.add_extension(&create_lt_trackers_plugin); + } + // add session + , [](lt::settings_pack& pack) {} + // add torrent + , [](lt::add_torrent_params& params) { + + // make sure neither peer has any content + // TODO: it would be more efficient to not create the content in the first + // place + params.save_path = save_path(test_counter(), 1); + + // the test is whether this peer will receive the tracker or not + params.trackers.clear(); + } + // on alert + , [&](lt::alert const* a, lt::session& ses) { + if (alert_cast(a)) + connected = true; + } + // terminate + , [&](int ticks, lt::session& ses) -> bool { + if (ticks > 10) + { + TEST_ERROR("timeout"); + return true; + } + return connected && ses.get_torrents()[0].trackers().size() > 0; + }); + + TEST_EQUAL(connected, true); } TORRENT_TEST(no_metadata) { - test_swarm_config cfg(no_metadata); - setup_swarm(2, cfg); + dsl_config network_cfg; + sim::simulation sim{network_cfg}; + + settings_pack pack = settings(); + + add_torrent_params p; + p.flags &= ~lt::add_torrent_params::flag_paused; + p.flags &= ~lt::add_torrent_params::flag_auto_managed; + + // the default torrent has one tracker + // we remove this from session 0 (the one under test) + p.trackers.push_back("http://test.non-existent.com/announce"); + + bool connected = false; + + setup_swarm(2, swarm_test::upload + , sim , pack, p + // init session + , [](lt::session& ses) { + ses.add_extension(&create_lt_trackers_plugin); + } + // add session + , [](lt::settings_pack& pack) {} + // add torrent + , [](lt::add_torrent_params& params) { + + // make sure neither peer has any content + // TODO: it would be more efficient to not create the content in the first + // place + params.save_path = save_path(test_counter(), 1); + + // the test is whether this peer will receive the tracker or not + params.trackers.clear(); + + // if we don't have metadata, the other peer should not send the + // tracker to us + params.info_hash = sha1_hash("aaaaaaaaaaaaaaaaaaaa"); + params.ti.reset(); + } + // on alert + , [&](lt::alert const* a, lt::session& ses) { + if (alert_cast(a)) + connected = true; + } + // terminate + , [](int ticks, lt::session& ses) -> bool { + if (ticks < 10) + return false; + TEST_EQUAL(ses.get_torrents()[0].trackers().size(), 0); + return true; + }); + + TEST_EQUAL(connected, true); } diff --git a/simulation/test_transfer.cpp b/simulation/test_transfer.cpp index be978e538..e3d519aee 100644 --- a/simulation/test_transfer.cpp +++ b/simulation/test_transfer.cpp @@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/settings_pack.hpp" #include "simulator/simulator.hpp" #include "simulator/socks_server.hpp" +#include "setup_swarm.hpp" using namespace sim; @@ -53,11 +54,6 @@ enum flags_t ipv6 = 1, }; -asio::ip::address addr(char const* str) -{ - return asio::ip::address::from_string(str); -} - template void run_test( Setup const& setup @@ -173,14 +169,11 @@ void run_test( sim.run(); } -void enable_utp(lt::session& ses) +void utp_only(lt::session& ses) { using namespace libtorrent; settings_pack p; - p.set_bool(settings_pack::enable_outgoing_tcp, false); - p.set_bool(settings_pack::enable_incoming_tcp, false); - p.set_bool(settings_pack::enable_outgoing_utp, true); - p.set_bool(settings_pack::enable_incoming_utp, true); + utp_only(p); ses.apply_settings(p); } @@ -188,10 +181,7 @@ void enable_enc(lt::session& ses) { using namespace libtorrent; settings_pack p; - p.set_bool(settings_pack::prefer_rc4, true); - p.set_int(settings_pack::in_enc_policy, settings_pack::pe_forced); - p.set_int(settings_pack::out_enc_policy, settings_pack::pe_forced); - p.set_int(settings_pack::allowed_enc_level, settings_pack::pe_both); + enable_enc(p); ses.apply_settings(p); } @@ -225,12 +215,6 @@ void set_proxy(lt::session& ses, int proxy_type, int flags = 0, bool proxy_peer_ ses.apply_settings(p); } -bool is_seed(lt::session& ses) -{ - lt::torrent_handle h = ses.get_torrents()[0]; - return h.status().is_seeding; -} - TORRENT_TEST(socks4_tcp) { using namespace libtorrent; @@ -346,10 +330,6 @@ TORRENT_TEST(no_proxy_utp) ); } -// TODO: test allow-fast -// TODO: test the different storage allocation modes -// TODO: test contiguous buffers - // TODO: the socks server does not support UDP yet /* @@ -358,7 +338,7 @@ TORRENT_TEST(encryption_utp) using namespace libtorrent; run_test( [](lt::session& ses0, lt::session& ses1) - { enable_enc(ses0); enable_enc(ses1); enable_utp(ses0); }, + { enable_enc(ses0); enable_enc(ses1); utp_only(ses0); }, [](lt::session& ses, lt::alert const* alert) {}, [](std::shared_ptr ses[2]) { TEST_EQUAL(is_seed(*ses[0]), true); @@ -373,7 +353,7 @@ TORRENT_TEST(socks5_utp) [](lt::session& ses0, lt::session& ses1) { set_proxy(ses0, settings_pack::socks5); - enable_utp(ses0); + utp_only(ses0); filter_ips(ses1); }, [](lt::session& ses, lt::alert const* alert) {}, diff --git a/simulation/test_utp.cpp b/simulation/test_utp.cpp index f2da7e950..e56da0131 100644 --- a/simulation/test_utp.cpp +++ b/simulation/test_utp.cpp @@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "setup_swarm.hpp" -#include "setup_transfer.hpp" // for create_torrent (factor this out!) #include "settings.hpp" #include #include @@ -46,144 +45,45 @@ POSSIBILITY OF SUCH DAMAGE. using namespace libtorrent; namespace lt = libtorrent; -// TODO: a lot of this class is boiler plate. Factor out into a reusable unit -struct swarm_config : swarm_setup_provider -{ - swarm_config(int num_peers) - : m_swarm_id(std::rand()) - , m_start_time(lt::clock_type::now()) - { - // in case the previous run did not exit gracefully - clear_download_directories(num_peers); - - error_code ec; - char save_path[200]; - snprintf(save_path, sizeof(save_path), "swarm-%04d-peer-%02d" - , m_swarm_id, 0); - - create_directory(save_path, ec); - std::ofstream file(combine_path(save_path, "temporary").c_str()); - m_ti = ::create_torrent(&file, "temporary", 0x4000, 90, false); - file.close(); - } - - virtual void on_exit(std::vector const& torrents) - { - TEST_CHECK(torrents.size() > 0); - for (int i = 0; i < int(torrents.size()); ++i) - { - torrent_status st = torrents[i].status(); - TEST_CHECK(st.is_seeding); - TEST_CHECK(st.total_upload > 0 || st.total_download > 0); - } - - // if this check fails, there is a performance regression in the protocol, - // either uTP or bittorrent itself. Be careful with the download request - // queue size (and make sure it can grow fast enough, to keep up with - // slow-start) and the send buffer watermark - TEST_CHECK(lt::clock_type::now() < m_start_time + lt::milliseconds(8500)); - - // clean up the download directories to make the next run start from - // scratch. - clear_download_directories(int(torrents.size())); - } - - void clear_download_directories(int num_peers) - { - for (int i = 0; i < num_peers; ++i) - { - error_code ec; - char save_path[200]; - snprintf(save_path, sizeof(save_path), "swarm-%04d-peer-%02d" - , m_swarm_id, i); - - // in case the previous run did not exit gracefully - remove_all(save_path, ec); - } - } - - // called for every alert. if the simulation is done, return true - virtual bool on_alert(libtorrent::alert const* alert - , int session_idx - , std::vector const& torrents - , libtorrent::session& ses) override - { - if (torrents.empty()) return false; - - bool all_are_seeding = true; - for (int i = 0; i < int(torrents.size()); ++i) - { - if (torrents[i].status().is_seeding) - continue; - - all_are_seeding = false; - break; - } - - // if all torrents are seeds, terminate the simulation, we're done - return all_are_seeding; - } - - // called for every torrent that's added (and every session that's started). - // this is useful to give every session a unique save path and to make some - // sessions seeds and others downloaders - virtual libtorrent::add_torrent_params add_torrent(int idx) override - { - add_torrent_params p; - p.flags &= ~add_torrent_params::flag_paused; - p.flags &= ~add_torrent_params::flag_auto_managed; - - if (idx == 0) - { - // skip checking up front, and get started with the transfer sooner - p.flags |= add_torrent_params::flag_seed_mode; - } - - p.ti = m_ti; - - char save_path[200]; - snprintf(save_path, sizeof(save_path), "swarm-%04d-peer-%02d" - , m_swarm_id, idx); - p.save_path = save_path; - return p; - } - - // called for every session that's added - virtual libtorrent::settings_pack add_session(int idx) override - { - settings_pack pack = settings(); - - // force uTP connection - pack.set_bool(settings_pack::enable_incoming_utp, true); - pack.set_bool(settings_pack::enable_outgoing_utp, true); - pack.set_bool(settings_pack::enable_incoming_tcp, false); - pack.set_bool(settings_pack::enable_outgoing_tcp, false); - - // the encryption handshake adds several round-trips to the bittorrent - // handshake, and slows it down significantly - pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_disabled); - pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_disabled); - - // make sure the sessions have different peer ids - lt::peer_id pid; - std::generate(&pid[0], &pid[0] + 20, &random_byte); - pack.set_str(lt::settings_pack::peer_fingerprint, pid.to_string()); - - return pack; - } - -private: - int m_swarm_id; - lt::time_point m_start_time; - boost::shared_ptr m_ti; -}; - TORRENT_TEST(utp) { // TODO: 3 simulate packet loss // TODO: 3 simulate unpredictible latencies // TODO: 3 simulate proper (taildrop) queues (perhaps even RED and BLUE) - swarm_config cfg(2); - setup_swarm(2, cfg); + lt::time_point start_time = lt::clock_type::now(); + + sim::default_config cfg; + sim::simulation sim{cfg}; + + setup_swarm(2, swarm_test::upload, sim + // add session + , [](lt::settings_pack& pack) { + // force uTP connection + utp_only(pack); + } + // add torrent + , [](lt::add_torrent_params& params) { + params.flags |= add_torrent_params::flag_seed_mode; + } + // on alert + , [&](lt::alert const* a, lt::session& ses) { + if (!is_seed(ses)) return; + + // if this check fails, there is a performance regression in the protocol, + // either uTP or bittorrent itself. Be careful with the download request + // queue size (and make sure it can grow fast enough, to keep up with + // slow-start) and the send buffer watermark + TEST_CHECK(lt::clock_type::now() < start_time + lt::milliseconds(8500)); + } + // terminate + , [](int ticks, lt::session& ses) -> bool + { + if (ticks > 100) + { + TEST_ERROR("timeout"); + return true; + } + return false; + }); } diff --git a/src/lt_trackers.cpp b/src/lt_trackers.cpp index 3c0651b41..06f8cf564 100644 --- a/src/lt_trackers.cpp +++ b/src/lt_trackers.cpp @@ -259,15 +259,14 @@ namespace libtorrent { namespace if (m_tp.num_tex_trackers() >= 50) break; +#ifndef TORRENT_DISABLE_LOGGING + m_pc.peer_log(peer_log_alert::info, "LT_TEX", "adding: %s", e.url.c_str()); +#endif e.fail_limit = 1; e.send_stats = false; e.source = announce_entry::source_tex; if (m_torrent.add_tracker(e)) m_tp.increment_tracker_counter(); - -#ifndef TORRENT_DISABLE_LOGGING - m_pc.peer_log(peer_log_alert::info, "LT_TEX", "added: %s", e.url.c_str()); -#endif } return true; } diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 6536fc1ec..233a1712a 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -4092,7 +4092,10 @@ namespace libtorrent // we cannot do this in a constructor TORRENT_ASSERT(m_in_constructor == false); - if (error > 0) m_failed = true; + if (error > 0) + { + m_failed = true; + } if (m_connected) m_counters.inc_stats_counter(counters::num_peers_connected, -1); @@ -4144,7 +4147,7 @@ namespace libtorrent if (ec == error_code(errors::timed_out) || ec == error::timed_out) m_counters.inc_stats_counter(counters::transport_timeout_peers); - + if (ec == error_code(errors::timed_out_inactivity) || ec == error_code(errors::timed_out_no_request) || ec == error_code(errors::timed_out_no_interest)) diff --git a/src/torrent.cpp b/src/torrent.cpp index 3fac8f919..44d2e9184 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -9610,20 +9610,13 @@ namespace libtorrent TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; - if (!m_allow_peers) return; - set_allow_peers(graceful ? true : false, graceful); + if (m_allow_peers) + { + // we need to save this new state + set_need_save_resume(); + } - m_announce_to_dht = false; - m_announce_to_trackers = false; - m_announce_to_lsd = false; - - // we need to save this new state - set_need_save_resume(); - state_updated(); - - update_gauge(); - update_want_peers(); - update_want_scrape(); + set_allow_peers(false, graceful); } void torrent::do_pause() @@ -9699,20 +9692,14 @@ namespace libtorrent // disconnect all peers with no outstanding data to receive // and choke all remaining peers to prevent responding to new // requests - bool update_ticks = false; + std::vector to_disconnect; for (peer_iterator i = m_connections.begin(); - i != m_connections.end();) + i != m_connections.end(); ++i) { - peer_iterator j = i++; - boost::shared_ptr p = (*j)->self(); + peer_connection* p = *i; TORRENT_ASSERT(p->associated_torrent().lock().get() == this); - if (p->is_disconnecting()) - { - i = m_connections.erase(j); - update_ticks = true; - continue; - } + if (p->is_disconnecting()) continue; if (p->outstanding_bytes() > 0) { @@ -9726,21 +9713,19 @@ namespace libtorrent continue; } + to_disconnect.push_back(p); + } + for (peer_iterator i = to_disconnect.begin(); i != to_disconnect.end(); ++i) + { + peer_connection* p = *i; + + // since we're currently in graceful pause mode, the last peer to + // disconnect (assuming all peers end up begin disconnected here) + // will post the torrent_paused_alert #ifndef TORRENT_DISABLE_LOGGING p->peer_log(peer_log_alert::info, "CLOSING_CONNECTION", "torrent_paused"); #endif p->disconnect(errors::torrent_paused, op_bittorrent); - i = j; - } - if (m_connections.empty()) - { - if (alerts().should_post()) - alerts().emplace_alert(get_handle()); - } - if (update_ticks) - { - update_want_peers(); - update_want_tick(); } } @@ -9792,12 +9777,20 @@ namespace libtorrent { TORRENT_ASSERT(is_single_thread()); + // if there are no peers, there is no point in a graceful pause mode. In + // fact, the promise to post the torrent_paused_alert exactly once is + // maintained by the last peer to be disconnected in graceful pause mode, + // if there are no peers, we must not enter graceful pause mode, and post + // the torrent_paused_alert immediately instead. + if (m_connections.empty()) + graceful = false; + if (m_allow_peers == b) { // there is one special case here. If we are // currently in graceful pause mode, and we just turned into regular // paused mode, we need to actually pause the torrent properly - if (m_allow_peers == true + if (m_allow_peers == false && m_graceful_pause_mode == true && graceful == false) { @@ -9812,21 +9805,28 @@ namespace libtorrent if (!m_ses.is_paused()) m_graceful_pause_mode = graceful; - update_gauge(); - update_want_scrape(); - update_state_list(); - if (!b) { m_announce_to_dht = false; m_announce_to_trackers = false; m_announce_to_lsd = false; + } + + update_gauge(); + update_want_scrape(); + update_want_peers(); + update_state_list(); + state_updated(); + + if (!b) + { do_pause(); } else { do_resume(); } + } void torrent::resume() diff --git a/test/settings.cpp b/test/settings.cpp index 171c29603..9ea20f42e 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -50,6 +50,11 @@ libtorrent::settings_pack settings() pack.set_bool(settings_pack::enable_upnp, false); pack.set_bool(settings_pack::enable_dht, false); + pack.set_bool(settings_pack::prefer_rc4, false); + pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_disabled); + pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_disabled); + pack.set_int(settings_pack::allowed_enc_level, settings_pack::pe_both); + pack.set_int(settings_pack::alert_mask, mask); #ifndef TORRENT_BUILD_SIMULATOR