diff --git a/ChangeLog b/ChangeLog index 1d3392ec9..6373d4672 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,7 @@ * fix uTP edge case where udp socket buffer fills up * fix nagle implementation in uTP + * fix deadlock caused by some UDP tracker failures * fix potential integer overflow issue in timers on windows * minor fix to peer_proportional mixed_mode algorithm (TCP limit could go too low) * graceful pause fix diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp index 885490a00..42c0cdb24 100644 --- a/include/libtorrent/tracker_manager.hpp +++ b/include/libtorrent/tracker_manager.hpp @@ -188,6 +188,8 @@ namespace libtorrent virtual void on_timeout(error_code const& ec) = 0; virtual ~timeout_handler() {} + io_service& get_io_service() { return m_timeout.get_io_service(); } + #if !defined TORRENT_VERBOSE_LOGGING \ && !defined TORRENT_LOGGING \ && !defined TORRENT_ERROR_LOGGING @@ -229,7 +231,6 @@ namespace libtorrent tracker_request const& tracker_req() const { return m_req; } - void fail_disp(error_code ec) { fail(ec); } void fail(error_code const& ec, int code = -1, char const* msg = "" , int interval = 0, int min_interval = 0); virtual void start() = 0; @@ -242,6 +243,9 @@ namespace libtorrent virtual bool on_receive_hostname(error_code const& ec, char const* hostname , char const* buf, int size) { return false; } + boost::intrusive_ptr self() + { return boost::intrusive_ptr(this); } + #if !defined TORRENT_VERBOSE_LOGGING \ && !defined TORRENT_LOGGING \ && !defined TORRENT_ERROR_LOGGING @@ -249,6 +253,9 @@ namespace libtorrent protected: #endif + void fail_impl(error_code const& ec, int code = -1, std::string msg = std::string() + , int interval = 0, int min_interval = 0); + boost::weak_ptr m_requester; tracker_manager& m_man; diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 5001edc55..3c0fdf956 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -107,8 +107,7 @@ namespace libtorrent std::size_t pos = url.find("announce"); if (pos == std::string::npos) { - m_ios.post(boost::bind(&http_tracker_connection::fail_disp, self() - , error_code(errors::scrape_not_available))); + tracker_connection::fail(error_code(errors::scrape_not_available)); return; } url.replace(pos, 8, "scrape"); diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp index 74ebb732b..9ee968de9 100644 --- a/src/tracker_manager.cpp +++ b/src/tracker_manager.cpp @@ -163,9 +163,17 @@ namespace libtorrent void tracker_connection::fail(error_code const& ec, int code , char const* msg, int interval, int min_interval) + { + // we need to post the error to avoid deadlock + get_io_service().post(boost::bind(&tracker_connection::fail_impl + , self(), ec, code, std::string(msg), interval, min_interval)); + } + + void tracker_connection::fail_impl(error_code const& ec, int code + , std::string msg, int interval, int min_interval) { boost::shared_ptr cb = requester(); - if (cb) cb->tracker_request_error(m_req, code, ec, msg + if (cb) cb->tracker_request_error(m_req, code, ec, msg.c_str() , interval == 0 ? min_interval : interval); close(); } diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp index 22380721f..24709352f 100644 --- a/src/udp_tracker_connection.cpp +++ b/src/udp_tracker_connection.cpp @@ -95,9 +95,7 @@ namespace libtorrent if (ec) { - // never call fail() when the session mutex is locked! - m_ses.m_io_service.post(boost::bind( - &tracker_connection::fail_disp, self(), ec)); + tracker_connection::fail(ec); return; }