forked from premiere/premiere-libtorrent
update libsimulator. add simulation/test for announcing twice to trackers over IPv4 and IPv6. fix bugs preventing libtorrent from doing that correctly
This commit is contained in:
parent
b2796af5b3
commit
729a8e9152
|
@ -124,6 +124,13 @@ namespace libtorrent
|
|||
address ip = address::from_string(device_name, ec);
|
||||
if (!ec)
|
||||
{
|
||||
#if TORRENT_USE_IPV6
|
||||
// this is to cover the case where "0.0.0.0" is considered any IPv4 or
|
||||
// IPv6 address. If we're asking to be bound to an IPv6 address and
|
||||
// providing 0.0.0.0 as the device, turn it into "::0"
|
||||
if (ip == address_v4::any() && !ipv4)
|
||||
ip = address_v6::any();
|
||||
#endif
|
||||
bind_ep.address(ip);
|
||||
// it appears to be an IP. Just bind to that address
|
||||
sock.bind(bind_ep, ec);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit dedd409321589f8ed11d244e1b65772435ef91d1
|
||||
Subproject commit 47ccf576c6ed7700752ba294962d8e297b1ce76f
|
|
@ -127,11 +127,8 @@ struct swarm
|
|||
bool term = false;
|
||||
ses->pop_alerts(&alerts);
|
||||
|
||||
for (std::vector<lt::alert*>::iterator i = alerts.begin();
|
||||
i != alerts.end(); ++i)
|
||||
for (lt::alert* a : alerts)
|
||||
{
|
||||
lt::alert* a = *i;
|
||||
|
||||
lt::time_duration d = a->timestamp() - m_start_time;
|
||||
boost::uint32_t millis = lt::duration_cast<lt::milliseconds>(d).count();
|
||||
printf("%4d.%03d: [%02d] %s\n", millis / 1000, millis % 1000,
|
||||
|
|
|
@ -42,6 +42,8 @@ using namespace libtorrent;
|
|||
using namespace sim;
|
||||
namespace lt = libtorrent;
|
||||
|
||||
using chrono::duration_cast;
|
||||
|
||||
// seconds
|
||||
const int duration = 10000;
|
||||
|
||||
|
@ -257,6 +259,131 @@ TORRENT_TEST(announce_interval_1200)
|
|||
test_interval(3600);
|
||||
}
|
||||
|
||||
struct sim_config : sim::default_config
|
||||
{
|
||||
chrono::high_resolution_clock::duration hostname_lookup(
|
||||
asio::ip::address const& requestor
|
||||
, std::string hostname
|
||||
, std::vector<asio::ip::address>& result
|
||||
, boost::system::error_code& ec)
|
||||
{
|
||||
if (hostname == "tracker.com")
|
||||
{
|
||||
result.push_back(address_v4::from_string("10.0.0.2"));
|
||||
result.push_back(address_v6::from_string("ff::dead:beef"));
|
||||
return duration_cast<chrono::high_resolution_clock::duration>(chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
return default_config::hostname_lookup(requestor, hostname, result, ec);
|
||||
}
|
||||
};
|
||||
|
||||
void on_alert_notify(lt::session* ses)
|
||||
{
|
||||
std::vector<lt::alert*> alerts;
|
||||
ses->pop_alerts(&alerts);
|
||||
|
||||
for (lt::alert* a : alerts)
|
||||
{
|
||||
lt::time_duration d = a->timestamp().time_since_epoch();
|
||||
boost::uint32_t millis = lt::duration_cast<lt::milliseconds>(d).count();
|
||||
printf("%4d.%03d: %s\n", millis / 1000, millis % 1000,
|
||||
a->message().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// this test makes sure that a tracker whose host name resolves to both IPv6 and
|
||||
// IPv4 addresses will be announced to twice, once for each address family
|
||||
TORRENT_TEST(ipv6_support)
|
||||
{
|
||||
using sim::asio::ip::address_v4;
|
||||
sim_config network_cfg;
|
||||
sim::simulation sim{network_cfg};
|
||||
|
||||
sim::asio::io_service web_server_v4(sim, address_v4::from_string("10.0.0.2"));
|
||||
sim::asio::io_service web_server_v6(sim, address_v6::from_string("ff::dead:beef"));
|
||||
|
||||
// listen on port 8080
|
||||
sim::http_server http_v4(web_server_v4, 8080);
|
||||
sim::http_server http_v6(web_server_v6, 8080);
|
||||
|
||||
// the timestamps (in seconds) of all announces
|
||||
std::vector<std::string> announces;
|
||||
|
||||
int v4_announces = 0;
|
||||
int v6_announces = 0;
|
||||
|
||||
http_v4.register_handler("/announce"
|
||||
, [&v4_announces](std::string method, std::string req)
|
||||
{
|
||||
++v4_announces;
|
||||
TEST_EQUAL(method, "GET");
|
||||
|
||||
char response[500];
|
||||
int size = snprintf(response, sizeof(response), "d8:intervali1800e5:peers0:e");
|
||||
return sim::send_response(200, "OK", size) + response;
|
||||
});
|
||||
|
||||
http_v6.register_handler("/announce"
|
||||
, [&v6_announces](std::string method, std::string req)
|
||||
{
|
||||
++v6_announces;
|
||||
TEST_EQUAL(method, "GET");
|
||||
|
||||
char response[500];
|
||||
int size = snprintf(response, sizeof(response), "d8:intervali1800e5:peers0:e");
|
||||
return sim::send_response(200, "OK", size) + response;
|
||||
});
|
||||
|
||||
{
|
||||
lt::session_proxy zombie;
|
||||
|
||||
asio::io_service ios(sim, { address_v4::from_string("10.0.0.3")
|
||||
, address_v6::from_string("ffff::1337") });
|
||||
lt::settings_pack sett = settings();
|
||||
std::unique_ptr<lt::session> ses(new lt::session(sett, ios));
|
||||
|
||||
ses->set_alert_notify(std::bind(&on_alert_notify, ses.get()));
|
||||
|
||||
|
||||
lt::add_torrent_params p;
|
||||
p.name = "test-torrent";
|
||||
p.save_path = ".";
|
||||
p.info_hash.assign("abababababababababab");
|
||||
|
||||
//TODO: parameterize http vs. udp here
|
||||
p.trackers.push_back("http://tracker.com:8080/announce");
|
||||
ses->async_add_torrent(p);
|
||||
|
||||
// stop the torrent 5 seconds in
|
||||
asio::high_resolution_timer stop(ios);
|
||||
stop.expires_from_now(chrono::seconds(5));
|
||||
stop.async_wait([&ses](boost::system::error_code const& ec)
|
||||
{
|
||||
std::vector<lt::torrent_handle> torrents = ses->get_torrents();
|
||||
for (auto const& t : torrents)
|
||||
{
|
||||
t.pause();
|
||||
}
|
||||
});
|
||||
|
||||
// then shut down 10 seconds in
|
||||
asio::high_resolution_timer terminate(ios);
|
||||
terminate.expires_from_now(chrono::seconds(10));
|
||||
terminate.async_wait([&ses,&zombie](boost::system::error_code const& ec)
|
||||
{
|
||||
zombie = ses->abort();
|
||||
ses.reset();
|
||||
});
|
||||
|
||||
sim.run();
|
||||
}
|
||||
|
||||
// 2 because there's one announce on startup and one when shutting down
|
||||
TEST_EQUAL(v4_announces, 2);
|
||||
TEST_EQUAL(v6_announces, 2);
|
||||
}
|
||||
|
||||
// TODO: test with different queuing settings
|
||||
// TODO: test when a torrent transitions from downloading to finished and
|
||||
// finished to seeding
|
||||
|
|
|
@ -1940,7 +1940,9 @@ retry:
|
|||
{
|
||||
error_code err;
|
||||
address test_family = address::from_string(device.c_str(), err);
|
||||
if (!err && test_family.is_v4() != address_family)
|
||||
if (!err
|
||||
&& test_family.is_v4() != address_family
|
||||
&& !is_any(test_family))
|
||||
continue;
|
||||
|
||||
listen_socket_t s = setup_listener(device, address_family, port
|
||||
|
|
|
@ -3531,13 +3531,11 @@ namespace libtorrent
|
|||
// do it if the bind IP for the tracker request that just completed
|
||||
// matches one of the listen interfaces, since that means this
|
||||
// announce was the second one
|
||||
// don't connect twice just to tell it we're stopping
|
||||
|
||||
if (((!is_any(m_ses.get_ipv6_interface().address()) && tracker_ip.is_v4())
|
||||
|| (!is_any(m_ses.get_ipv4_interface().address()) && tracker_ip.is_v6()))
|
||||
&& r.bind_ip != m_ses.get_ipv4_interface().address()
|
||||
&& r.bind_ip != m_ses.get_ipv6_interface().address()
|
||||
&& r.event != tracker_request::stopped)
|
||||
&& r.bind_ip != m_ses.get_ipv6_interface().address())
|
||||
{
|
||||
std::list<address>::const_iterator i = std::find_if(tracker_ips.begin()
|
||||
, tracker_ips.end(), boost::bind(&address::is_v4, _1) != tracker_ip.is_v4());
|
||||
|
@ -3546,15 +3544,22 @@ namespace libtorrent
|
|||
// the tracker did resolve to a different type of address, so announce
|
||||
// to that as well
|
||||
|
||||
// TODO 2: there's a bug when removing a torrent or shutting down the session,
|
||||
// where the second announce is skipped (in this case, the one to the IPv6
|
||||
// name). This should be fixed by generalizing the tracker list structure to
|
||||
// separate the IPv6 and IPv4 addresses as conceptually separate trackers,
|
||||
// and they should be announced to in parallel
|
||||
|
||||
tracker_request req = r;
|
||||
// tell the tracker to bind to the opposite protocol type
|
||||
address bind_interface = tracker_ip.is_v4()
|
||||
?m_ses.get_ipv6_interface().address()
|
||||
:m_ses.get_ipv4_interface().address();
|
||||
announce_with_tracker(r.event, bind_interface);
|
||||
req.bind_ip = tracker_ip.is_v4()
|
||||
? m_ses.get_ipv6_interface().address()
|
||||
: m_ses.get_ipv4_interface().address();
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
debug_log("announce again using %s as the bind interface"
|
||||
, print_address(bind_interface).c_str());
|
||||
, print_address(req.bind_ip).c_str());
|
||||
#endif
|
||||
m_ses.queue_tracker_request(req, shared_from_this());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue