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);
|
address ip = address::from_string(device_name, ec);
|
||||||
if (!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);
|
bind_ep.address(ip);
|
||||||
// it appears to be an IP. Just bind to that address
|
// it appears to be an IP. Just bind to that address
|
||||||
sock.bind(bind_ep, ec);
|
sock.bind(bind_ep, ec);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit dedd409321589f8ed11d244e1b65772435ef91d1
|
Subproject commit 47ccf576c6ed7700752ba294962d8e297b1ce76f
|
|
@ -127,11 +127,8 @@ struct swarm
|
||||||
bool term = false;
|
bool term = false;
|
||||||
ses->pop_alerts(&alerts);
|
ses->pop_alerts(&alerts);
|
||||||
|
|
||||||
for (std::vector<lt::alert*>::iterator i = alerts.begin();
|
for (lt::alert* a : alerts)
|
||||||
i != alerts.end(); ++i)
|
|
||||||
{
|
{
|
||||||
lt::alert* a = *i;
|
|
||||||
|
|
||||||
lt::time_duration d = a->timestamp() - m_start_time;
|
lt::time_duration d = a->timestamp() - m_start_time;
|
||||||
boost::uint32_t millis = lt::duration_cast<lt::milliseconds>(d).count();
|
boost::uint32_t millis = lt::duration_cast<lt::milliseconds>(d).count();
|
||||||
printf("%4d.%03d: [%02d] %s\n", millis / 1000, millis % 1000,
|
printf("%4d.%03d: [%02d] %s\n", millis / 1000, millis % 1000,
|
||||||
|
|
|
@ -42,6 +42,8 @@ using namespace libtorrent;
|
||||||
using namespace sim;
|
using namespace sim;
|
||||||
namespace lt = libtorrent;
|
namespace lt = libtorrent;
|
||||||
|
|
||||||
|
using chrono::duration_cast;
|
||||||
|
|
||||||
// seconds
|
// seconds
|
||||||
const int duration = 10000;
|
const int duration = 10000;
|
||||||
|
|
||||||
|
@ -257,6 +259,131 @@ TORRENT_TEST(announce_interval_1200)
|
||||||
test_interval(3600);
|
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 with different queuing settings
|
||||||
// TODO: test when a torrent transitions from downloading to finished and
|
// TODO: test when a torrent transitions from downloading to finished and
|
||||||
// finished to seeding
|
// finished to seeding
|
||||||
|
|
|
@ -1940,7 +1940,9 @@ retry:
|
||||||
{
|
{
|
||||||
error_code err;
|
error_code err;
|
||||||
address test_family = address::from_string(device.c_str(), 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;
|
continue;
|
||||||
|
|
||||||
listen_socket_t s = setup_listener(device, address_family, port
|
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
|
// do it if the bind IP for the tracker request that just completed
|
||||||
// matches one of the listen interfaces, since that means this
|
// matches one of the listen interfaces, since that means this
|
||||||
// announce was the second one
|
// 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())
|
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()))
|
|| (!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_ipv4_interface().address()
|
||||||
&& r.bind_ip != m_ses.get_ipv6_interface().address()
|
&& r.bind_ip != m_ses.get_ipv6_interface().address())
|
||||||
&& r.event != tracker_request::stopped)
|
|
||||||
{
|
{
|
||||||
std::list<address>::const_iterator i = std::find_if(tracker_ips.begin()
|
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());
|
, 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
|
// the tracker did resolve to a different type of address, so announce
|
||||||
// to that as well
|
// 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
|
// tell the tracker to bind to the opposite protocol type
|
||||||
address bind_interface = tracker_ip.is_v4()
|
req.bind_ip = tracker_ip.is_v4()
|
||||||
? m_ses.get_ipv6_interface().address()
|
? m_ses.get_ipv6_interface().address()
|
||||||
: m_ses.get_ipv4_interface().address();
|
: m_ses.get_ipv4_interface().address();
|
||||||
announce_with_tracker(r.event, bind_interface);
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
debug_log("announce again using %s as the bind interface"
|
debug_log("announce again using %s as the bind interface"
|
||||||
, print_address(bind_interface).c_str());
|
, print_address(req.bind_ip).c_str());
|
||||||
#endif
|
#endif
|
||||||
|
m_ses.queue_tracker_request(req, shared_from_this());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue