diff --git a/include/libtorrent/connection_queue.hpp b/include/libtorrent/connection_queue.hpp index 527b862df..749d72133 100644 --- a/include/libtorrent/connection_queue.hpp +++ b/include/libtorrent/connection_queue.hpp @@ -63,6 +63,7 @@ public: void limit(int limit); int limit() const; void close(); + int size() const { return m_queue.size(); } #ifndef NDEBUG void check_invariant() const; @@ -93,6 +94,7 @@ private: int m_next_ticket; int m_num_connecting; int m_half_open_limit; + bool m_abort; deadline_timer m_timer; diff --git a/src/connection_queue.cpp b/src/connection_queue.cpp index 548fe07e6..d5228a66a 100644 --- a/src/connection_queue.cpp +++ b/src/connection_queue.cpp @@ -42,6 +42,7 @@ namespace libtorrent connection_queue::connection_queue(io_service& ios): m_next_ticket(0) , m_num_connecting(0) , m_half_open_limit(0) + , m_abort(false) , m_timer(ios) #ifndef NDEBUG , m_in_timeout_function(false) @@ -114,7 +115,24 @@ namespace libtorrent void connection_queue::close() { error_code ec; + mutex_t::scoped_lock l(m_mutex); m_timer.cancel(ec); + m_abort = true; + + // make a copy of the list to go through, so + // that connections removing themseleves won't + // interfere with the iteration + std::list closing_entries = m_queue; + + // we don't want to call the timeout callback while we're locked + // since that is a recepie for dead-locks + l.unlock(); + + for (std::list::iterator i = closing_entries.begin() + , end(closing_entries.end()); i != end; ++i) + { + try { i->on_timeout(); } catch (std::exception&) {} + } } void connection_queue::limit(int limit) @@ -148,6 +166,7 @@ namespace libtorrent #ifdef TORRENT_CONNECTION_LOGGING m_log << log_time() << " " << free_slots() << std::endl; #endif + if (m_abort) return; if (m_num_connecting >= m_half_open_limit && m_half_open_limit > 0) return; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index f67559468..b0702c310 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -498,6 +498,12 @@ namespace aux { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << time_now_string() << " aborting all connections (" << m_connections.size() << ")\n"; #endif + m_half_open.close(); + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + (*m_logger) << time_now_string() << " connection queue: " << m_half_open.size() << std::endl; +#endif + // abort all connections while (!m_connections.empty()) { @@ -508,10 +514,14 @@ namespace aux { TORRENT_ASSERT(conn == int(m_connections.size()) + 1); } +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + (*m_logger) << time_now_string() << " connection queue: " << m_half_open.size() << std::endl; +#endif + TORRENT_ASSERT(m_half_open.size() == 0); + #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << time_now_string() << " shutting down connection queue\n"; #endif - m_half_open.close(); m_download_channel.close(); m_upload_channel.close(); @@ -2270,6 +2280,7 @@ namespace aux { (*m_logger) << time_now_string() << "\n\n *** shutting down session *** \n\n"; #endif abort(); + TORRENT_ASSERT(m_connections.empty()); #ifndef TORRENT_DISABLE_GEO_IP if (m_asnum_db) GeoIP_delete(m_asnum_db); @@ -2292,6 +2303,7 @@ namespace aux { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << time_now_string() << " shutdown complete!\n"; #endif + TORRENT_ASSERT(m_connections.empty()); } void session_impl::set_max_uploads(int limit) diff --git a/src/torrent.cpp b/src/torrent.cpp index 9f045eec5..1ecede483 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -3126,7 +3126,8 @@ namespace libtorrent && m_state != torrent_status::checking_files && (m_state != torrent_status::queued_for_checking || !valid_metadata()) - && m_policy.num_connect_candidates() > 0; + && m_policy.num_connect_candidates() > 0 + && !m_abort; } void torrent::disconnect_all()