diff --git a/ChangeLog b/ChangeLog index d66c92f33..8edd7bb0f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * add support for IPv6 peers from udp trackers * correctly URL encode the IPv6 argument to trackers * fix default file pool size on windows * fix bug where settings_pack::file_pool_size setting was not being honored diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp index 3e1430884..141f81b34 100644 --- a/src/udp_tracker_connection.cpp +++ b/src/udp_tracker_connection.cpp @@ -598,8 +598,15 @@ namespace libtorrent resp.min_interval = 60; resp.incomplete = detail::read_int32(buf); resp.complete = detail::read_int32(buf); - int num_peers = (size - 20) / 6; - if ((size - 20) % 6 != 0) + + std::size_t const ip_stride = +#if TORRENT_USE_IPV6 + m_target.address().is_v6() ? 18 : +#endif + 6; + + int const num_peers = (size - 20) / ip_stride; + if ((size - 20) % ip_stride != 0) { fail(error_code(errors::invalid_tracker_response_length)); return false; @@ -619,14 +626,31 @@ namespace libtorrent return true; } - resp.peers4.reserve(num_peers); - for (int i = 0; i < num_peers; ++i) +#if TORRENT_USE_IPV6 + if (m_target.address().is_v6()) { - ipv4_peer_entry e; - memcpy(&e.ip[0], buf, 4); - buf += 4; - e.port = detail::read_uint16(buf); - resp.peers4.push_back(e); + resp.peers6.reserve(std::size_t(num_peers)); + for (int i = 0; i < num_peers; ++i) + { + ipv6_peer_entry e; + std::memcpy(&e.ip[0], buf, 16); + buf += 16; + e.port = detail::read_uint16(buf); + resp.peers6.push_back(e); + } + } + else +#endif + { + resp.peers4.reserve(std::size_t(num_peers)); + for (int i = 0; i < num_peers; ++i) + { + ipv4_peer_entry e; + memcpy(&e.ip[0], buf, 4); + buf += 4; + e.port = detail::read_uint16(buf); + resp.peers4.push_back(e); + } } std::list
ip_list; diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 3cbcda4df..4615b5dc3 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -264,7 +264,7 @@ void save_file(char const* filename, char const* data, int size) bool print_alerts(lt::session& ses, char const* name , bool allow_disconnects, bool allow_no_torrents, bool allow_failed_fastresume - , bool (*predicate)(libtorrent::alert const*), bool no_output) + , boost::function predicate, bool no_output) { bool ret = false; std::vector handles = ses.get_torrents(); diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index 3b5ece736..bbb5e3fb6 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -75,7 +75,8 @@ EXPORT bool print_alerts(libtorrent::session& ses, char const* name , bool allow_disconnects = false , bool allow_no_torrents = false , bool allow_failed_fastresume = false - , bool (*)(libtorrent::alert const*) = 0 + , boost::function predicate + = boost::function() , bool no_output = false); EXPORT void wait_for_listen(libtorrent::session& ses, char const* name); diff --git a/test/test_tracker.cpp b/test/test_tracker.cpp index 0f25c4570..1c980632f 100644 --- a/test/test_tracker.cpp +++ b/test/test_tracker.cpp @@ -312,17 +312,23 @@ TORRENT_TEST(extract_peer_missing_port) , errors::invalid_tracker_response, false); } -TORRENT_TEST(udp_tracker) +bool connect_alert(libtorrent::alert const* a, tcp::endpoint& ep) { - int http_port = start_web_server(); - int udp_port = start_udp_tracker(); + if (peer_connect_alert const* pc = alert_cast(a)) + ep = pc->ip; + return true; +} + +void test_udp_tracker(std::string const& iface, address tracker, tcp::endpoint const& expected_peer) +{ + int const udp_port = start_udp_tracker(tracker); int prev_udp_announces = num_udp_announces(); settings_pack pack = settings(); pack.set_bool(settings_pack::announce_to_all_trackers, true); pack.set_bool(settings_pack::announce_to_all_tiers, true); - pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:48875"); + pack.set_str(settings_pack::listen_interfaces, iface + ":48875"); boost::scoped_ptr s(new lt::session(pack)); @@ -334,12 +340,9 @@ TORRENT_TEST(udp_tracker) file.close(); char tracker_url[200]; - snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port); + snprintf(tracker_url, sizeof(tracker_url), "udp://%s:%d/announce", iface.c_str(), udp_port); t->add_tracker(tracker_url, 0); - snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port); - t->add_tracker(tracker_url, 1); - add_torrent_params addp; addp.flags &= ~add_torrent_params::flag_paused; addp.flags &= ~add_torrent_params::flag_auto_managed; @@ -348,9 +351,11 @@ TORRENT_TEST(udp_tracker) addp.save_path = "tmp1_tracker"; torrent_handle h = s->add_torrent(addp); + tcp::endpoint peer_ep; for (int i = 0; i < 50; ++i) { - print_alerts(*s, "s"); + print_alerts(*s, "s", false, false, false, boost::bind(&connect_alert, _1, boost::ref(peer_ep))); + if (num_udp_announces() == prev_udp_announces + 1) break; @@ -370,7 +375,7 @@ TORRENT_TEST(udp_tracker) for (int i = 0; i < 50; ++i) { - print_alerts(*s, "s", true, true); + print_alerts(*s, "s", true, true, false, boost::bind(&connect_alert, _1, boost::ref(peer_ep))); if (num_udp_announces() == prev_udp_announces + 2) break; @@ -379,6 +384,8 @@ TORRENT_TEST(udp_tracker) , int(prev_udp_announces) + 1); } + TEST_CHECK(peer_ep == expected_peer); + fprintf(stderr, "destructing session\n"); s.reset(); fprintf(stderr, "done\n"); @@ -387,6 +394,18 @@ TORRENT_TEST(udp_tracker) TEST_EQUAL(num_udp_announces(), prev_udp_announces + 2); } +TORRENT_TEST(udp_tracker_v4) +{ + test_udp_tracker("127.0.0.1", address_v4::any(), ep("1.3.3.7", 1337)); +} + +#if TORRENT_USE_IPV6 +TORRENT_TEST(udp_tracker_v6) +{ + test_udp_tracker("[::1]", address_v6::any(), ep("::1.3.3.7", 1337)); +} +#endif + TORRENT_TEST(http_peers) { int http_port = start_web_server(); diff --git a/test/udp_tracker.cpp b/test/udp_tracker.cpp index 5d5a59fdd..922dbfe55 100644 --- a/test/udp_tracker.cpp +++ b/test/udp_tracker.cpp @@ -120,9 +120,30 @@ struct udp_tracker detail::write_uint32(1800, ptr); // interval detail::write_uint32(1, ptr); // incomplete detail::write_uint32(1, ptr); // complete - // 0 peers - m_socket.send_to(boost::asio::buffer(buffer, 20), *from, 0, e); - if (e) fprintf(stderr, "%s: UDP send_to failed. ERROR: %s\n" + // 1 peers +#if TORRENT_USE_IPV6 + if (from->address().is_v6()) + { + detail::write_uint32(0, ptr); + detail::write_uint32(0, ptr); + detail::write_uint32(0, ptr); + detail::write_uint8(1, ptr); + detail::write_uint8(3, ptr); + detail::write_uint8(3, ptr); + detail::write_uint8(7, ptr); + detail::write_uint16(1337, ptr); + } + else +#endif + { + detail::write_uint8(1, ptr); + detail::write_uint8(3, ptr); + detail::write_uint8(3, ptr); + detail::write_uint8(7, ptr); + detail::write_uint16(1337, ptr); + } + m_socket.send_to(boost::asio::buffer(buffer, ptr - buffer), *from, 0, e); + if (e) std::printf("%s: UDP send_to failed. ERROR: %s\n" , time_now_string(), e.message().c_str()); else fprintf(stderr, "%s: UDP sent response to: %s\n" , time_now_string(), print_endpoint(*from).c_str()); @@ -142,21 +163,21 @@ struct udp_tracker , boost::bind(&udp_tracker::on_udp_receive, this, _1, _2, from, buffer, size)); } - udp_tracker() + udp_tracker(address iface) : m_udp_announces(0) , m_socket(m_ios) , m_port(0) , m_abort(false) { error_code ec; - m_socket.open(udp::v4(), ec); + m_socket.open(iface.is_v4() ? udp::v4() : udp::v6(), ec); if (ec) { fprintf(stderr, "UDP Error opening listen UDP tracker socket: %s\n", ec.message().c_str()); return; } - m_socket.bind(udp::endpoint(address_v4::any(), 0), ec); + m_socket.bind(udp::endpoint(iface, 0), ec); if (ec) { fprintf(stderr, "UDP Error binding UDP tracker socket to port 0: %s\n", ec.message().c_str()); @@ -176,6 +197,7 @@ struct udp_tracker void stop() { + std::printf("%s: UDP tracker, stop\n", time_now_string()); m_abort = true; m_socket.cancel(); m_socket.close(); @@ -222,9 +244,9 @@ struct udp_tracker boost::shared_ptr g_udp_tracker; -int start_udp_tracker() +int start_udp_tracker(address iface) { - g_udp_tracker.reset(new udp_tracker); + g_udp_tracker.reset(new udp_tracker(iface)); return g_udp_tracker->port(); } diff --git a/test/udp_tracker.hpp b/test/udp_tracker.hpp index d27258da1..56dc07eed 100644 --- a/test/udp_tracker.hpp +++ b/test/udp_tracker.hpp @@ -31,9 +31,11 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "test.hpp" // for EXPORT +#include "libtorrent/address.hpp" // returns the port the udp tracker is running on -int EXPORT start_udp_tracker(); +int EXPORT start_udp_tracker(libtorrent::address iface + = libtorrent::address_v4::any()); // the number of udp tracker announces received int EXPORT num_udp_announces();