From b6083fbc28fffe75c34a51422cea45b2b5a1b013 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 31 Aug 2013 20:19:03 +0000 Subject: [PATCH] first steps towards supporting SSL over uTP. moved the TODO comment and made it describe the next step. Optimized session destruction in unit tests, hopefully shaving off a bit of test run-time (and now supports asio-debugging of unit tests) --- include/libtorrent/utp_stream.hpp | 35 +++++++++++++++++++++++++++++-- src/session_impl.cpp | 6 +++++- src/torrent.cpp | 3 --- test/main.cpp | 12 +++++++---- test/test_metadata_extension.cpp | 12 +++++++++++ test/test_pe_crypto.cpp | 10 +++++++++ test/test_pex.cpp | 12 +++++++++++ test/test_ssl.cpp | 22 ++++++++++++++++--- test/test_swarm.cpp | 13 ++++++++++++ test/test_transfer.cpp | 21 +++++++++++++++++++ 10 files changed, 133 insertions(+), 13 deletions(-) diff --git a/include/libtorrent/utp_stream.hpp b/include/libtorrent/utp_stream.hpp index 923800b94..0869a08ac 100644 --- a/include/libtorrent/utp_stream.hpp +++ b/include/libtorrent/utp_stream.hpp @@ -271,6 +271,12 @@ public: do_connect(endpoint, &utp_stream::on_connect); } + template + void async_read_some(boost::asio::null_buffers const& buffers, Handler const& handler) + { + TORRENT_ASSERT(false); + } + template void async_read_some(Mutable_Buffers const& buffers, Handler const& handler) { @@ -286,14 +292,24 @@ public: m_io_service.post(boost::bind(handler, asio::error::operation_not_supported, 0)); return; } + int bytes_added = 0; for (typename Mutable_Buffers::const_iterator i = buffers.begin() , end(buffers.end()); i != end; ++i) { - TORRENT_ASSERT(buffer_size(*i) > 0); + if (buffer_size(*i) == 0) continue; using asio::buffer_cast; using asio::buffer_size; add_read_buffer(buffer_cast(*i), buffer_size(*i)); + bytes_added += buffer_size(*i); } + if (bytes_added == 0) + { + // if we're reading 0 bytes, post handler immediately + // asio's SSL layer depends on this behavior + m_io_service.post(boost::bind(handler, error_code(), 0)); + return; + } + m_read_handler = handler; set_read_handler(&utp_stream::on_read); } @@ -374,6 +390,12 @@ public: } #endif + template + void async_write_some(boost::asio::null_buffers const& buffers, Handler const& handler) + { + TORRENT_ASSERT(false); + } + template void async_write_some(Const_Buffers const& buffers, Handler const& handler) { @@ -390,13 +412,22 @@ public: return; } + int bytes_added = 0; for (typename Const_Buffers::const_iterator i = buffers.begin() , end(buffers.end()); i != end; ++i) { - TORRENT_ASSERT(buffer_size(*i) > 0); + if (buffer_size(*i) == 0) continue; using asio::buffer_cast; using asio::buffer_size; add_write_buffer((void*)buffer_cast(*i), buffer_size(*i)); + bytes_added += buffer_size(*i); + } + if (bytes_added == 0) + { + // if we're reading 0 bytes, post handler immediately + // asio's SSL layer depends on this behavior + m_io_service.post(boost::bind(handler, error_code(), 0)); + return; } m_write_handler = handler; set_write_handler(&utp_stream::on_write); diff --git a/src/session_impl.cpp b/src/session_impl.cpp index c61d3b696..ad3729d7e 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -659,6 +659,11 @@ namespace aux { #endif , m_external_udp_port(0) , m_udp_socket(m_io_service, m_half_open) + // TODO: 4 in order to support SSL over uTP, the utp_socket manager either + // needs to be able to receive packets on multiple ports, or we need to + // peek into the first few bytes the payload stream of a socket to determine + // whether or not it's an SSL connection. (The former is simpler but won't + // do as well with NATs) , m_utp_socket_manager(m_settings, m_udp_socket , boost::bind(&session_impl::incoming_connection, this, _1)) , m_boost_connections(0) @@ -2623,7 +2628,6 @@ retry: str = c->get(); } - #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("session_impl::on_accept_connection"); #endif diff --git a/src/torrent.cpp b/src/torrent.cpp index 6e0ee019a..0e3f3e07c 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -5797,9 +5797,6 @@ namespace libtorrent userdata = m_ssl_ctx.get(); // SSL handshakes are slow timeout_extend = 10; - - // TODO: 3 support SSL over uTP - sm = 0; } #endif diff --git a/test/main.cpp b/test/main.cpp index 1208c79a8..aba387178 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -159,10 +159,14 @@ int main() fflush(stdout); fflush(stderr); - remove_all(test_dir, ec); - if (ec) - fprintf(stderr, "failed to remove test dir: %s\n", ec.message().c_str()); + int ret = print_failures(); + if (ret == 0) + { + remove_all(test_dir, ec); + if (ec) + fprintf(stderr, "failed to remove test dir: %s\n", ec.message().c_str()); + } - return print_failures(); + return ret; } diff --git a/test/test_metadata_extension.cpp b/test/test_metadata_extension.cpp index f67bd5f0e..771e72c82 100644 --- a/test/test_metadata_extension.cpp +++ b/test/test_metadata_extension.cpp @@ -48,6 +48,13 @@ void test_transfer(bool clear_files, bool disconnect { using namespace libtorrent; + // these are declared before the session objects + // so that they are destructed last. This enables + // the sessions to destruct in parallel + session_proxy p1; + session_proxy p2; + session_proxy p3; + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48100, 49000), "0.0.0.0", 0); session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49100, 50000), "0.0.0.0", 0); session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50100, 51000), "0.0.0.0", 0); @@ -102,6 +109,11 @@ void test_transfer(bool clear_files, bool disconnect TEST_CHECK(tor2.status().is_seeding); if (tor2.status().is_seeding) std::cerr << "done\n"; + // this allows shutting down the sessions in parallel + p1 = ses1.abort(); + p2 = ses2.abort(); + p3 = ses3.abort(); + error_code ec; remove_all("tmp1_meta", ec); remove_all("tmp2_meta", ec); diff --git a/test/test_pe_crypto.cpp b/test/test_pe_crypto.cpp index a9531256c..0ba1da56a 100644 --- a/test/test_pe_crypto.cpp +++ b/test/test_pe_crypto.cpp @@ -72,6 +72,12 @@ void test_transfer(libtorrent::pe_settings::enc_policy policy, { using namespace libtorrent; + // these are declared before the session objects + // so that they are destructed last. This enables + // the sessions to destruct in parallel + session_proxy p1; + session_proxy p2; + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48800, 49000), "0.0.0.0", 0); session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49800, 50000), "0.0.0.0", 0); pe_settings s; @@ -119,6 +125,10 @@ void test_transfer(libtorrent::pe_settings::enc_policy policy, ses1.remove_torrent(tor1); ses2.remove_torrent(tor2); + // this allows shutting down the sessions in parallel + p1 = ses1.abort(); + p2 = ses2.abort(); + error_code ec; remove_all("tmp1_pe", ec); remove_all("tmp2_pe", ec); diff --git a/test/test_pex.cpp b/test/test_pex.cpp index 37bae419d..b3bdc9706 100644 --- a/test/test_pex.cpp +++ b/test/test_pex.cpp @@ -45,6 +45,13 @@ void test_pex() { using namespace libtorrent; + // these are declared before the session objects + // so that they are destructed last. This enables + // the sessions to destruct in parallel + session_proxy p1; + session_proxy p2; + session_proxy p3; + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48200, 49000), "0.0.0.0", 0); session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49200, 50000), "0.0.0.0", 0); session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50200, 51000), "0.0.0.0", 0); @@ -135,6 +142,11 @@ void test_pex() TEST_CHECK(st1.num_peers == 2 && st2.num_peers == 2 && st3.num_peers == 2) if (!tor2.status().is_seeding && tor3.status().is_seeding) std::cerr << "done\n"; + + // this allows shutting down the sessions in parallel + p1 = ses1.abort(); + p2 = ses2.abort(); + p3 = ses3.abort(); } int test_main() diff --git a/test/test_ssl.cpp b/test/test_ssl.cpp index 75f590040..b9da5769a 100644 --- a/test/test_ssl.cpp +++ b/test/test_ssl.cpp @@ -101,11 +101,17 @@ bool on_alert(alert* a) return false; } -void test_ssl(int test_idx) +void test_ssl(int test_idx, bool use_utp) { + // these are declared before the session objects + // so that they are destructed last. This enables + // the sessions to destruct in parallel + session_proxy p1; + session_proxy p2; + test_config_t const& test = test_config[test_idx]; - fprintf(stderr, "\n%s TEST: %s\n\n", time_now_string(), test.name); + fprintf(stderr, "\n%s TEST: %s Protocol: %s\n\n", time_now_string(), test.name, use_utp ? "uTP": "TCP"); #ifndef TORRENT_USE_OPENSSL if (test.use_ssl_ports) @@ -128,6 +134,11 @@ void test_ssl(int test_idx) session_settings sett; + sett.enable_incoming_utp = use_utp; + sett.enable_outgoing_utp = use_utp; + sett.enable_incoming_tcp = !use_utp; + sett.enable_outgoing_tcp = !use_utp; + sett.ssl_listen = 1024 + rand() % 50000; ses1.set_settings(sett); @@ -227,14 +238,19 @@ void test_ssl(int test_idx) fprintf(stderr, "%s: EXPECT: %s\n", time_now_string(), test.expected_to_complete ? "SUCCEESS" : "FAILURE"); fprintf(stderr, "%s: RESULT: %s\n", time_now_string(), tor2.status().is_seeding ? "SUCCEESS" : "FAILURE"); TEST_CHECK(tor2.status().is_seeding == test.expected_to_complete); + + // this allows shutting down the sessions in parallel + p1 = ses1.abort(); + p2 = ses2.abort(); } int test_main() { using namespace libtorrent; + // No support for SSL/uTP yet, so always pass in false for (int i = 0; i < sizeof(test_config)/sizeof(test_config[0]); ++i) - test_ssl(i); + test_ssl(i, false); error_code ec; remove_all("tmp1_ssl", ec); diff --git a/test/test_swarm.cpp b/test/test_swarm.cpp index 7e80a8395..ae9bdda59 100644 --- a/test/test_swarm.cpp +++ b/test/test_swarm.cpp @@ -52,6 +52,13 @@ void test_swarm(bool super_seeding = false, bool strict = false, bool seed_mode remove_all("tmp2_swarm", ec); remove_all("tmp3_swarm", ec); + // these are declared before the session objects + // so that they are destructed last. This enables + // the sessions to destruct in parallel + session_proxy p1; + session_proxy p2; + session_proxy p3; + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48000, 49000), "0.0.0.0", 0); session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000), "0.0.0.0", 0); session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50000, 51000), "0.0.0.0", 0); @@ -182,6 +189,12 @@ void test_swarm(bool super_seeding = false, bool strict = false, bool seed_mode std::cerr << ret->message() << std::endl; start = time_now(); } + + // this allows shutting down the sessions in parallel + p1 = ses1.abort(); + p2 = ses2.abort(); + p3 = ses3.abort(); + TEST_CHECK(time_now_hires() - start < seconds(3)); TEST_CHECK(time_now_hires() - start >= seconds(2)); diff --git a/test/test_transfer.cpp b/test/test_transfer.cpp index 442a05c56..bd74cc3d4 100644 --- a/test/test_transfer.cpp +++ b/test/test_transfer.cpp @@ -79,6 +79,12 @@ void test_rate() remove_all("tmp1_transfer_moved", ec); remove_all("tmp2_transfer_moved", ec); + // these are declared before the session objects + // so that they are destructed last. This enables + // the sessions to destruct in parallel + session_proxy p1; + session_proxy p2; + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48575, 49000), "0.0.0.0", 0, alert_mask); session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49575, 50000), "0.0.0.0", 0, alert_mask); @@ -125,6 +131,10 @@ void test_rate() std::cerr << "average download rate: " << (t->total_size() / (std::max)(total_milliseconds(dt), 1)) << " kB/s" << std::endl; + + // this allows shutting down the sessions in parallel + p1 = ses1.abort(); + p2 = ses2.abort(); } void print_alert(std::auto_ptr) @@ -249,6 +259,12 @@ void test_transfer(int proxy_type, bool test_disk_full = false, bool test_allowe remove_all("tmp1_transfer_moved", ec); remove_all("tmp2_transfer_moved", ec); + // these are declared before the session objects + // so that they are destructed last. This enables + // the sessions to destruct in parallel + session_proxy p1; + session_proxy p2; + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48075, 49000), "0.0.0.0", 0, alert_mask); session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49075, 50000), "0.0.0.0", 0, alert_mask); @@ -589,12 +605,17 @@ void test_transfer(int proxy_type, bool test_disk_full = false, bool test_allowe TEST_CHECK(tor2.status().is_seeding); + // this allows shutting down the sessions in parallel + p1 = ses1.abort(); + p2 = ses2.abort(); + if (test_priorities) { stop_tracker(); stop_web_server(); } if (proxy_type) stop_proxy(ps.port); + } int test_main()