From 56904441784ff79d2ab56ab4b89629fd2f9d6983 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 5 Feb 2011 21:19:33 +0000 Subject: [PATCH] fixed bug in udp_socket where there would be two outstanding async read operations on the socket --- include/libtorrent/udp_socket.hpp | 7 +- src/udp_socket.cpp | 135 ++++++++++++++++++++++-------- 2 files changed, 105 insertions(+), 37 deletions(-) diff --git a/include/libtorrent/udp_socket.hpp b/include/libtorrent/udp_socket.hpp index bc2a4e21a..57410f392 100644 --- a/include/libtorrent/udp_socket.hpp +++ b/include/libtorrent/udp_socket.hpp @@ -189,8 +189,11 @@ namespace libtorrent bool m_reallocate_buffer6; #endif - int m_bind_port; - char m_outstanding; + boost::uint16_t m_bind_port; + boost::uint8_t m_v4_outstanding; +#if TORRENT_USE_IPV6 + boost::uint8_t m_v6_outstanding; +#endif tcp::socket m_socks5_sock; int m_connection_ticket; diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index d1e73b098..925f28eb7 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -69,7 +69,10 @@ udp_socket::udp_socket(asio::io_service& ios , m_reallocate_buffer6(false) #endif , m_bind_port(0) - , m_outstanding(0) + , m_v4_outstanding(0) +#if TORRENT_USE_IPV6 + , m_v6_outstanding(0) +#endif , m_socks5_sock(ios) , m_connection_ticket(-1) , m_cc(cc) @@ -93,6 +96,13 @@ udp_socket::udp_socket(asio::io_service& ios m_v6_buf_size = 1600; m_v6_buf = (char*)malloc(m_v6_buf_size); #endif + +#ifdef TORRENT_DEBUG + m_v4_outstanding = 0; +#if TORRENT_USE_IPV6 + m_v6_outstanding = 0; +#endif +#endif } udp_socket::~udp_socket() @@ -100,11 +110,12 @@ udp_socket::~udp_socket() free(m_v4_buf); #if TORRENT_USE_IPV6 free(m_v6_buf); + TORRENT_ASSERT_VAL(m_v6_outstanding == 0, m_v6_outstanding); #endif -#ifdef TORRENT_DEBUG + TORRENT_ASSERT_VAL(m_v4_outstanding == 0, m_v4_outstanding); TORRENT_ASSERT(m_magic == 0x1337); TORRENT_ASSERT(!m_callback || !m_started); - TORRENT_ASSERT_VAL(m_outstanding == 0, m_outstanding); +#ifdef TORRENT_DEBUG m_magic = 0; #endif } @@ -196,20 +207,37 @@ void udp_socket::send(udp::endpoint const& ep, char const* p, int len void udp_socket::maybe_realloc_buffers(int which) { TORRENT_ASSERT(is_single_thread()); + bool no_mem = false; if (m_reallocate_buffer4 && (which & 1)) { - free(m_v4_buf); - m_v4_buf = (char*)malloc(m_v4_buf_size); + TORRENT_ASSERT(m_v4_outstanding == 0); + void* tmp = realloc(m_v4_buf, m_v4_buf_size); + if (tmp != 0) m_v4_buf = (char*)tmp; + else no_mem = true; m_reallocate_buffer4 = false; } #if TORRENT_USE_IPV6 if (m_reallocate_buffer6 && (which & 2)) { - free(m_v6_buf); - m_v6_buf = (char*)malloc(m_v6_buf_size); + TORRENT_ASSERT(m_v6_outstanding == 0); + void* tmp = realloc(m_v6_buf, m_v6_buf_size); + if (tmp != 0) m_v6_buf = (char*)tmp; + else no_mem = true; m_reallocate_buffer6 = false; } #endif + + if (no_mem) + { + free(m_v4_buf); + m_v4_buf_size = 0; +#if TORRENT_USE_IPV6 + free(m_v6_buf); + m_v6_buf_size = 0; +#endif + if (m_callback) m_callback(error::no_memory, m_v4_ep, 0, 0); + close(); + } } void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_transferred) @@ -220,12 +248,22 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_ TORRENT_ASSERT(m_magic == 0x1337); TORRENT_ASSERT(is_single_thread()); - TORRENT_ASSERT(m_outstanding > 0); - --m_outstanding; - - if (e == asio::error::operation_aborted || m_abort) +#if TORRENT_USE_IPV6 + if (s == &m_ipv6_sock) { - if (m_outstanding == 0) + TORRENT_ASSERT(m_v6_outstanding > 0); + --m_v6_outstanding; + } + else +#endif + { + TORRENT_ASSERT(m_v4_outstanding > 0); + --m_v4_outstanding; + } + + if (m_abort) + { + if (m_v4_outstanding + m_v6_outstanding == 0) { // "this" may be destructed in the callback callback_t tmp = m_callback; @@ -266,9 +304,10 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_ && e != asio::error::connection_reset && e != asio::error::connection_refused && e != asio::error::connection_aborted + && e != asio::error::connection_aborted && e != asio::error::message_size) { - if (m_outstanding == 0) + if (m_v4_outstanding + m_v6_outstanding == 0) { // "this" may be destructed in the callback callback_t tmp = m_callback; @@ -286,14 +325,21 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_ #endif #if TORRENT_USE_IPV6 if (s == &m_ipv6_sock) + { + TORRENT_ASSERT(m_v6_outstanding == 0); + ++m_v6_outstanding; s->async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size) , m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2)); + } else #endif + { + TORRENT_ASSERT(m_v4_outstanding == 0); + ++m_v4_outstanding; s->async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size) , m_v4_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2)); + } - ++m_outstanding; #ifdef TORRENT_DEBUG m_started = true; #endif @@ -329,6 +375,8 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_ #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("udp_socket::on_read"); #endif + TORRENT_ASSERT(m_v6_outstanding == 0); + ++m_v6_outstanding; s->async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size) , m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2)); } @@ -362,10 +410,11 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_ #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("udp_socket::on_read"); #endif + TORRENT_ASSERT(m_v4_outstanding == 0); + ++m_v4_outstanding; s->async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size) , m_v4_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2)); } - ++m_outstanding; #ifdef TORRENT_DEBUG m_started = true; @@ -509,7 +558,7 @@ void udp_socket::close() m_connection_ticket = -1; } - if (m_outstanding == 0) + if (m_v4_outstanding + m_v6_outstanding == 0) { // "this" may be destructed in the callback callback_t tmp = m_callback; @@ -552,12 +601,16 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec) if (ec) return; m_ipv4_sock.bind(ep, ec); if (ec) return; + if (m_v4_outstanding == 0) + { #if defined TORRENT_ASIO_DEBUGGING - add_outstanding_async("udp_socket::on_read"); + add_outstanding_async("udp_socket::on_read"); #endif - m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size) - , m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2)); - ++m_outstanding; + ++m_v4_outstanding; + m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size) + , m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock + , _1, _2)); + } } #if TORRENT_USE_IPV6 else @@ -566,12 +619,17 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec) if (ec) return; m_ipv6_sock.bind(ep, ec); if (ec) return; + if (m_v6_outstanding == 0) + { #if defined TORRENT_ASIO_DEBUGGING - add_outstanding_async("udp_socket::on_read"); + add_outstanding_async("udp_socket::on_read"); #endif - m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size) - , m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2)); - ++m_outstanding; + TORRENT_ASSERT(m_v6_outstanding == 0); + ++m_v6_outstanding; + m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size) + , m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock + , _1, _2)); + } } #endif #ifdef TORRENT_DEBUG @@ -604,12 +662,13 @@ void udp_socket::bind(int port) add_outstanding_async("udp_socket::on_read"); #endif m_ipv4_sock.bind(udp::endpoint(address_v4::any(), port), ec); - m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size) - , m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2)); - ++m_outstanding; -#ifdef TORRENT_DEBUG - m_started = true; -#endif + if (m_v4_outstanding == 0) + { + ++m_v4_outstanding; + m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size) + , m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock + , _1, _2)); + } } #if TORRENT_USE_IPV6 m_ipv6_sock.open(udp::v6(), ec); @@ -620,13 +679,19 @@ void udp_socket::bind(int port) #endif m_ipv6_sock.set_option(v6only(true), ec); m_ipv6_sock.bind(udp::endpoint(address_v6::any(), port), ec); - m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size) - , m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2)); - ++m_outstanding; + + if (m_v6_outstanding == 0) + { + ++m_v6_outstanding; + m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size) + , m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock + , _1, _2)); + } + } +#endif // TORRENT_USE_IPV6 + #ifdef TORRENT_DEBUG m_started = true; -#endif - } #endif m_bind_port = port; }