defer reconnecting peers to after the second_tick loop (to avoid mutating m_connections while iterating over it)

This commit is contained in:
arvidn 2017-06-13 04:41:26 -04:00 committed by Arvid Norberg
parent 3215deb2c5
commit 3f09d16e3c
3 changed files with 94 additions and 2 deletions

View File

@ -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<queue>(
std::ref(m_sim->get_io_service())
, 1000
, lt::duration_cast<lt::time_duration>(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<queue>(
std::ref(m_sim->get_io_service()), 1000
, lt::duration_cast<lt::time_duration>(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<peer_disconnected_alert>(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;

View File

@ -30,6 +30,9 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_UTILS_HPP_INCLUDED
#define TORRENT_UTILS_HPP_INCLUDED
#include <functional>
#include "libtorrent/address.hpp"
#include "libtorrent/socket.hpp"
@ -61,3 +64,5 @@ void print_alerts(lt::session& ses
, std::function<void(lt::session&, lt::alert const*)> on_alert
= [](lt::session&, lt::alert const*) {});
#endif

View File

@ -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<torrent> weak_t = t;
std::weak_ptr<peer_connection> 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<torrent> tor = weak_t.lock();
std::shared_ptr<peer_connection> p = weak_self.lock();
if (tor && p)
{
torrent_peer* pi = p->peer_info_struct();
tor->connect_to_peer(pi, true);
}
});
}
return;
}