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);
proxy_settings const& get_proxy_settings() { return m_proxy_settings; }
#ifndef NDEBUG
~udp_socket() { m_magic = 0; }
#endif
private:
callback_t m_callback;
@ -94,6 +98,7 @@ namespace libtorrent
char m_v4_buf[1600];
char m_v6_buf[1600];
int m_bind_port;
uint8_t m_outstanding;
tcp::socket m_socks5_sock;
int m_connection_ticket;
@ -103,6 +108,9 @@ namespace libtorrent
char m_tmp_buf[100];
bool m_tunnel_packets;
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_ipv6_sock(ios)
, m_bind_port(0)
, m_outstanding(0)
, m_socks5_sock(ios)
, m_connection_ticket(-1)
, m_cc(cc)
, m_resolver(ios)
, 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)
{
if (ec == asio::error::operation_aborted) return;
mutex_t::scoped_lock l(m_mutex);
CHECK_MAGIC;
if (m_tunnel_packets)
{
// 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)
{
if (e == asio::error::operation_aborted) return;
TORRENT_ASSERT(m_magic == 0x1337);
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 (e)
@ -59,9 +88,9 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_
try {
#endif
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
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
} catch(std::exception&) {}
#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)
unwrap(e, m_v4_buf, bytes_transferred);
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
} 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)
unwrap(e, m_v6_buf, bytes_transferred);
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
} 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))
, 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)
{
CHECK_MAGIC;
using namespace libtorrent::detail;
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
void udp_socket::unwrap(error_code const& e, char const* buf, int size)
{
CHECK_MAGIC;
using namespace libtorrent::detail;
// the minimum socks5 header size
@ -177,27 +209,37 @@ void udp_socket::unwrap(error_code const& e, char const* buf, int size)
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()
{
TORRENT_ASSERT(m_magic == 0x1337);
mutex_t::scoped_lock l(m_mutex);
error_code ec;
m_ipv4_sock.close(ec);
m_ipv6_sock.close(ec);
m_socks5_sock.close(ec);
m_callback.clear();
if (m_connection_ticket >= 0)
{
m_cc.done(m_connection_ticket);
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)
{
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex);
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_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2));
}
++m_outstanding;
m_bind_port = ep.port();
}
void udp_socket::bind(int port)
{
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex);
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.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_outstanding;
}
m_ipv6_sock.open(udp::v6(), 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.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_outstanding;
}
m_bind_port = port;
}
void udp_socket::set_proxy_settings(proxy_settings const& ps)
{
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex);
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)
{
if (e) return;
CHECK_MAGIC;
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()
{
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex);
error_code ec;
@ -295,6 +344,7 @@ void udp_socket::on_timeout()
void udp_socket::on_connect(int ticket)
{
CHECK_MAGIC;
mutex_t::scoped_lock l(m_mutex);
m_connection_ticket = ticket;
@ -306,12 +356,13 @@ void udp_socket::on_connect(int ticket)
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_connection_ticket = -1;
if (e) return;
mutex_t::scoped_lock l(m_mutex);
using namespace libtorrent::detail;
// 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)
{
CHECK_MAGIC;
if (e) return;
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)
{
CHECK_MAGIC;
if (e) return;
using namespace libtorrent::detail;
@ -390,6 +443,7 @@ void udp_socket::handshake2(error_code const& e)
void udp_socket::handshake3(error_code const& e)
{
CHECK_MAGIC;
if (e) return;
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)
{
CHECK_MAGIC;
if (e) return;
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()
{
CHECK_MAGIC;
using namespace libtorrent::detail;
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)
{
CHECK_MAGIC;
if (e) return;
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)
{
CHECK_MAGIC;
if (e) return;
mutex_t::scoped_lock l(m_mutex);