diff --git a/ChangeLog b/ChangeLog index 0e1e1a205..c5e53c4db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ * fix uTP edge case where udp socket buffer fills up * fix nagle implementation in uTP + * udp socket refcounter fix * added missing async_add_torrent to python bindings * raised the limit for bottled http downloads to 2 MiB * add support for magnet links and URLs in python example client diff --git a/include/libtorrent/udp_socket.hpp b/include/libtorrent/udp_socket.hpp index f86ae7acf..e9118df7c 100644 --- a/include/libtorrent/udp_socket.hpp +++ b/include/libtorrent/udp_socket.hpp @@ -256,6 +256,11 @@ namespace libtorrent bool m_started; int m_magic; int m_outstanding_when_aborted; + int m_outstanding_connect; + int m_outstanding_timeout; + int m_outstanding_resolve; + int m_outstanding_connect_queue; + int m_outstanding_socks; #endif }; diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index 32afc7906..95cdd8b79 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -84,6 +84,11 @@ udp_socket::udp_socket(asio::io_service& ios m_magic = 0x1337; m_started = false; m_outstanding_when_aborted = -1; + m_outstanding_connect_queue = 0; + m_outstanding_connect = 0; + m_outstanding_timeout = 0; + m_outstanding_resolve = 0; + m_outstanding_socks = 0; #if defined BOOST_HAS_PTHREADS m_thread = 0; #endif @@ -595,8 +600,17 @@ void udp_socket::close() // we just called done, which means on_timeout // won't be called. Decrement the outstanding // ops counter for that +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_timeout > 0); + --m_outstanding_timeout; +#endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; } @@ -745,6 +759,9 @@ void udp_socket::set_proxy_settings(proxy_settings const& ps) // connect to socks5 server and open up the UDP tunnel tcp::resolver::query q(ps.hostname, to_string(ps.port).elems); ++m_outstanding_ops; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_resolve; +#endif m_resolver.async_resolve(q, boost::bind( &udp_socket::on_name_lookup, this, _1, _2)); } @@ -752,8 +769,18 @@ void udp_socket::set_proxy_settings(proxy_settings const& ps) void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i) { +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_resolve > 0); + --m_outstanding_resolve; +#endif + TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; CHECK_MAGIC; @@ -777,15 +804,35 @@ void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i) // when m_outstanding_ops may be decremented // To simplyfy this, it's probably a good idea to // merge on_connect and on_timeout to a single function - ++m_outstanding_ops; + + // on_timeout may be called before on_connected + // so increment the outstanding ops + // it may also not be called in case we call + // connection_queue::done first, so be sure to + // decrement if that happens + m_outstanding_ops += 2; + +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_timeout; + ++m_outstanding_connect_queue; +#endif m_cc.enqueue(boost::bind(&udp_socket::on_connect, this, _1) , boost::bind(&udp_socket::on_timeout, this), seconds(10)); } void udp_socket::on_timeout() { +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_timeout > 0); + --m_outstanding_timeout; +#endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; CHECK_MAGIC; TORRENT_ASSERT(is_single_thread()); @@ -798,8 +845,17 @@ void udp_socket::on_timeout() void udp_socket::on_connect(int ticket) { TORRENT_ASSERT(is_single_thread()); +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_connect_queue > 0); + --m_outstanding_connect_queue; +#endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); CHECK_MAGIC; if (m_abort) return; @@ -814,16 +870,13 @@ void udp_socket::on_connect(int ticket) add_outstanding_async("udp_socket::on_connected"); #endif m_connection_ticket = ticket; - // at this point on_timeout may be called before on_connected - // so increment the outstanding ops - // it may also not be called in case we call - // connection_queue::done first, so be sure to - // decrement if that happens - ++m_outstanding_ops; error_code ec; m_socks5_sock.open(m_proxy_addr.address().is_v4()?tcp::v4():tcp::v6(), ec); ++m_outstanding_ops; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_connect; +#endif m_socks5_sock.async_connect(tcp::endpoint(m_proxy_addr.address(), m_proxy_addr.port()) , boost::bind(&udp_socket::on_connected, this, _1)); } @@ -832,11 +885,19 @@ void udp_socket::on_connected(error_code const& e) { #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_connected"); +#endif +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_connect > 0); + --m_outstanding_connect; #endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; - CHECK_MAGIC; if (e == asio::error::operation_aborted) return; @@ -848,8 +909,17 @@ void udp_socket::on_connected(error_code const& e) // we just called done, which means on_timeout // won't be called. Decrement the outstanding // ops counter for that +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_timeout > 0); + --m_outstanding_timeout; +#endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; if (e) @@ -880,6 +950,9 @@ void udp_socket::on_connected(error_code const& e) add_outstanding_async("udp_socket::on_handshake1"); #endif ++m_outstanding_ops; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_socks; +#endif asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf) , boost::bind(&udp_socket::handshake1, this, _1)); } @@ -888,11 +961,19 @@ void udp_socket::handshake1(error_code const& e) { #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_handshake1"); +#endif +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_socks > 0); + --m_outstanding_socks; #endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; - CHECK_MAGIC; if (e) return; @@ -902,6 +983,9 @@ void udp_socket::handshake1(error_code const& e) add_outstanding_async("udp_socket::on_handshake2"); #endif ++m_outstanding_ops; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_socks; +#endif asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 2) , boost::bind(&udp_socket::handshake2, this, _1)); } @@ -910,9 +994,18 @@ void udp_socket::handshake2(error_code const& e) { #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_handshake2"); +#endif +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_socks > 0); + --m_outstanding_socks; #endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; CHECK_MAGIC; @@ -953,6 +1046,9 @@ void udp_socket::handshake2(error_code const& e) add_outstanding_async("udp_socket::on_handshake3"); #endif ++m_outstanding_ops; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_socks; +#endif asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf) , boost::bind(&udp_socket::handshake3, this, _1)); } @@ -968,11 +1064,19 @@ void udp_socket::handshake3(error_code const& e) { #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_handshake3"); +#endif +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_socks > 0); + --m_outstanding_socks; #endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; - CHECK_MAGIC; if (e) return; @@ -982,6 +1086,9 @@ void udp_socket::handshake3(error_code const& e) add_outstanding_async("udp_socket::on_handshake4"); #endif ++m_outstanding_ops; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_socks; +#endif asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 2) , boost::bind(&udp_socket::handshake4, this, _1)); } @@ -990,11 +1097,19 @@ void udp_socket::handshake4(error_code const& e) { #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_handshake4"); +#endif +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_socks > 0); + --m_outstanding_socks; #endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; - CHECK_MAGIC; if (e) return; @@ -1041,6 +1156,9 @@ void udp_socket::socks_forward_udp() add_outstanding_async("udp_socket::connect1"); #endif ++m_outstanding_ops; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_socks; +#endif asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf) , boost::bind(&udp_socket::connect1, this, _1)); } @@ -1049,11 +1167,19 @@ void udp_socket::connect1(error_code const& e) { #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::connect1"); +#endif +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_socks > 0); + --m_outstanding_socks; #endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; - CHECK_MAGIC; if (e) return; @@ -1063,6 +1189,9 @@ void udp_socket::connect1(error_code const& e) add_outstanding_async("udp_socket::connect2"); #endif ++m_outstanding_ops; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_socks; +#endif asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 10) , boost::bind(&udp_socket::connect2, this, _1)); } @@ -1071,15 +1200,24 @@ void udp_socket::connect2(error_code const& e) { #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::connect2"); +#endif +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_socks > 0); + --m_outstanding_socks; #endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); + if (m_abort) { m_queue.clear(); return; } - CHECK_MAGIC; if (e) { @@ -1140,6 +1278,9 @@ void udp_socket::connect2(error_code const& e) add_outstanding_async("udp_socket::hung_up"); #endif ++m_outstanding_ops; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + ++m_outstanding_socks; +#endif asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 10) , boost::bind(&udp_socket::hung_up, this, _1)); } @@ -1148,11 +1289,19 @@ void udp_socket::hung_up(error_code const& e) { #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::hung_up"); +#endif +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS + TORRENT_ASSERT(m_outstanding_socks > 0); + --m_outstanding_socks; #endif TORRENT_ASSERT(m_outstanding_ops > 0); --m_outstanding_ops; + TORRENT_ASSERT(m_outstanding_ops == m_outstanding_connect + + m_outstanding_timeout + + m_outstanding_resolve + + m_outstanding_connect_queue + + m_outstanding_socks); if (m_abort) return; - CHECK_MAGIC; TORRENT_ASSERT(is_single_thread());