diff --git a/simulation/test_swarm.cpp b/simulation/test_swarm.cpp index 7abff593d..0eb60bd91 100644 --- a/simulation/test_swarm.cpp +++ b/simulation/test_swarm.cpp @@ -39,7 +39,13 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/session_stats.hpp" #include "libtorrent/aux_/path.hpp" #include "libtorrent/torrent_info.hpp" +#include "libtorrent/time.hpp" #include "settings.hpp" +#include "setup_transfer.hpp" // for ep() +#include "fake_peer.hpp" + +#include "simulator/queue.hpp" +#include "utils.hpp" using namespace lt; @@ -370,6 +376,70 @@ TORRENT_TEST(shutdown) }); } +// make the delays on the connections unreasonable long, so libtorrent times-out +// the connection attempts +struct timeout_config : sim::default_config +{ + virtual sim::route incoming_route(lt::address ip) override + { + auto it = m_incoming.find(ip); + if (it != m_incoming.end()) return sim::route().append(it->second); + it = m_incoming.insert(it, std::make_pair(ip, std::make_shared( + std::ref(m_sim->get_io_service()) + , 1000 + , lt::duration_cast(seconds(10)) + , 1000, "packet-loss modem in"))); + return sim::route().append(it->second); + } + + virtual sim::route outgoing_route(lt::address ip) override + { + auto it = m_outgoing.find(ip); + if (it != m_outgoing.end()) return sim::route().append(it->second); + it = m_outgoing.insert(it, std::make_pair(ip, std::make_shared( + std::ref(m_sim->get_io_service()), 1000 + , lt::duration_cast(seconds(5)), 200 * 1000, "packet-loss out"))); + return sim::route().append(it->second); + } +}; + +// make sure peers that are no longer alive are handled correctly. +TORRENT_TEST(dead_peers) +{ + int num_connect_timeout = 0; + + timeout_config network_cfg; + sim::simulation sim{network_cfg}; + setup_swarm(1, swarm_test::download, sim + // add session + , [](lt::settings_pack& p) { + p.set_int(settings_pack::peer_connect_timeout, 1); + } + // add torrent + , [](lt::add_torrent_params& params) { + params.peers.assign({ + ep("66.66.66.60", 9999) + , ep("66.66.66.61", 9999) + , ep("66.66.66.62", 9999) + }); + } + // on alert + , [&](lt::alert const* a, lt::session&) { + auto* e = alert_cast(a); + if (e + && e->operation == op_connect + && e->error == error_code(errors::timed_out)) + { + ++num_connect_timeout; + } + } + // terminate + , [](int t, lt::session&) -> bool + { return t > 100; }); + + TEST_EQUAL(num_connect_timeout, 3); +} + TORRENT_TEST(delete_files) { std::string save_path; diff --git a/simulation/utils.hpp b/simulation/utils.hpp index 0128483ef..d301ef735 100644 --- a/simulation/utils.hpp +++ b/simulation/utils.hpp @@ -30,6 +30,9 @@ POSSIBILITY OF SUCH DAMAGE. */ +#ifndef TORRENT_UTILS_HPP_INCLUDED +#define TORRENT_UTILS_HPP_INCLUDED + #include #include "libtorrent/address.hpp" #include "libtorrent/socket.hpp" @@ -61,3 +64,5 @@ void print_alerts(lt::session& ses , std::function on_alert = [](lt::session&, lt::alert const*) {}); +#endif + diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 26c60a179..f822ae4a5 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -4019,10 +4019,27 @@ namespace libtorrent { { m_peer_info->supports_utp = false; // reconnect immediately using TCP - torrent_peer* pi = peer_info_struct(); fast_reconnect(true); disconnect(e, op_connect, 0); - if (t && pi) t->connect_to_peer(pi, true); + if (t && m_peer_info) + { + std::weak_ptr weak_t = t; + std::weak_ptr weak_self = shared_from_this(); + + // we can't touch m_connections here, since we're likely looping + // over it. So defer the actual reconnection to after we've handled + // the existing message queue + m_ses.get_io_service().post([weak_t, weak_self]() + { + std::shared_ptr tor = weak_t.lock(); + std::shared_ptr p = weak_self.lock(); + if (tor && p) + { + torrent_peer* pi = p->peer_info_struct(); + tor->connect_to_peer(pi, true); + } + }); + } return; }