diff --git a/simulation/Jamfile b/simulation/Jamfile index b8b1ae37b..f3673c743 100644 --- a/simulation/Jamfile +++ b/simulation/Jamfile @@ -15,6 +15,7 @@ project swarm_suite.cpp setup_swarm.cpp setup_dht.cpp + create_torrent.cpp : default-build multi full @@ -34,5 +35,6 @@ alias libtorrent-sims : [ run test_metadata_extension.cpp ] [ run test_trackers_extension.cpp ] [ run test_tracker.cpp ] + [ run test_ip_filter.cpp ] ; diff --git a/simulation/create_torrent.cpp b/simulation/create_torrent.cpp new file mode 100644 index 000000000..8b504e1a9 --- /dev/null +++ b/simulation/create_torrent.cpp @@ -0,0 +1,65 @@ +/* + +Copyright (c) 2015, Arvid Norberg +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 "test.hpp" +#include "setup_transfer.hpp" // for ::create_torrent +#include "libtorrent/add_torrent_params.hpp" +#include + +namespace lt = libtorrent; + +lt::add_torrent_params create_torrent(int idx, bool seed) +{ + // TODO: if we want non-seeding torrents, that could be a bit cheaper to + // create + lt::add_torrent_params params; + int swarm_id = test_counter(); + char name[200]; + snprintf(name, sizeof(name), "temp-%02d", idx); + char path[200]; + snprintf(path, sizeof(path), "swarm-%04d-peer-%02d" + , swarm_id, idx); + lt::error_code ec; + lt::create_directory(path, ec); + if (ec) fprintf(stderr, "failed to create directory: \"%s\": %s\n" + , path, ec.message().c_str()); + std::ofstream file(lt::combine_path(path, name).c_str()); + params.ti = ::create_torrent(&file, name + , 0x4000, 9 + idx, false); + file.close(); + + // by setting the save path to a dummy path, it won't be seeding + params.save_path = seed ? path : "dummy"; + return params; +} + + diff --git a/simulation/create_torrent.hpp b/simulation/create_torrent.hpp new file mode 100644 index 000000000..a72c2cee9 --- /dev/null +++ b/simulation/create_torrent.hpp @@ -0,0 +1,41 @@ +/* + +Copyright (c) 2015, Arvid Norberg +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 TORRENT_CREATE_TORRENT_HPP_INCLUDED +#define TORRENT_CREATE_TORRENT_HPP_INCLUDED + +#include "libtorrent/add_torrent_params.hpp" + +libtorrent::add_torrent_params create_torrent(int idx, bool seed); + +#endif + diff --git a/simulation/test_auto_manage.cpp b/simulation/test_auto_manage.cpp index 8b4465bab..38c0262ee 100644 --- a/simulation/test_auto_manage.cpp +++ b/simulation/test_auto_manage.cpp @@ -35,9 +35,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/settings_pack.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/deadline_timer.hpp" -#include "test.hpp" #include "swarm_config.hpp" #include "settings.hpp" +#include "create_torrent.hpp" #include "simulator/simulator.hpp" #include @@ -45,31 +45,6 @@ using namespace sim; const int num_torrents = 10; -lt::add_torrent_params create_torrent(int idx, bool seed) -{ - // TODO: if we want non-seeding torrents, that could be a bit cheaper to - // create - lt::add_torrent_params params; - int swarm_id = test_counter(); - char name[200]; - snprintf(name, sizeof(name), "temp-%02d", idx); - char path[200]; - snprintf(path, sizeof(path), "swarm-%04d-peer-%02d" - , swarm_id, idx); - error_code ec; - create_directory(path, ec); - if (ec) fprintf(stderr, "failed to create directory: \"%s\": %s\n" - , path, ec.message().c_str()); - std::ofstream file(combine_path(path, name).c_str()); - params.ti = ::create_torrent(&file, name - , 0x4000, 9 + idx, false); - file.close(); - - // by setting the save path to a dummy path, it won't be seeding - params.save_path = seed ? path : "dummy"; - return params; -} - using sim::asio::ip::address_v4; std::unique_ptr make_io_service(sim::simulation& sim, int i) diff --git a/simulation/test_ip_filter.cpp b/simulation/test_ip_filter.cpp new file mode 100644 index 000000000..55dabce14 --- /dev/null +++ b/simulation/test_ip_filter.cpp @@ -0,0 +1,291 @@ +/* + +Copyright (c) 2015, Arvid Norberg +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 +#include "test.hpp" +#include "create_torrent.hpp" +#include "settings.hpp" +#include "libtorrent/session.hpp" +#include "libtorrent/deadline_timer.hpp" +#include "libtorrent/settings_pack.hpp" +#include "libtorrent/ip_filter.hpp" +#include "libtorrent/alert_types.hpp" +#include "simulator/simulator.hpp" + +using namespace sim; + +namespace lt = libtorrent; + +struct fake_peer +{ + fake_peer(simulation& sim, char const* ip) + : m_ios(sim, asio::ip::address::from_string(ip)) + , m_acceptor(m_ios) + , m_socket(m_ios) + , m_tripped(false) + { + boost::system::error_code ec; + m_acceptor.open(asio::ip::tcp::v4(), ec); + TEST_CHECK(!ec); + m_acceptor.bind(asio::ip::tcp::endpoint(asio::ip::address_v4::any(), 6881), ec); + TEST_CHECK(!ec); + m_acceptor.listen(10, ec); + TEST_CHECK(!ec); + + m_acceptor.async_accept(m_socket, [&] (boost::system::error_code const& ec) + { if (!ec) m_tripped = true; }); + } + + void close() + { + m_acceptor.close(); + m_socket.close(); + } + + bool tripped() const { return m_tripped; } + +private: + asio::io_service m_ios; + asio::ip::tcp::acceptor m_acceptor; + asio::ip::tcp::socket m_socket; + bool m_tripped; +}; + +template +void run_test(Setup const& setup + , HandleAlerts const& on_alert + , Test const& test) +{ + // setup the simulation + sim::default_config network_cfg; + sim::simulation sim{network_cfg}; + sim::asio::io_service ios(sim, asio::ip::address_v4::from_string("50.0.0.1")); + lt::session_proxy zombie; + + // setup settings pack to use for the session (customization point) + lt::settings_pack pack = settings(); + // create session + std::shared_ptr ses = std::make_shared(pack, ios); + + fake_peer p1(sim, "60.0.0.0"); + fake_peer p2(sim, "60.0.0.1"); + fake_peer p3(sim, "60.0.0.2"); + fake_peer p4(sim, "60.0.0.3"); + fake_peer p5(sim, "60.0.0.4"); + std::array test_peers = {{ &p1, &p2, &p3, &p4, &p5 }}; + + // set up test, like adding torrents (customization point) + setup(*ses); + + // the alert notification function is called from within libtorrent's + // context. It's not OK to talk to libtorrent in there, post it back out and + // then ask for alerts. + ses->set_alert_notify([&] { ios.post([&] { + std::vector alerts; + ses->pop_alerts(&alerts); + // call the user handler + if (!alerts.empty()) on_alert(*ses, alerts); + } ); } ); + + lt::deadline_timer timer(ios); + timer.expires_from_now(lt::seconds(60)); + timer.async_wait([&](lt::error_code const& ec) + { + test(*ses, test_peers); + + ses->set_alert_notify([]{}); + // shut down + zombie = ses->abort(); + + for (auto* p : test_peers) p->close(); + + ses.reset(); + }); + + sim.run(); +} + +void add_fake_peers(lt::torrent_handle h) +{ + // add the fake peers + for (int i = 0; i < 5; ++i) + { + char ep[30]; + snprintf(ep, sizeof(ep), "60.0.0.%d", i); + h.connect_peer(lt::tcp::endpoint( + lt::address_v4::from_string(ep), 6881)); + } +} + +void check_tripped(std::array& test_peers, std::array expected) +{ + int idx = 0; + for (auto p : test_peers) + { + TEST_EQUAL(p->tripped(), expected[idx]); + ++idx; + } +} + +void add_ip_filter(lt::session& ses) +{ + lt::ip_filter filter; + // filter out 0-2 inclusive + filter.add_rule( + asio::ip::address_v4::from_string("60.0.0.0") + , asio::ip::address_v4::from_string("60.0.0.2") + , lt::ip_filter::blocked); + ses.set_ip_filter(filter); +} + +// set an IP filter, add a torrent, add peers, make sure the correct ones are +// connected to +TORRENT_TEST(apply_ip_filter) +{ + lt::time_point start_time = lt::clock_type::now(); + + run_test( + [](lt::session& ses) + { + add_ip_filter(ses); + + lt::add_torrent_params params = create_torrent(0, false); + params.flags &= ~lt::add_torrent_params::flag_auto_managed; + params.flags &= ~lt::add_torrent_params::flag_paused; + ses.async_add_torrent(params); + }, + + [&](lt::session& ses, std::vector const& alerts) + { + for (lt::alert const* a : alerts) + { + printf("%-3d %s\n", int(lt::duration_cast(a->timestamp() + - start_time).count()), a->message().c_str()); + + if (lt::add_torrent_alert const* at = lt::alert_cast(a)) + { + lt::torrent_handle h = at->handle; + add_fake_peers(h); + } + } + }, + + [](lt::session& ses, std::array& test_peers) + { + check_tripped(test_peers, {{false, false, false, true, true}} ); + } + ); +} + +// add a torrent, set an IP filter, add peers, make sure the correct ones are +// connected to +TORRENT_TEST(update_ip_filter) +{ + lt::time_point start_time = lt::clock_type::now(); + + run_test( + [](lt::session& ses) + { + lt::add_torrent_params params = create_torrent(0, false); + params.flags &= ~lt::add_torrent_params::flag_auto_managed; + params.flags &= ~lt::add_torrent_params::flag_paused; + ses.async_add_torrent(params); + }, + + [&](lt::session& ses, std::vector const& alerts) + { + for (lt::alert const* a : alerts) + { + printf("%-3d %s\n", int(lt::duration_cast(a->timestamp() + - start_time).count()), a->message().c_str()); + + if (lt::add_torrent_alert const* at = lt::alert_cast(a)) + { + // here we add the IP filter after the torrent has already been + // added + add_ip_filter(ses); + + lt::torrent_handle h = at->handle; + add_fake_peers(h); + } + } + }, + + [](lt::session& ses, std::array& test_peers) + { + check_tripped(test_peers, {{false, false, false, true, true}} ); + } + ); +} + +TORRENT_TEST(apply_ip_filter_to_torrent) +{ + lt::time_point start_time = lt::clock_type::now(); + + run_test( + [](lt::session& ses) + { + add_ip_filter(ses); + + lt::add_torrent_params params = create_torrent(0, false); + params.flags &= ~lt::add_torrent_params::flag_auto_managed; + params.flags &= ~lt::add_torrent_params::flag_paused; + + // disable the IP filter! + params.flags &= ~lt::add_torrent_params::flag_apply_ip_filter; + ses.async_add_torrent(params); + }, + + [&](lt::session& ses, std::vector const& alerts) + { + for (lt::alert const* a : alerts) + { + printf("%-3d %s\n", int(lt::duration_cast(a->timestamp() + - start_time).count()), a->message().c_str()); + + if (lt::add_torrent_alert const* at = lt::alert_cast(a)) + { + lt::torrent_handle h = at->handle; + add_fake_peers(h); + } + } + }, + + [](lt::session& ses, std::array& test_peers) + { + // since the IP filter didn't apply to this torrent, it should have hit + // all peers + check_tripped(test_peers, {{true, true, true, true, true}} ); + } + ); +} +