From e5720eafd8432457ed9137b5af04dd330df87b50 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 9 Apr 2011 17:59:00 +0000 Subject: [PATCH] fix crash in udp_socket when using SOCKS5 proxy --- ChangeLog | 1 + include/libtorrent/udp_socket.hpp | 8 ++ src/udp_socket.cpp | 135 +++++++++++++++++++++++++----- 3 files changed, 122 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 14e2d825f..7a475d663 100644 --- a/ChangeLog +++ b/ChangeLog @@ -85,6 +85,7 @@ incoming connection * added more detailed instrumentation of the disk I/O thread + * fixed crash in udp trackers when using SOCKS5 proxy * fixed reconnect delay when leaving upload only mode * fixed default values being set incorrectly in add_torrent_params through add_magnet_uri in python bindings * implemented unaligned write (for unbuffered I/O) diff --git a/include/libtorrent/udp_socket.hpp b/include/libtorrent/udp_socket.hpp index fd07b7c9e..6fa272eb6 100644 --- a/include/libtorrent/udp_socket.hpp +++ b/include/libtorrent/udp_socket.hpp @@ -119,6 +119,8 @@ namespace libtorrent int flags; }; + // number of outstanding UDP socket operations + // using the UDP socket buffer int num_outstanding() const { return m_v4_outstanding @@ -160,6 +162,7 @@ namespace libtorrent void unwrap(error_code const& e, char const* buf, int size); void maybe_realloc_buffers(int which = 3); + bool maybe_clear_callback(); #ifdef TORRENT_DEBUG #if defined BOOST_HAS_PTHREADS @@ -218,6 +221,11 @@ namespace libtorrent // we have to queue the packets, we'll flush // them once we're connected std::deque m_queue; + + // counts the number of outstanding async + // operations hanging on this socket + int m_outstanding_ops; + #ifdef TORRENT_DEBUG bool m_started; int m_magic; diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index 68605081c..95fd904fa 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -80,6 +80,7 @@ udp_socket::udp_socket(asio::io_service& ios , m_queue_packets(false) , m_tunnel_packets(false) , m_abort(false) + , m_outstanding_ops(0) { #ifdef TORRENT_DEBUG m_magic = 0x1337; @@ -111,6 +112,7 @@ udp_socket::~udp_socket() #ifdef TORRENT_DEBUG m_magic = 0; #endif + TORRENT_ASSERT(m_outstanding_ops == 0); } #ifdef TORRENT_DEBUG @@ -155,6 +157,21 @@ void udp_socket::send_hostname(char const* hostname, int port qp.flags = 0; } +bool udp_socket::maybe_clear_callback() +{ + if (m_outstanding_ops + m_v4_outstanding +#if TORRENT_USE_IPV6 + + m_v6_outstanding +#endif + == 0) + { + // "this" may be destructed in the callback + m_callback.clear(); + return true; + } + return false; +} + void udp_socket::send(udp::endpoint const& ep, char const* p, int len , error_code& ec, int flags) { @@ -259,12 +276,7 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_ if (m_abort) { - if (num_outstanding() == 0) - { - // "this" may be destructed in the callback - callback_t tmp = m_callback; - m_callback.clear(); - } + maybe_clear_callback(); return; } @@ -293,12 +305,7 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_ && e != asio::error::operation_aborted && e != asio::error::message_size) { - if (num_outstanding() == 0) - { - // "this" may be destructed in the callback - callback_t tmp = m_callback; - m_callback.clear(); - } + maybe_clear_callback(); return; } @@ -547,12 +554,7 @@ void udp_socket::close() m_connection_ticket = -1; } - if (num_outstanding() == 0) - { - // "this" may be destructed in the callback - callback_t tmp = m_callback; - m_callback.clear(); - } + maybe_clear_callback(); } void udp_socket::set_buf_size(int s) @@ -706,6 +708,7 @@ void udp_socket::set_proxy_settings(proxy_settings const& ps) m_queue_packets = true; // connect to socks5 server and open up the UDP tunnel tcp::resolver::query q(ps.hostname, to_string(ps.port).elems); + ++m_outstanding_ops; m_resolver.async_resolve(q, boost::bind( &udp_socket::on_name_lookup, this, _1, _2)); } @@ -713,9 +716,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 (e == asio::error::operation_aborted) return; + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + + if (m_abort) + { + maybe_clear_callback(); + return; + } CHECK_MAGIC; + if (e == asio::error::operation_aborted) return; + TORRENT_ASSERT(is_single_thread()); if (e) @@ -729,6 +741,7 @@ void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i) m_proxy_addr.address(i->endpoint().address()); m_proxy_addr.port(i->endpoint().port()); // on_connect may be called from within this thread + ++m_outstanding_ops; m_cc.enqueue(boost::bind(&udp_socket::on_connect, this, _1) , boost::bind(&udp_socket::on_timeout, this), seconds(10)); } @@ -745,8 +758,15 @@ void udp_socket::on_timeout() void udp_socket::on_connect(int ticket) { - CHECK_MAGIC; TORRENT_ASSERT(is_single_thread()); + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + if (m_abort) + { + maybe_clear_callback(); + return; + } + CHECK_MAGIC; if (m_abort) return; if (is_closed()) return; @@ -757,6 +777,7 @@ void udp_socket::on_connect(int ticket) m_connection_ticket = ticket; error_code ec; m_socks5_sock.open(m_proxy_addr.address().is_v4()?tcp::v4():tcp::v6(), ec); + ++m_outstanding_ops; m_socks5_sock.async_connect(tcp::endpoint(m_proxy_addr.address(), m_proxy_addr.port()) , boost::bind(&udp_socket::on_connected, this, _1)); } @@ -766,11 +787,18 @@ void udp_socket::on_connected(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_connected"); #endif - - if (e == asio::error::operation_aborted) return; + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + if (m_abort) + { + maybe_clear_callback(); + return; + } CHECK_MAGIC; + if (e == asio::error::operation_aborted) return; + TORRENT_ASSERT(is_single_thread()); m_cc.done(m_connection_ticket); m_connection_ticket = -1; @@ -803,6 +831,7 @@ void udp_socket::on_connected(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("udp_socket::on_handshake1"); #endif + ++m_outstanding_ops; asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf) , boost::bind(&udp_socket::handshake1, this, _1)); } @@ -812,6 +841,14 @@ void udp_socket::handshake1(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_handshake1"); #endif + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + if (m_abort) + { + maybe_clear_callback(); + return; + } + CHECK_MAGIC; if (e) return; @@ -820,6 +857,7 @@ void udp_socket::handshake1(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("udp_socket::on_handshake2"); #endif + ++m_outstanding_ops; asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 2) , boost::bind(&udp_socket::handshake2, this, _1)); } @@ -829,7 +867,15 @@ void udp_socket::handshake2(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_handshake2"); #endif + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + if (m_abort) + { + maybe_clear_callback(); + return; + } CHECK_MAGIC; + if (e) return; using namespace libtorrent::detail; @@ -866,6 +912,7 @@ void udp_socket::handshake2(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("udp_socket::on_handshake3"); #endif + ++m_outstanding_ops; asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf) , boost::bind(&udp_socket::handshake3, this, _1)); } @@ -882,6 +929,14 @@ void udp_socket::handshake3(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_handshake3"); #endif + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + if (m_abort) + { + maybe_clear_callback(); + return; + } + CHECK_MAGIC; if (e) return; @@ -890,6 +945,7 @@ void udp_socket::handshake3(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("udp_socket::on_handshake4"); #endif + ++m_outstanding_ops; asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 2) , boost::bind(&udp_socket::handshake4, this, _1)); } @@ -899,6 +955,14 @@ void udp_socket::handshake4(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::on_handshake4"); #endif + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + if (m_abort) + { + maybe_clear_callback(); + return; + } + CHECK_MAGIC; if (e) return; @@ -944,6 +1008,7 @@ void udp_socket::socks_forward_udp() #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("udp_socket::connect1"); #endif + ++m_outstanding_ops; asio::async_write(m_socks5_sock, asio::buffer(m_tmp_buf, p - m_tmp_buf) , boost::bind(&udp_socket::connect1, this, _1)); } @@ -953,6 +1018,14 @@ void udp_socket::connect1(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::connect1"); #endif + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + if (m_abort) + { + maybe_clear_callback(); + return; + } + CHECK_MAGIC; if (e) return; @@ -961,6 +1034,7 @@ void udp_socket::connect1(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("udp_socket::connect2"); #endif + ++m_outstanding_ops; asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 10) , boost::bind(&udp_socket::connect2, this, _1)); } @@ -970,6 +1044,14 @@ void udp_socket::connect2(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::connect2"); #endif + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + if (m_abort) + { + maybe_clear_callback(); + return; + } + CHECK_MAGIC; if (e) return; @@ -1020,6 +1102,7 @@ void udp_socket::connect2(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("udp_socket::hung_up"); #endif + ++m_outstanding_ops; asio::async_read(m_socks5_sock, asio::buffer(m_tmp_buf, 10) , boost::bind(&udp_socket::hung_up, this, _1)); } @@ -1029,6 +1112,14 @@ void udp_socket::hung_up(error_code const& e) #if defined TORRENT_ASIO_DEBUGGING complete_async("udp_socket::hung_up"); #endif + TORRENT_ASSERT(m_outstanding_ops > 0); + --m_outstanding_ops; + if (m_abort) + { + maybe_clear_callback(); + return; + } + CHECK_MAGIC; TORRENT_ASSERT(is_single_thread());