From 3abecd2546e5aaaa3f9c11ba0715e9c52cb82345 Mon Sep 17 00:00:00 2001 From: AllSeeingEyeTolledEweSew Date: Sat, 26 Nov 2016 03:39:17 +0000 Subject: [PATCH 01/12] Cast cached_piece_info::kind to int. --- bindings/python/src/session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/src/session.cpp b/bindings/python/src/session.cpp index 91018b589..c0d83d205 100644 --- a/bindings/python/src/session.cpp +++ b/bindings/python/src/session.cpp @@ -477,7 +477,7 @@ namespace d["piece"] = i->piece; d["last_use"] = total_milliseconds(now - i->last_use) / 1000.f; d["next_to_hash"] = i->next_to_hash; - d["kind"] = i->kind; + d["kind"] = static_cast(i->kind); pieces.append(d); } return pieces; From be4167660e7dc0b51d0f219405e3f18753b4ea60 Mon Sep 17 00:00:00 2001 From: Calum Lind Date: Sat, 26 Nov 2016 22:07:02 +0000 Subject: [PATCH 02/12] Fix autoreconf AC_LANG_CONFTEST warnings --- m4/ax_check_openssl.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m4/ax_check_openssl.m4 b/m4/ax_check_openssl.m4 index aecf20849..973f7e880 100644 --- a/m4/ax_check_openssl.m4 +++ b/m4/ax_check_openssl.m4 @@ -106,7 +106,7 @@ AC_DEFUN([AX_CHECK_OPENSSL], [ LIBS="$OPENSSL_LIBS $LIBS" CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" AC_LINK_IFELSE( - AC_LANG_PROGRAM([#include ], [SSL_new(NULL)]), + [AC_LANG_PROGRAM([#include ], [SSL_new(NULL)])], [ AC_MSG_RESULT([yes]) $1 From 8874a907eff76748b9e4904848049c2474665571 Mon Sep 17 00:00:00 2001 From: arvidn Date: Fri, 2 Dec 2016 18:13:39 -0500 Subject: [PATCH 03/12] fix to file priorities --- src/torrent.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/torrent.cpp b/src/torrent.cpp index c400c283c..eb89c9e71 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -5626,8 +5626,8 @@ namespace libtorrent else if (prio > 7) prio = 7; if (int(m_file_priority.size()) <= index) { - // any unallocated slot is assumed to be 1 - if (prio == 1) return; + // any unallocated slot is assumed to be 4 + if (prio == 4) return; m_file_priority.resize(index+1, 4); } @@ -5717,6 +5717,8 @@ namespace libtorrent if (file_prio == 0) { + // the pieces already start out as priority 0, no need to update + // the pieces vector in this case need_update = true; continue; } @@ -5733,8 +5735,7 @@ namespace libtorrent , pieces.begin() + last_piece + 1 , boost::bind(&set_if_greater, _1, file_prio)); - if (has_picker() || file_prio != 1) - need_update = true; + need_update = true; } if (need_update) prioritize_pieces(pieces); } From 29e09a457abfbbd34bcd894a455146df7169b80c Mon Sep 17 00:00:00 2001 From: arvidn Date: Fri, 2 Dec 2016 18:25:50 -0500 Subject: [PATCH 04/12] fix deprecation of use_interface --- include/libtorrent/torrent_handle.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index f4449fcf9..8a0ecd2c1 100644 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -972,8 +972,6 @@ namespace libtorrent // will return the resume data in an alert TORRENT_DEPRECATED entry write_resume_data() const; - // ================ end deprecation ============ -#endif // ``use_interface()`` sets the network interface this torrent will use // when it opens outgoing connections. By default, it uses the same @@ -982,7 +980,10 @@ namespace libtorrent // IPv4 or IPv6 address). When specifying multiple interfaces, the // torrent will round-robin which interface to use for each outgoing // connection. This is useful for clients that are multi-homed. + TORRENT_DEPRECATED void use_interface(const char* net_interface) const; + // ================ end deprecation ============ +#endif // Fills the specified ``std::vector`` with the availability for // each piece in this torrent. libtorrent does not keep track of From 864fcfacedde949666988fc26180ee8581788ccf Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 4 Dec 2016 09:16:00 -0500 Subject: [PATCH 05/12] initialize piece priorities to 4 --- bindings/python/test.py | 3 +++ src/torrent.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bindings/python/test.py b/bindings/python/test.py index 4df6bfb52..e594f11dc 100644 --- a/bindings/python/test.py +++ b/bindings/python/test.py @@ -29,6 +29,9 @@ class test_torrent_handle(unittest.TestCase): ti = lt.torrent_info('url_seed_multi.torrent'); h = ses.add_torrent({'ti': ti, 'save_path': os.getcwd()}) + self.assertEqual(h.file_priorities(), [4,4]) + self.assertEqual(h.piece_priorities(), [4]) + h.prioritize_files([0,1]) self.assertEqual(h.file_priorities(), [0,1]) diff --git a/src/torrent.cpp b/src/torrent.cpp index eb89c9e71..d547fa240 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -5545,7 +5545,7 @@ namespace libtorrent if (!has_picker()) { pieces->clear(); - pieces->resize(m_torrent_file->num_pieces(), 1); + pieces->resize(m_torrent_file->num_pieces(), 4); return; } From 5d0322d393081cc2cd74639d82679fba63b1767f Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Tue, 6 Dec 2016 13:38:24 -0800 Subject: [PATCH 06/12] fix assertion in fingerprint::to_string --- src/fingerprint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fingerprint.cpp b/src/fingerprint.cpp index 763f61833..304d56dc6 100644 --- a/src/fingerprint.cpp +++ b/src/fingerprint.cpp @@ -91,7 +91,7 @@ namespace libtorrent { #ifndef TORRENT_NO_DEPRECATE std::string fingerprint::to_string() const { - return generate_fingerprint(name, major_version, minor_version + return generate_fingerprint(std::string(name, 2), major_version, minor_version , revision_version, tag_version); } #endif // TORRENT_NO_DEPRECATE From a39f3714b2dba9c97ec08be2378e9f9f8dd92912 Mon Sep 17 00:00:00 2001 From: arvidn Date: Wed, 7 Dec 2016 20:09:57 -0500 Subject: [PATCH 07/12] fix python build with CC/CXX environment --- ChangeLog | 1 + bindings/python/setup.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index fbe011249..93a6e8747 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fix python build with CC/CXX environment * add trackers from add_torrent_params/magnet links to separate tiers * fix resumedata check issue with files with priority 0 * deprecated mmap_cache feature diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 69de9b95b..9492314e5 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -116,6 +116,13 @@ else: extra_link = flags.parse(ldflags) extra_compile = flags.parse(extra_cmd) + # for some reason distutils uses the CC environment variable to determine + # the compiler to use for C++ + if 'CXX' in os.environ: + os.environ['CC'] = os.environ['CXX'] + if 'CXXFLAGS' in os.environ: + os.environ['CFLAGS'] = os.environ['CXXFLAGS'] + ext = [Extension('libtorrent', sources = source_list, language='c++', From 30303c17dfce4baae84758dd2fc9c93d9165da62 Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Thu, 8 Dec 2016 11:00:12 -0800 Subject: [PATCH 08/12] don't indicate interest in peers when in upload only mode If the torrent is paused we don't want to mark peers as interesting even if the torrent has not finished downloading. --- src/peer_connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index b9ddb69d9..dea740fce 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -1929,7 +1929,7 @@ namespace libtorrent // calling disconnect_if_redundant, otherwise we may disconnect even if // we are interested if (!t->has_piece_passed(index) - && !t->is_seed() + && !t->is_upload_only() && !is_interesting() && (!t->has_picker() || t->picker().piece_priority(index) != 0)) t->peer_is_interesting(*this); From db65eaaa00c2e0582f75a6946caa5d9173bcc198 Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Thu, 15 Dec 2016 14:11:31 -0800 Subject: [PATCH 09/12] submit disk jobs from read_piece right away Without this the jobs get submitted on the next tick which may take a while. --- src/torrent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/torrent.cpp b/src/torrent.cpp index d547fa240..e91afbc01 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1028,6 +1028,8 @@ namespace libtorrent get_handle(), r.piece, rp->piece_data, 0); return; } + + m_ses.deferred_submit_jobs(); for (int i = 0; i < blocks_in_piece; ++i, r.start += block_size()) { r.length = (std::min)(piece_size - r.start, block_size()); From d62b98027829186e52d62ddaed33907fecce1928 Mon Sep 17 00:00:00 2001 From: Andrei Kurushin Date: Sun, 18 Dec 2016 15:31:02 +0300 Subject: [PATCH 10/12] backport fix upnp xml_parse --- include/libtorrent/upnp.hpp | 21 ++++++++++ src/upnp.cpp | 82 +++++++++++++++---------------------- test/test_xml.cpp | 52 +++++++++++++++++++++++ 3 files changed, 107 insertions(+), 48 deletions(-) diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index beee17768..a5538cded 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -130,9 +130,30 @@ struct parse_state } }; +struct error_code_parse_state +{ + error_code_parse_state(): in_error_code(false), exit(false), error_code(-1) {} + bool in_error_code; + bool exit; + int error_code; +}; + +struct ip_address_parse_state: error_code_parse_state +{ + ip_address_parse_state(): in_ip_address(false) {} + bool in_ip_address; + std::string ip_address; +}; + TORRENT_EXTRA_EXPORT void find_control_url(int type, char const* string , int str_len, parse_state& state); +TORRENT_EXTRA_EXPORT void find_error_code(int type, char const* string + , int str_len, error_code_parse_state& state); + +TORRENT_EXTRA_EXPORT void find_ip_address(int type, char const* string + , int str_len, ip_address_parse_state& state); + // TODO: support using the windows API for UPnP operations as well class TORRENT_EXTRA_EXPORT upnp : public boost::enable_shared_from_this { diff --git a/src/upnp.cpp b/src/upnp.cpp index ab10a02a2..f78ac9824 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -1063,53 +1063,39 @@ void upnp::disable(error_code const& ec, mutex::scoped_lock& l) m_socket.close(); } +void find_error_code(int type, char const* string, int str_len, error_code_parse_state& state) +{ + if (state.exit) return; + if (type == xml_start_tag && !std::strncmp("errorCode", string, size_t(str_len))) + { + state.in_error_code = true; + } + else if (type == xml_string && state.in_error_code) + { + std::string error_code_str(string, str_len); + state.error_code = std::atoi(error_code_str.c_str()); + state.exit = true; + } +} + +void find_ip_address(int type, char const* string, int str_len, ip_address_parse_state& state) +{ + find_error_code(type, string, str_len, state); + if (state.exit) return; + + if (type == xml_start_tag && !std::strncmp("NewExternalIPAddress", string, size_t(str_len))) + { + state.in_ip_address = true; + } + else if (type == xml_string && state.in_ip_address) + { + state.ip_address.assign(string, str_len); + state.exit = true; + } +} + namespace { - struct error_code_parse_state - { - error_code_parse_state(): in_error_code(false), exit(false), error_code(-1) {} - bool in_error_code; - bool exit; - int error_code; - }; - - void find_error_code(int type, char const* string, error_code_parse_state& state) - { - if (state.exit) return; - if (type == xml_start_tag && !std::strcmp("errorCode", string)) - { - state.in_error_code = true; - } - else if (type == xml_string && state.in_error_code) - { - state.error_code = std::atoi(string); - state.exit = true; - } - } - - struct ip_address_parse_state: public error_code_parse_state - { - ip_address_parse_state(): in_ip_address(false) {} - bool in_ip_address; - std::string ip_address; - }; - - void find_ip_address(int type, char const* string, ip_address_parse_state& state) - { - find_error_code(type, string, state); - if (state.exit) return; - - if (type == xml_start_tag && !std::strcmp("NewExternalIPAddress", string)) - { - state.in_ip_address = true; - } - else if (type == xml_string && state.in_ip_address) - { - state.ip_address = string; - state.exit = true; - } - } - struct error_code_t { int code; @@ -1239,7 +1225,7 @@ void upnp::on_upnp_get_ip_address_response(error_code const& e ip_address_parse_state s; xml_parse(const_cast(p.get_body().begin), const_cast(p.get_body().end) - , boost::bind(&find_ip_address, _1, _2, boost::ref(s))); + , boost::bind(&find_ip_address, _1, _2, _3, boost::ref(s))); if (s.error_code != -1) { char msg[500]; @@ -1333,7 +1319,7 @@ void upnp::on_upnp_map_response(error_code const& e error_code_parse_state s; xml_parse(const_cast(p.get_body().begin) , const_cast(p.get_body().end) - , boost::bind(&find_error_code, _1, _2, boost::ref(s))); + , boost::bind(&find_error_code, _1, _2, _3, boost::ref(s))); if (s.error_code != -1) { @@ -1476,7 +1462,7 @@ void upnp::on_upnp_unmap_response(error_code const& e { xml_parse(const_cast(p.get_body().begin) , const_cast(p.get_body().end) - , boost::bind(&find_error_code, _1, _2, boost::ref(s))); + , boost::bind(&find_error_code, _1, _2, _3, boost::ref(s))); } int const proto = m_mappings[mapping].protocol; diff --git a/test/test_xml.cpp b/test/test_xml.cpp index 2ef6df392..a42c38e64 100644 --- a/test/test_xml.cpp +++ b/test/test_xml.cpp @@ -233,6 +233,36 @@ char upnp_xml2[] = "" ""; +char upnp_xml3[] = +"" +"" +"" +"s:Client" +"UPnPError" +"" +"" +"402" +"Invalid Args" +"" +"" +"" +"" +""; + +char upnp_xml4[] = +"" +"" +"" +"" +"123.10.20.30" +"" +"" +""; + using namespace libtorrent; void parser_callback(std::string& out, int token, char const* s, int len @@ -304,6 +334,28 @@ TORRENT_TEST(upnp_parser2) TEST_EQUAL(xml_s.model, "Wireless-G ADSL Home Gateway"); } +TORRENT_TEST(upnp_parser3) +{ + error_code_parse_state xml_s; + xml_parse(upnp_xml3, upnp_xml3 + sizeof(upnp_xml3) + , boost::bind(&find_error_code, _1, _2, _3, boost::ref(xml_s))); + + std::cout << "error_code " << xml_s.error_code << std::endl; + TEST_EQUAL(xml_s.error_code, 402); +} + +TORRENT_TEST(upnp_parser4) +{ + ip_address_parse_state xml_s; + xml_parse(upnp_xml4, upnp_xml4 + sizeof(upnp_xml4) + , boost::bind(&find_ip_address, _1, _2, _3, boost::ref(xml_s))); + + std::cout << "error_code " << xml_s.error_code << std::endl; + std::cout << "ip_address " << xml_s.ip_address << std::endl; + TEST_EQUAL(xml_s.error_code, -1); + TEST_EQUAL(xml_s.ip_address, "123.10.20.30"); +} + TORRENT_TEST(tags) { test_parse("foobar", "BaSfooEbSbarFa"); From 8adcbdd32bb9501863030df0beda14622934134e Mon Sep 17 00:00:00 2001 From: Falcosc Date: Sun, 18 Dec 2016 21:58:14 +0100 Subject: [PATCH 11/12] add setting urlseed_max_request_bytes to handle large web seed requests #1405 (#1423) add setting urlseed_max_request_bytes to handle large web seed requests. change default for urlseed max request to 16MIB --- ChangeLog | 1 + include/libtorrent/peer_connection.hpp | 4 ++-- include/libtorrent/settings_pack.hpp | 15 +++++++++++++++ src/settings_pack.cpp | 1 + src/web_peer_connection.cpp | 16 ++++++++-------- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 93a6e8747..757c1666f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * add setting urlseed_max_request_bytes to handle large web seed requests * fix python build with CC/CXX environment * add trackers from add_torrent_params/magnet links to separate tiers * fix resumedata check issue with files with priority 0 diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index aee016017..aa6e598b8 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -365,7 +365,7 @@ namespace libtorrent int picker_options() const; void prefer_contiguous_blocks(int num) - { m_prefer_contiguous_blocks = (std::min)(num, 255); } + { m_prefer_contiguous_blocks = num; } bool request_large_blocks() const { return m_request_large_blocks; } @@ -1134,7 +1134,7 @@ namespace libtorrent // if it is 0, the download rate limit setting // will be used to determine if whole pieces // are preferred. - boost::uint8_t m_prefer_contiguous_blocks; + int m_prefer_contiguous_blocks; // this is the number of times this peer has had // a request rejected because of a disk I/O failure. diff --git a/include/libtorrent/settings_pack.hpp b/include/libtorrent/settings_pack.hpp index 11182d450..5c22ef1e7 100644 --- a/include/libtorrent/settings_pack.hpp +++ b/include/libtorrent/settings_pack.hpp @@ -767,6 +767,21 @@ namespace libtorrent // low number, like 5 urlseed_pipeline_size, + // The maximum request range of an url seed in bytes. This value + // defines the largest possible sequential web seed request. Default + // is 16 * 1024 * 1024. Lower values are possible but will be ignored + // if they are lower then piece size. + // This value should be related to your download speed to prevent + // libtorrent from creating too many expensive http requests per + // second. You can select a value as high as you want but keep in mind + // that libtorrent can't create parallel requests if the first request + // did already select the whole file. + // If you combine bittorrent seeds with web seeds and pick strategies + // like rarest first you may find your web seed requests split into + // smaller parts because we don't download already picked pieces + // twice. + urlseed_max_request_bytes, + // time to wait until a new retry of a web seed takes place urlseed_wait_retry, diff --git a/src/settings_pack.cpp b/src/settings_pack.cpp index c67ea6d68..152f4b0d9 100644 --- a/src/settings_pack.cpp +++ b/src/settings_pack.cpp @@ -229,6 +229,7 @@ namespace libtorrent SET(peer_timeout, 120, 0), SET(urlseed_timeout, 20, 0), SET(urlseed_pipeline_size, 5, 0), + SET_NOPREV(urlseed_max_request_bytes, 16 * 1024 * 1024, 0), SET(urlseed_wait_retry, 30, 0), SET(file_pool_size, 40, 0), SET(max_failcount, 3, &session_impl::update_max_failcount), diff --git a/src/web_peer_connection.cpp b/src/web_peer_connection.cpp index 39afd81d3..51aef9a65 100644 --- a/src/web_peer_connection.cpp +++ b/src/web_peer_connection.cpp @@ -86,16 +86,16 @@ web_peer_connection::web_peer_connection(peer_connection_args const& pack shared_ptr tor = pack.tor.lock(); TORRENT_ASSERT(tor); - // we always prefer downloading 1 MiB chunks - // from web seeds, or whole pieces if pieces - // are larger than a MiB - int preferred_size = 1024 * 1024; + // if the web server is known not to support keep-alive. request 4MiB + // but we want to have at least piece size to prevent block based requests + int const min_size = std::max((web.supports_keepalive ? 1 : 4) * 1024 * 1024, + tor->torrent_file().piece_length()); - // if the web server is known not to support keep-alive. - // request even larger blocks at a time - if (!web.supports_keepalive) preferred_size *= 4; + // we prefer downloading large chunks from web seeds, + // but still want to be able to split requests + int const preferred_size = std::max(min_size, m_settings.get_int(settings_pack::urlseed_max_request_bytes)); - prefer_contiguous_blocks((std::max)(preferred_size / tor->block_size(), 1)); + prefer_contiguous_blocks(preferred_size / tor->block_size()); boost::shared_ptr t = associated_torrent().lock(); bool const single_file_request = t->torrent_file().num_files() == 1; From ad7e796d05fd9d682c812e43127d7cb2071df057 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 18 Dec 2016 20:56:59 -0500 Subject: [PATCH 12/12] fix socks5 support for UDP. based on patch in https://github.com/arvidn/libtorrent/issues/1373 --- ChangeLog | 1 + simulation/fake_peer.hpp | 105 ++++++++++++++++++++++++------------- simulation/libsimulator | 2 +- simulation/test_socks5.cpp | 87 ++++++++++++++++++++++++++++++ simulation/utils.cpp | 1 + src/session_impl.cpp | 3 ++ src/udp_socket.cpp | 6 ++- 7 files changed, 166 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index 757c1666f..995f2d049 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fix socks5 support for UDP * add setting urlseed_max_request_bytes to handle large web seed requests * fix python build with CC/CXX environment * add trackers from add_torrent_params/magnet links to separate tiers diff --git a/simulation/fake_peer.hpp b/simulation/fake_peer.hpp index c113680b0..deb8d3e53 100644 --- a/simulation/fake_peer.hpp +++ b/simulation/fake_peer.hpp @@ -53,10 +53,6 @@ struct fake_peer { fake_peer(simulation& sim, char const* ip) : m_ios(sim, asio::ip::address::from_string(ip)) - , m_acceptor(m_ios) - , m_in_socket(m_ios) - , m_out_socket(m_ios) - , m_tripped(false) { boost::system::error_code ec; m_acceptor.open(asio::ip::tcp::v4(), ec); @@ -177,20 +173,20 @@ private: char m_out_buffer[300]; asio::io_service m_ios; - asio::ip::tcp::acceptor m_acceptor; - asio::ip::tcp::socket m_in_socket; - asio::ip::tcp::socket m_out_socket; - bool m_tripped; + asio::ip::tcp::acceptor m_acceptor{m_ios}; + asio::ip::tcp::socket m_in_socket{m_ios}; + asio::ip::tcp::socket m_out_socket{m_ios}; + bool m_tripped = false; std::vector m_send_buffer; }; -struct fake_node +struct udp_server { - fake_node(simulation& sim, char const* ip, int port = 6881) + udp_server(simulation& sim, char const* ip, int port + , std::function(char const*, int)> handler) : m_ios(sim, asio::ip::address::from_string(ip)) - , m_socket(m_ios) - , m_tripped(false) + , m_handler(handler) { boost::system::error_code ec; m_socket.open(asio::ip::udp::v4(), ec); @@ -198,31 +194,73 @@ struct fake_node m_socket.bind(asio::ip::udp::endpoint(asio::ip::address_v4::any(), port), ec); TEST_CHECK(!ec); - fprintf(stderr, "fake_node::async_read_some\n"); - m_socket.async_receive(boost::asio::buffer(m_in_buffer) - , [&] (boost::system::error_code const& ec, size_t bytes_transferred) - { - fprintf(stderr, "fake_node::async_read_some callback. ec: %s transferred: %d\n" - , ec.message().c_str(), int(bytes_transferred)); - if (ec) return; + m_socket.io_control(lt::udp::socket::non_blocking_io(true)); + std::printf("udp_server::async_read_some\n"); + using namespace std::placeholders; + m_socket.async_receive_from(boost::asio::buffer(m_in_buffer) + , m_from, 0, std::bind(&udp_server::on_read, this, _1, _2)); + } + + void close() { m_socket.close(); } + +private: + + void on_read(boost::system::error_code const& ec, size_t bytes_transferred) + { + std::printf("udp_server::async_read_some callback. ec: %s transferred: %d\n" + , ec.message().c_str(), int(bytes_transferred)); + if (ec) return; + + std::vector send_buffer = m_handler(m_in_buffer.data(), int(bytes_transferred)); + + if (!send_buffer.empty()) + { + lt::error_code err; + m_socket.send_to(boost::asio::buffer(send_buffer), m_from, 0, err); + if (err) + { + std::printf("send_to FAILED: %s\n", err.message().c_str()); + } + else + { + std::printf("udp_server responding with %d bytes\n" + , int(send_buffer.size())); + } + } + + std::printf("udp_server::async_read_some\n"); + using namespace std::placeholders; + m_socket.async_receive_from(boost::asio::buffer(m_in_buffer) + , m_from, 0, std::bind(&udp_server::on_read, this, _1, _2)); + } + + std::array m_in_buffer; + + asio::io_service m_ios; + asio::ip::udp::socket m_socket{m_ios}; + asio::ip::udp::endpoint m_from; + + std::function(char const*, int)> m_handler; +}; + +struct fake_node : udp_server +{ + fake_node(simulation& sim, char const* ip, int port = 6881) + : udp_server(sim, ip, port, [&](char const* incoming, int size) + { lt::bdecode_node n; boost::system::error_code err; - int const ret = bdecode(m_in_buffer.data(), m_in_buffer.data() + bytes_transferred - , n, err, nullptr, 10, 200); + int const ret = bdecode(incoming, incoming + size, n, err, nullptr, 10, 200); TEST_EQUAL(ret, 0); - m_incoming_packets.emplace_back(m_in_buffer.data(), m_in_buffer.data() + bytes_transferred); + m_incoming_packets.emplace_back(incoming, incoming + size); // TODO: ideally we would validate the DHT message m_tripped = true; - }); - } - - void close() - { - m_socket.close(); - } + return std::vector(); + }) + {} bool tripped() const { return m_tripped; } @@ -231,15 +269,8 @@ struct fake_node private: - std::array m_in_buffer; - std::vector> m_incoming_packets; - - asio::io_service m_ios; - asio::ip::udp::socket m_socket; - bool m_tripped; - - std::vector m_send_buffer; + bool m_tripped = false; }; inline void add_fake_peers(lt::torrent_handle h) diff --git a/simulation/libsimulator b/simulation/libsimulator index e45086495..36b46fc2c 160000 --- a/simulation/libsimulator +++ b/simulation/libsimulator @@ -1 +1 @@ -Subproject commit e450864958668f8c2ecf8b9839fa278c9c797571 +Subproject commit 36b46fc2c316d34714315c04c87cf74de6efae90 diff --git a/simulation/test_socks5.cpp b/simulation/test_socks5.cpp index f4940ec4a..ae19e56a1 100644 --- a/simulation/test_socks5.cpp +++ b/simulation/test_socks5.cpp @@ -303,3 +303,90 @@ TORRENT_TEST(socks5_tcp_announce) TEST_CHECK(tracker_port != -1); } +TORRENT_TEST(udp_tracker) +{ + using namespace libtorrent; + bool tracker_alert = false; + bool connected = false; + bool announced = false; + run_test( + [](lt::session& ses) + { + set_proxy(ses, settings_pack::socks5); + + // The socks server in libsimulator does not support forwarding UDP + // packets to hostnames (just IPv4 destinations) + settings_pack p; + p.set_bool(settings_pack::proxy_hostnames, false); + ses.apply_settings(p); + + lt::add_torrent_params params; + params.info_hash = sha1_hash("abababababababababab"); + params.trackers.push_back("udp://2.2.2.2:8080/announce"); + params.save_path = "."; + ses.async_add_torrent(params); + }, + [&tracker_alert](lt::session& ses, lt::alert const* alert) { + if (lt::alert_cast(alert)) + tracker_alert = true; + }, + [&](sim::simulation& sim, lt::session& ses + , boost::shared_ptr ti) + { + // listen on port 8080 + udp_server tracker(sim, "2.2.2.2", 8080, + [&](char const* msg, int size) + { + using namespace libtorrent::detail; + std::vector ret; + TEST_CHECK(size >= 16); + + if (size < 16) return ret; + + std::uint64_t connection_id = read_uint64(msg); + std::uint32_t action = read_uint32(msg); + std::uint32_t transaction_id = read_uint32(msg); + + std::uint64_t const conn_id = 0xfeedface1337ull; + + if (action == 0) + { + std::printf("udp connect\n"); + // udp tracker connect + TEST_CHECK(connection_id == 0x41727101980ull); + auto inserter = std::back_inserter(ret); + write_uint32(0, inserter); // connect + write_uint32(transaction_id, inserter); + write_uint64(conn_id, inserter); + connected = true; + } + else if (action == 1) + { + std::printf("udp announce\n"); + // udp tracker announce + TEST_EQUAL(connection_id, conn_id); + + auto inserter = std::back_inserter(ret); + write_uint32(1, inserter); // announce + write_uint32(transaction_id, inserter); + write_uint32(1800, inserter); + write_uint32(0, inserter); // leechers + write_uint32(0, inserter); // seeders + announced = true; + } + else + { + std::printf("unsupported udp tracker action: %d\n", action); + } + return ret; + }); + + sim.run(); + } + ); + + TEST_CHECK(tracker_alert); + TEST_CHECK(connected); + TEST_CHECK(announced); +} + diff --git a/simulation/utils.cpp b/simulation/utils.cpp index ab1b3e432..269a5681b 100644 --- a/simulation/utils.cpp +++ b/simulation/utils.cpp @@ -112,6 +112,7 @@ void set_proxy(lt::session& ses, int proxy_type, int flags, bool proxy_peer_conn p.set_bool(settings_pack::proxy_hostnames, true); p.set_bool(settings_pack::proxy_peer_connections, proxy_peer_connections); p.set_bool(settings_pack::proxy_tracker_connections, true); + p.set_bool(settings_pack::force_proxy, true); ses.apply_settings(p); } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index d24af11e8..0fdbbc047 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -2109,6 +2109,7 @@ retry: maybe_update_udp_mapping(0, true, ssl_port, ssl_port); maybe_update_udp_mapping(1, true, ssl_port, ssl_port); } + m_ssl_udp_socket.set_proxy_settings(proxy()); } } else @@ -2170,6 +2171,8 @@ retry: maybe_update_udp_mapping(0, false, m_listen_interface.port(), m_listen_interface.port()); maybe_update_udp_mapping(1, false, m_listen_interface.port(), m_listen_interface.port()); } + + m_udp_socket.set_proxy_settings(proxy()); } // we made it! now post all the listen_succeeded_alerts diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index 646e9d2fa..73daeadf9 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -845,10 +845,14 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec) } } #endif + + error_code err; + m_bind_port = m_ipv4_sock.local_endpoint(err).port(); + if (err) m_bind_port = ep.port(); + #if TORRENT_USE_ASSERTS m_started = true; #endif - m_bind_port = ep.port(); } void udp_socket::set_proxy_settings(aux::proxy_settings const& ps)