Add dual stack DHT node simulation tests
This commit is contained in:
parent
2abd9867ce
commit
43be11177b
|
@ -64,6 +64,13 @@ namespace {
|
|||
return asio::ip::address_v4(lt::random());
|
||||
}
|
||||
|
||||
asio::ip::address addr6_from_int(int idx)
|
||||
{
|
||||
asio::ip::address_v6::bytes_type bytes;
|
||||
for (uint8_t& b : bytes) b = uint8_t(lt::random());
|
||||
return asio::ip::address_v6(bytes);
|
||||
}
|
||||
|
||||
// this is the node ID assigned to node 'idx'
|
||||
dht::node_id id_from_addr(lt::address const& addr)
|
||||
{
|
||||
|
@ -74,28 +81,27 @@ namespace {
|
|||
|
||||
struct dht_node final : lt::dht::udp_socket_interface
|
||||
{
|
||||
enum flags_t
|
||||
{
|
||||
add_dead_nodes = 1
|
||||
};
|
||||
|
||||
dht_node(sim::simulation& sim, lt::dht_settings const& sett, lt::counters& cnt
|
||||
, int idx, std::uint32_t flags)
|
||||
: m_io_service(sim, addr_from_int(idx))
|
||||
: m_io_service(sim, (flags & dht_network::bind_ipv6) ? addr6_from_int(idx) : addr_from_int(idx))
|
||||
#if LIBSIMULATOR_USE_MOVE
|
||||
, m_socket(m_io_service)
|
||||
, m_dht(ipv4, this, sett, id_from_addr(m_io_service.get_ips().front())
|
||||
, m_dht((flags & dht_network::bind_ipv6) ? ipv6 : ipv4
|
||||
, this, sett, id_from_addr(m_io_service.get_ips().front())
|
||||
, nullptr, cnt, std::map<std::string, lt::dht::node*>())
|
||||
#else
|
||||
, m_socket(new asio::ip::udp::socket(m_io_service))
|
||||
, m_dht(new lt::dht::node(ipv4, this, sett, id_from_addr(m_io_service.get_ips().front())
|
||||
, m_dht(new lt::dht::node((flags & dht_network::bind_ipv6) ? ipv6 : ipv4
|
||||
, this, sett, id_from_addr(m_io_service.get_ips().front())
|
||||
, nullptr, cnt, std::map<std::string, lt::dht::node*>()))
|
||||
#endif
|
||||
, m_add_dead_nodes(flags & add_dead_nodes)
|
||||
, m_add_dead_nodes(flags & dht_network::add_dead_nodes)
|
||||
, m_ipv6(flags & dht_network::bind_ipv6)
|
||||
{
|
||||
error_code ec;
|
||||
sock().open(asio::ip::udp::v4());
|
||||
sock().bind(asio::ip::udp::endpoint(lt::address_v4::any(), 6881));
|
||||
sock().open(m_ipv6 ? asio::ip::udp::v6() : asio::ip::udp::v4());
|
||||
sock().bind(asio::ip::udp::endpoint(
|
||||
m_ipv6 ? lt::address(lt::address_v6::any()) : lt::address(lt::address_v4::any()), 6881));
|
||||
|
||||
udp::socket::non_blocking_io ioc(true);
|
||||
sock().io_control(ioc);
|
||||
|
@ -116,7 +122,7 @@ struct dht_node final : lt::dht::udp_socket_interface
|
|||
// reserving space in the vector before emplacing any nodes).
|
||||
dht_node(dht_node&& n) noexcept
|
||||
: m_socket(std::move(n.m_socket))
|
||||
, m_dht(ipv4, this, n.m_dht.settings(), n.m_dht.nid()
|
||||
, m_dht(n.m_ipv6 ? ipv6 : ipv4, this, n.m_dht.settings(), n.m_dht.nid()
|
||||
, n.m_dht.observer(), n.m_dht.stats_counters()
|
||||
, std::map<std::string, lt::dht::node*>())
|
||||
{
|
||||
|
@ -217,7 +223,8 @@ struct dht_node final : lt::dht::udp_socket_interface
|
|||
dht::node_id const mask = dht::generate_prefix_mask(bucket + 1);
|
||||
dht::node_id target = dht::generate_random_id() & ~mask;
|
||||
target |= id & mask;
|
||||
dht().m_table.node_seen(target, rand_udp_ep(), (lt::random() % 300) + 10);
|
||||
dht().m_table.node_seen(target, rand_udp_ep(m_ipv6 ? rand_v6 : rand_v4)
|
||||
, (lt::random() % 300) + 10);
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
@ -256,10 +263,11 @@ private:
|
|||
#endif
|
||||
lt::udp::endpoint m_ep;
|
||||
bool m_add_dead_nodes;
|
||||
bool m_ipv6;
|
||||
char m_buffer[1300];
|
||||
};
|
||||
|
||||
dht_network::dht_network(sim::simulation& sim, int num_nodes)
|
||||
dht_network::dht_network(sim::simulation& sim, int num_nodes, std::uint32_t flags)
|
||||
{
|
||||
m_sett.ignore_dark_internet = false;
|
||||
m_sett.restrict_routing_ips = false;
|
||||
|
@ -273,7 +281,7 @@ dht_network::dht_network(sim::simulation& sim, int num_nodes)
|
|||
for (int i = 0; i < num_nodes; ++i)
|
||||
{
|
||||
// node 0 is the one we log
|
||||
m_nodes.emplace_back(sim, m_sett, m_cnt, i, 0/*, dht_node::add_dead_nodes*/);
|
||||
m_nodes.emplace_back(sim, m_sett, m_cnt, i, flags);
|
||||
all_nodes.push_back(m_nodes.back().node_info());
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,13 @@ void print_routing_table(std::vector<lt::dht_routing_bucket> const& rt);
|
|||
|
||||
struct dht_network
|
||||
{
|
||||
dht_network(sim::simulation& sim, int num_nodes);
|
||||
enum flags_t
|
||||
{
|
||||
add_dead_nodes = 1,
|
||||
bind_ipv6 = 2
|
||||
};
|
||||
|
||||
dht_network(sim::simulation& sim, int num_nodes, std::uint32_t flags = 0);
|
||||
~dht_network();
|
||||
|
||||
void stop();
|
||||
|
|
|
@ -51,6 +51,49 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace lt = libtorrent;
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
void bootstrap_session(std::vector<dht_network*> networks, lt::session& ses)
|
||||
{
|
||||
lt::dht_settings sett;
|
||||
sett.ignore_dark_internet = false;
|
||||
ses.set_dht_settings(sett);
|
||||
|
||||
lt::entry state;
|
||||
|
||||
for (auto dht : networks)
|
||||
{
|
||||
// bootstrap off of 8 of the nodes
|
||||
auto router_nodes = dht->router_nodes();
|
||||
|
||||
char const* nodes_key;
|
||||
if (router_nodes.front().address().is_v6())
|
||||
nodes_key = "nodes6";
|
||||
else
|
||||
nodes_key = "nodes";
|
||||
|
||||
lt::entry::list_type& nodes = state["dht state"][nodes_key].list();
|
||||
for (auto const& n : router_nodes)
|
||||
{
|
||||
std::string node;
|
||||
std::back_insert_iterator<std::string> out(node);
|
||||
lt::detail::write_endpoint(n, out);
|
||||
nodes.push_back(lt::entry(node));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<char> buf;
|
||||
lt::bencode(std::back_inserter(buf), state);
|
||||
lt::bdecode_node e;
|
||||
lt::error_code ec;
|
||||
lt::bdecode(&buf[0], &buf[0] + buf.size(), e, ec);
|
||||
|
||||
ses.load_state(e);
|
||||
lt::settings_pack pack;
|
||||
pack.set_bool(lt::settings_pack::enable_dht, true);
|
||||
ses.apply_settings(pack);
|
||||
}
|
||||
#endif // TORRENT_DISABLE_DHT
|
||||
|
||||
TORRENT_TEST(dht_bootstrap)
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
|
@ -89,31 +132,7 @@ TORRENT_TEST(dht_bootstrap)
|
|||
{
|
||||
if (ticks == 0)
|
||||
{
|
||||
lt::dht_settings sett;
|
||||
sett.ignore_dark_internet = false;
|
||||
ses.set_dht_settings(sett);
|
||||
|
||||
// bootstrap off of 8 of the nodes
|
||||
lt::entry state;
|
||||
lt::entry::list_type& nodes = state["dht state"]["nodes"].list();
|
||||
for (auto const& n : dht.router_nodes())
|
||||
{
|
||||
std::string node;
|
||||
std::back_insert_iterator<std::string> out(node);
|
||||
lt::detail::write_endpoint(n, out);
|
||||
nodes.push_back(lt::entry(node));
|
||||
}
|
||||
|
||||
std::vector<char> buf;
|
||||
lt::bencode(std::back_inserter(buf), state);
|
||||
lt::bdecode_node e;
|
||||
lt::error_code ec;
|
||||
lt::bdecode(&buf[0], &buf[0] + buf.size(), e, ec);
|
||||
|
||||
ses.load_state(e);
|
||||
lt::settings_pack pack;
|
||||
pack.set_bool(lt::settings_pack::enable_dht, true);
|
||||
ses.apply_settings(pack);
|
||||
bootstrap_session({&dht}, ses);
|
||||
}
|
||||
if (ticks > 2)
|
||||
{
|
||||
|
@ -133,3 +152,196 @@ TORRENT_TEST(dht_bootstrap)
|
|||
|
||||
}
|
||||
|
||||
TORRENT_TEST(dht_dual_stack_get_peers)
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
sim::default_config cfg;
|
||||
sim::simulation sim{ cfg };
|
||||
|
||||
dht_network dht(sim, 100);
|
||||
dht_network dht6(sim, 100, dht_network::bind_ipv6);
|
||||
|
||||
lt::sha1_hash const test_ih("01234567890123456789");
|
||||
bool got_peer_v4 = false, got_peer_v6 = false;
|
||||
|
||||
setup_swarm(1, swarm_test::download, sim
|
||||
// add session
|
||||
, [](lt::settings_pack& pack) {
|
||||
}
|
||||
// add torrent
|
||||
, [](lt::add_torrent_params& params) {}
|
||||
// on alert
|
||||
, [&](lt::alert const* a, lt::session& ses)
|
||||
{
|
||||
if (lt::dht_get_peers_reply_alert const* p = lt::alert_cast<lt::dht_get_peers_reply_alert>(a))
|
||||
{
|
||||
std::vector<lt::tcp::endpoint> peers;
|
||||
p->peers(peers);
|
||||
for (lt::tcp::endpoint const& peer : peers)
|
||||
{
|
||||
// TODO: verify that the endpoint matches the session's
|
||||
got_peer_v4 |= peer.address().is_v4();
|
||||
got_peer_v6 |= peer.address().is_v6();
|
||||
}
|
||||
}
|
||||
}
|
||||
// terminate?
|
||||
, [&](int ticks, lt::session& ses) -> bool
|
||||
{
|
||||
if (ticks == 0)
|
||||
{
|
||||
bootstrap_session({&dht, &dht6}, ses);
|
||||
}
|
||||
if (ticks == 2)
|
||||
{
|
||||
ses.dht_announce(test_ih, 6881);
|
||||
}
|
||||
if (ticks == 4)
|
||||
{
|
||||
ses.dht_get_peers(test_ih);
|
||||
}
|
||||
if (ticks == 6)
|
||||
{
|
||||
TEST_CHECK(got_peer_v4);
|
||||
TEST_CHECK(got_peer_v6);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
sim.run();
|
||||
|
||||
#endif // TORRENT_DISABLE_DHT
|
||||
}
|
||||
|
||||
TORRENT_TEST(dht_dual_stack_immutable_item)
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
sim::default_config cfg;
|
||||
sim::simulation sim{ cfg };
|
||||
|
||||
dht_network dht(sim, 100);
|
||||
dht_network dht6(sim, 100, dht_network::bind_ipv6);
|
||||
|
||||
lt::sha1_hash item_hash;
|
||||
bool got_item = false;
|
||||
|
||||
setup_swarm(1, swarm_test::download, sim
|
||||
// add session
|
||||
, [](lt::settings_pack& pack) {
|
||||
}
|
||||
// add torrent
|
||||
, [](lt::add_torrent_params& params) {}
|
||||
// on alert
|
||||
, [&](lt::alert const* a, lt::session& ses)
|
||||
{
|
||||
if (lt::dht_immutable_item_alert const* p = lt::alert_cast<lt::dht_immutable_item_alert>(a))
|
||||
{
|
||||
// we should only get one alert for each request
|
||||
TEST_CHECK(!got_item);
|
||||
got_item = p->target == item_hash && p->item.string() == "immutable item";
|
||||
}
|
||||
}
|
||||
// terminate?
|
||||
, [&](int ticks, lt::session& ses) -> bool
|
||||
{
|
||||
if (ticks == 0)
|
||||
{
|
||||
bootstrap_session({&dht, &dht6}, ses);
|
||||
}
|
||||
if (ticks == 2)
|
||||
{
|
||||
item_hash = ses.dht_put_item(lt::entry("immutable item"));
|
||||
}
|
||||
if (ticks == 4)
|
||||
{
|
||||
ses.dht_get_item(item_hash);
|
||||
}
|
||||
if (ticks == 6)
|
||||
{
|
||||
TEST_CHECK(got_item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
sim.run();
|
||||
|
||||
#endif // TORRENT_DISABLE_DHT
|
||||
}
|
||||
|
||||
TORRENT_TEST(dht_dual_stack_mutable_item)
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
sim::default_config cfg;
|
||||
sim::simulation sim{ cfg };
|
||||
|
||||
dht_network dht(sim, 100);
|
||||
dht_network dht6(sim, 100, dht_network::bind_ipv6);
|
||||
|
||||
boost::array<char, ed25519_private_key_size> sk;
|
||||
boost::array<char, ed25519_public_key_size> pk;
|
||||
int put_count = 0;
|
||||
bool got_item = false;
|
||||
|
||||
setup_swarm(1, swarm_test::download, sim
|
||||
// add session
|
||||
, [](lt::settings_pack& pack) {
|
||||
}
|
||||
// add torrent
|
||||
, [](lt::add_torrent_params& params) {}
|
||||
// on alert
|
||||
, [&](lt::alert const* a, lt::session& ses)
|
||||
{
|
||||
if (lt::dht_mutable_item_alert const* p = lt::alert_cast<lt::dht_mutable_item_alert>(a))
|
||||
{
|
||||
TEST_CHECK(!got_item);
|
||||
if (p->authoritative)
|
||||
got_item = p->key == pk && p->item.string() == "mutable item";
|
||||
}
|
||||
}
|
||||
// terminate?
|
||||
, [&](int ticks, lt::session& ses) -> bool
|
||||
{
|
||||
if (ticks == 0)
|
||||
{
|
||||
bootstrap_session({&dht, &dht6}, ses);
|
||||
}
|
||||
if (ticks == 2)
|
||||
{
|
||||
boost::array<unsigned char, ed25519_seed_size> seed;
|
||||
ed25519_create_keypair((unsigned char*)pk.data()
|
||||
, (unsigned char*)sk.data(), seed.data());
|
||||
|
||||
ses.dht_put_item(pk, [&](lt::entry& item, boost::array<char, 64>& sig
|
||||
, boost::uint64_t& seq, std::string const& salt)
|
||||
{
|
||||
item = "mutable item";
|
||||
seq = 1;
|
||||
std::vector<char> v;
|
||||
lt::bencode(std::back_inserter(v), item);
|
||||
lt::dht::sign_mutable_item(
|
||||
std::make_pair(v.data(), v.size()), std::make_pair(salt.data(), salt.size())
|
||||
, seq, pk.data(), sk.data(), sig.data());
|
||||
put_count++;
|
||||
});
|
||||
}
|
||||
if (ticks == 4)
|
||||
{
|
||||
// should be one for each stack, ipv4 and ipv6
|
||||
TEST_EQUAL(put_count, 2);
|
||||
ses.dht_get_item(pk);
|
||||
}
|
||||
if (ticks == 6)
|
||||
{
|
||||
TEST_CHECK(got_item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
sim.run();
|
||||
|
||||
#endif // TORRENT_DISABLE_DHT
|
||||
}
|
||||
|
||||
|
|
|
@ -124,10 +124,10 @@ tcp::endpoint rand_tcp_ep()
|
|||
return tcp::endpoint(rand_v4(), g_port + 1024);
|
||||
}
|
||||
|
||||
udp::endpoint rand_udp_ep()
|
||||
udp::endpoint rand_udp_ep(libtorrent::address(&rand_addr)())
|
||||
{
|
||||
g_port = (g_port + 1) % 14037;
|
||||
return udp::endpoint(rand_v4(), g_port + 1024);
|
||||
return udp::endpoint(rand_addr(), g_port + 1024);
|
||||
}
|
||||
|
||||
std::map<std::string, boost::int64_t> get_counters(libtorrent::session& s)
|
||||
|
|
|
@ -57,7 +57,7 @@ EXPORT libtorrent::address rand_v4();
|
|||
EXPORT libtorrent::address rand_v6();
|
||||
#endif
|
||||
EXPORT libtorrent::tcp::endpoint rand_tcp_ep();
|
||||
EXPORT libtorrent::udp::endpoint rand_udp_ep();
|
||||
EXPORT libtorrent::udp::endpoint rand_udp_ep(libtorrent::address(&rand_addr)() = rand_v4);
|
||||
|
||||
EXPORT libtorrent::sha1_hash rand_hash();
|
||||
|
||||
|
|
Loading…
Reference in New Issue