fixed bug in udp_socket when the sockets own lifetime was dependent on the callback

This commit is contained in:
Arvid Norberg 2008-09-22 23:43:21 +00:00
parent 67bed1407f
commit ba8163ca9c
2 changed files with 80 additions and 14 deletions

View File

@ -64,6 +64,10 @@ namespace libtorrent
void set_proxy_settings(proxy_settings const& ps); void set_proxy_settings(proxy_settings const& ps);
proxy_settings const& get_proxy_settings() { return m_proxy_settings; } proxy_settings const& get_proxy_settings() { return m_proxy_settings; }
#ifndef NDEBUG
~udp_socket() { m_magic = 0; }
#endif
private: private:
callback_t m_callback; callback_t m_callback;
@ -94,6 +98,7 @@ namespace libtorrent
char m_v4_buf[1600]; char m_v4_buf[1600];
char m_v6_buf[1600]; char m_v6_buf[1600];
int m_bind_port; int m_bind_port;
uint8_t m_outstanding;
tcp::socket m_socks5_sock; tcp::socket m_socks5_sock;
int m_connection_ticket; int m_connection_ticket;
@ -103,6 +108,9 @@ namespace libtorrent
char m_tmp_buf[100]; char m_tmp_buf[100];
bool m_tunnel_packets; bool m_tunnel_packets;
udp::endpoint m_proxy_addr; udp::endpoint m_proxy_addr;
#ifndef NDEBUG
int m_magic;
#endif
}; };
} }

View File

@ -18,20 +18,33 @@ udp_socket::udp_socket(asio::io_service& ios, udp_socket::callback_t const& c
, m_ipv4_sock(ios) , m_ipv4_sock(ios)
, m_ipv6_sock(ios) , m_ipv6_sock(ios)
, m_bind_port(0) , m_bind_port(0)
, m_outstanding(0)
, m_socks5_sock(ios) , m_socks5_sock(ios)
, m_connection_ticket(-1) , m_connection_ticket(-1)
, m_cc(cc) , m_cc(cc)
, m_resolver(ios) , m_resolver(ios)
, m_tunnel_packets(false) , m_tunnel_packets(false)
{ {
#ifndef NDEBUG
m_magic = 0x1337;
#endif
} }
#ifndef NDEBUG
#define CHECK_MAGIC check_magic_ cm_(m_magic)
struct check_magic_
{
check_magic_(int& m_): m(m_) { TORRENT_ASSERT(m == 0x1337); }
~check_magic_() { TORRENT_ASSERT(m == 0x1337); }
int& m;
};
#else
#define CHECK_MAGIC (void)
#endif
void udp_socket::send(udp::endpoint const& ep, char const* p, int len, error_code& ec) void udp_socket::send(udp::endpoint const& ep, char const* p, int len, error_code& ec)
{ {
if (ec == asio::error::operation_aborted) return; CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex);
if (m_tunnel_packets) if (m_tunnel_packets)
{ {
// send udp packets through SOCKS5 server // send udp packets through SOCKS5 server
@ -47,10 +60,26 @@ void udp_socket::send(udp::endpoint const& ep, char const* p, int len, error_cod
void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_transferred) void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_transferred)
{ {
if (e == asio::error::operation_aborted) return; TORRENT_ASSERT(m_magic == 0x1337);
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
TORRENT_ASSERT(m_outstanding > 0);
--m_outstanding;
if (e == asio::error::operation_aborted)
{
if (m_outstanding == 0)
{
// "this" may be destructed in the callback
// that's why we need to unlock
l.unlock();
callback_t tmp = m_callback;
m_callback.clear();
}
return;
}
CHECK_MAGIC;
if (!m_callback) return; if (!m_callback) return;
if (e) if (e)
@ -59,9 +88,9 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_
try { try {
#endif #endif
if (s == &m_ipv4_sock) if (s == &m_ipv4_sock)
get_io_service().post(boost::bind(m_callback, e, m_v4_ep, (char*)0, 0)); m_callback(e, m_v4_ep, 0, 0);
else else
get_io_service().post(boost::bind(m_callback, e, m_v6_ep, (char*)0, 0)); m_callback(e, m_v6_ep, 0, 0);
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} catch(std::exception&) {} } catch(std::exception&) {}
#endif #endif
@ -94,7 +123,7 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_
if (m_tunnel_packets && m_v4_ep == m_proxy_addr) if (m_tunnel_packets && m_v4_ep == m_proxy_addr)
unwrap(e, m_v4_buf, bytes_transferred); unwrap(e, m_v4_buf, bytes_transferred);
else else
get_io_service().post(boost::bind(m_callback, e, m_v4_ep, m_v4_buf, bytes_transferred)); m_callback(e, m_v4_ep, m_v4_buf, bytes_transferred);
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} catch(std::exception&) {} } catch(std::exception&) {}
@ -111,7 +140,7 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_
if (m_tunnel_packets && m_v6_ep == m_proxy_addr) if (m_tunnel_packets && m_v6_ep == m_proxy_addr)
unwrap(e, m_v6_buf, bytes_transferred); unwrap(e, m_v6_buf, bytes_transferred);
else else
get_io_service().post(boost::bind(m_callback, e, m_v6_ep, m_v6_buf, bytes_transferred)); m_callback(e, m_v6_ep, m_v6_buf, bytes_transferred);
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} catch(std::exception&) {} } catch(std::exception&) {}
@ -119,10 +148,12 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_
s->async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf)) s->async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
, m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2)); , m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
} }
++m_outstanding;
} }
void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len, error_code& ec) void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len, error_code& ec)
{ {
CHECK_MAGIC;
using namespace libtorrent::detail; using namespace libtorrent::detail;
char header[20]; char header[20];
@ -147,6 +178,7 @@ void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len, error_cod
// unwrap the UDP packet from the SOCKS5 header // unwrap the UDP packet from the SOCKS5 header
void udp_socket::unwrap(error_code const& e, char const* buf, int size) void udp_socket::unwrap(error_code const& e, char const* buf, int size)
{ {
CHECK_MAGIC;
using namespace libtorrent::detail; using namespace libtorrent::detail;
// the minimum socks5 header size // the minimum socks5 header size
@ -177,27 +209,37 @@ void udp_socket::unwrap(error_code const& e, char const* buf, int size)
return; return;
} }
get_io_service().post(boost::bind(m_callback, e, sender, p, size - (p - buf))); m_callback(e, sender, p, size - (p - buf));
} }
void udp_socket::close() void udp_socket::close()
{ {
TORRENT_ASSERT(m_magic == 0x1337);
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
error_code ec; error_code ec;
m_ipv4_sock.close(ec); m_ipv4_sock.close(ec);
m_ipv6_sock.close(ec); m_ipv6_sock.close(ec);
m_socks5_sock.close(ec); m_socks5_sock.close(ec);
m_callback.clear();
if (m_connection_ticket >= 0) if (m_connection_ticket >= 0)
{ {
m_cc.done(m_connection_ticket); m_cc.done(m_connection_ticket);
m_connection_ticket = -1; m_connection_ticket = -1;
} }
if (m_outstanding == 0)
{
// "this" may be destructed in the callback
// that's why we need to unlock
l.unlock();
callback_t tmp = m_callback;
m_callback.clear();
}
} }
void udp_socket::bind(udp::endpoint const& ep, error_code& ec) void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
{ {
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
if (m_ipv4_sock.is_open()) m_ipv4_sock.close(ec); if (m_ipv4_sock.is_open()) m_ipv4_sock.close(ec);
@ -221,11 +263,13 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf)) m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
, m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2)); , m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2));
} }
++m_outstanding;
m_bind_port = ep.port(); m_bind_port = ep.port();
} }
void udp_socket::bind(int port) void udp_socket::bind(int port)
{ {
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
error_code ec; error_code ec;
@ -239,6 +283,7 @@ void udp_socket::bind(int port)
m_ipv4_sock.bind(udp::endpoint(address_v4::any(), port), ec); m_ipv4_sock.bind(udp::endpoint(address_v4::any(), port), ec);
m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf)) m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf))
, m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2)); , m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2));
++m_outstanding;
} }
m_ipv6_sock.open(udp::v6(), ec); m_ipv6_sock.open(udp::v6(), ec);
if (!ec) if (!ec)
@ -247,12 +292,14 @@ void udp_socket::bind(int port)
m_ipv6_sock.bind(udp::endpoint(address_v6::any(), port), ec); m_ipv6_sock.bind(udp::endpoint(address_v6::any(), port), ec);
m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf)) m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
, m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2)); , m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2));
++m_outstanding;
} }
m_bind_port = port; m_bind_port = port;
} }
void udp_socket::set_proxy_settings(proxy_settings const& ps) void udp_socket::set_proxy_settings(proxy_settings const& ps)
{ {
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
error_code ec; error_code ec;
@ -275,6 +322,7 @@ void udp_socket::set_proxy_settings(proxy_settings const& ps)
void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i) void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
{ {
if (e) return; if (e) return;
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -286,6 +334,7 @@ void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
void udp_socket::on_timeout() void udp_socket::on_timeout()
{ {
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
error_code ec; error_code ec;
@ -295,6 +344,7 @@ void udp_socket::on_timeout()
void udp_socket::on_connect(int ticket) void udp_socket::on_connect(int ticket)
{ {
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
m_connection_ticket = ticket; m_connection_ticket = ticket;
@ -306,12 +356,13 @@ void udp_socket::on_connect(int ticket)
void udp_socket::on_connected(error_code const& e) void udp_socket::on_connected(error_code const& e)
{ {
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex);
m_cc.done(m_connection_ticket); m_cc.done(m_connection_ticket);
m_connection_ticket = -1; m_connection_ticket = -1;
if (e) return; if (e) return;
mutex_t::scoped_lock l(m_mutex);
using namespace libtorrent::detail; using namespace libtorrent::detail;
// send SOCKS5 authentication methods // send SOCKS5 authentication methods
@ -335,6 +386,7 @@ void udp_socket::on_connected(error_code const& e)
void udp_socket::handshake1(error_code const& e) void udp_socket::handshake1(error_code const& e)
{ {
CHECK_MAGIC;
if (e) return; if (e) return;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -345,6 +397,7 @@ void udp_socket::handshake1(error_code const& e)
void udp_socket::handshake2(error_code const& e) void udp_socket::handshake2(error_code const& e)
{ {
CHECK_MAGIC;
if (e) return; if (e) return;
using namespace libtorrent::detail; using namespace libtorrent::detail;
@ -390,6 +443,7 @@ void udp_socket::handshake2(error_code const& e)
void udp_socket::handshake3(error_code const& e) void udp_socket::handshake3(error_code const& e)
{ {
CHECK_MAGIC;
if (e) return; if (e) return;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -400,6 +454,7 @@ void udp_socket::handshake3(error_code const& e)
void udp_socket::handshake4(error_code const& e) void udp_socket::handshake4(error_code const& e)
{ {
CHECK_MAGIC;
if (e) return; if (e) return;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -418,6 +473,7 @@ void udp_socket::handshake4(error_code const& e)
void udp_socket::socks_forward_udp() void udp_socket::socks_forward_udp()
{ {
CHECK_MAGIC;
using namespace libtorrent::detail; using namespace libtorrent::detail;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -437,6 +493,7 @@ void udp_socket::socks_forward_udp()
void udp_socket::connect1(error_code const& e) void udp_socket::connect1(error_code const& e)
{ {
CHECK_MAGIC;
if (e) return; if (e) return;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -447,6 +504,7 @@ void udp_socket::connect1(error_code const& e)
void udp_socket::connect2(error_code const& e) void udp_socket::connect2(error_code const& e)
{ {
CHECK_MAGIC;
if (e) return; if (e) return;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);