simplify session pause mechanism by keeping two separate states in torrents and having the session explicitly tell torrents when it's pausing (#779)

This commit is contained in:
Arvid Norberg 2016-06-03 07:32:48 -04:00
parent 42a9022065
commit be67553897
13 changed files with 556 additions and 116 deletions

View File

@ -369,7 +369,7 @@ namespace libtorrent
, int protocol, error_code const& ec, int nat_transport);
bool is_aborted() const override { return m_abort; }
bool is_paused() const override { return m_paused; }
bool is_paused() const { return m_paused; }
void pause();
void resume();

View File

@ -176,7 +176,6 @@ namespace libtorrent { namespace aux
virtual boost::uint16_t session_time() const = 0;
virtual bool is_paused() const = 0;
virtual bool is_aborted() const = 0;
virtual int num_uploads() const = 0;
virtual bool preemptive_unchoke() const = 0;

View File

@ -173,7 +173,7 @@ namespace libtorrent
struct TORRENT_EXTRA_EXPORT torrent_hot_members
{
torrent_hot_members(aux::session_interface& ses
, add_torrent_params const& p, int block_size);
, add_torrent_params const& p, int block_size, bool session_paused);
protected:
// the piece picker. This is allocated lazily. When we don't
@ -225,6 +225,10 @@ namespace libtorrent
// is true if this torrent has allows having peers
bool m_paused:1;
// is true if the session is paused, in which case the torrent is
// effectively paused as well.
bool m_session_paused:1;
// this is set when the torrent is in share-mode
bool m_share_mode:1;
@ -274,7 +278,7 @@ namespace libtorrent
public:
torrent(aux::session_interface& ses, int block_size
, int seq, add_torrent_params const& p
, int seq, bool session_paused, add_torrent_params const& p
, sha1_hash const& info_hash);
~torrent();
@ -458,6 +462,7 @@ namespace libtorrent
flag_graceful_pause = 1,
flag_clear_disk_cache = 2
};
void set_session_paused(bool b);
void set_paused(bool b, int flags = flag_clear_disk_cache);
void set_announce_to_dht(bool b) { m_announce_to_dht = b; }
void set_announce_to_trackers(bool b) { m_announce_to_trackers = b; }

View File

@ -24,6 +24,7 @@ project
;
alias libtorrent-sims :
[ run test_pause.cpp ]
[ run test_socks5.cpp ]
[ run test_checking.cpp ]
[ run test_optimistic_unchoke.cpp ]

View File

@ -53,9 +53,11 @@ struct fake_peer
fake_peer(simulation& sim, char const* ip)
: m_ios(sim, asio::ip::address::from_string(ip))
, m_acceptor(m_ios)
, m_in_socket(m_ios)
, m_out_socket(m_ios)
, m_tripped(false)
, m_socket(m_ios)
, m_info_hash(0)
, m_accepted(false)
, m_connected(false)
, m_disconnected(false)
{
boost::system::error_code ec;
m_acceptor.open(asio::ip::tcp::v4(), ec);
@ -65,37 +67,46 @@ struct fake_peer
m_acceptor.listen(10, ec);
TEST_CHECK(!ec);
m_acceptor.async_accept(m_in_socket, [&] (boost::system::error_code const& ec)
m_acceptor.async_accept(m_socket, [&] (boost::system::error_code const& ec)
{
// TODO: ideally we would kick off a read on the socket to verify that
// we received a bittorrent handshake
if (!ec) m_tripped = true;
using namespace std::placeholders;
if (ec) return;
asio::async_read(m_socket, asio::mutable_buffers_1(&m_out_buffer[0], 68)
, std::bind(&fake_peer::read_handshake, this, _1, _2));
m_accepted = true;
});
}
void close()
{
m_acceptor.close();
m_in_socket.close();
m_out_socket.close();
m_socket.close();
}
void connect_to(asio::ip::tcp::endpoint ep, lt::sha1_hash const& ih)
{
using namespace std::placeholders;
m_info_hash = ih;
boost::system::error_code ec;
m_out_socket.async_connect(ep, std::bind(&fake_peer::write_handshake
m_socket.async_connect(ep, std::bind(&fake_peer::write_handshake
, this, _1, ih));
}
bool tripped() const { return m_tripped; }
bool accepted() const { return m_accepted; }
bool connected() const { return m_connected; }
bool disconnected() const { return m_disconnected; }
private:
void write_handshake(boost::system::error_code const& ec, lt::sha1_hash ih)
{
asio::ip::tcp::endpoint ep = m_out_socket.remote_endpoint();
using namespace std::placeholders;
asio::ip::tcp::endpoint ep = m_socket.remote_endpoint();
std::printf("fake_peer::connect (%s) -> (%d) %s\n"
, lt::print_endpoint(ep).c_str(), ec.value()
, ec.message().c_str());
@ -108,43 +119,140 @@ private:
memcpy(m_out_buffer, handshake, len);
memcpy(&m_out_buffer[28], ih.data(), 20);
asio::async_write(m_out_socket, asio::const_buffers_1(&m_out_buffer[0]
, len), [=](boost::system::error_code const& ec, size_t bytes_transferred)
asio::async_write(m_socket, asio::const_buffers_1(&m_out_buffer[0]
, len), [this, ep](boost::system::error_code const& ec, size_t bytes_transferred)
{
std::printf("fake_peer::write_handshake(%s) -> (%d) %s\n"
, lt::print_endpoint(ep).c_str(), ec.value()
, ec.message().c_str());
this->m_out_socket.close();
asio::async_read(m_socket, asio::mutable_buffers_1(&m_out_buffer[0], 68)
, std::bind(&fake_peer::read_handshake, this, _1, _2));
});
}
void read_handshake(lt::error_code const& ec, size_t bytes_transferred)
{
using namespace std::placeholders;
std::printf("fake_peer::read_handshake -> (%d) %s\n"
, ec.value(), ec.message().c_str());
if (ec)
{
m_socket.close();
return;
}
if (memcmp(&m_out_buffer[0], "\x13" "BitTorrent protocol", 20) != 0)
{
std::printf(" invalid protocol specifier\n");
m_socket.close();
return;
}
// if this peer accepted an incoming connection, we don't know what the
// info hash is supposed to be
if (!m_info_hash.is_all_zeros()
&& memcmp(&m_out_buffer[28], m_info_hash.data(), 20) != 0)
{
std::printf(" invalid info hash\n");
m_socket.close();
return;
}
m_connected = true;
// keep reading until we receie EOF, then set m_disconnected = true
m_socket.async_read_some(asio::mutable_buffers_1(&m_out_buffer[0]
, sizeof(m_out_buffer))
, std::bind(&fake_peer::on_read, this, _1, _2));
}
void on_read(lt::error_code const& ec, size_t bytes_transferred)
{
using namespace std::placeholders;
std::printf("fake_peer::on_read -> (%d) %s\n"
, ec.value(), ec.message().c_str());
if (ec)
{
std::printf(" closing\n");
m_disconnected = true;
m_socket.close();
return;
}
m_socket.async_read_some(asio::mutable_buffers_1(&m_out_buffer[0]
, sizeof(m_out_buffer))
, std::bind(&fake_peer::on_read, this, _1, _2));
}
char m_out_buffer[300];
asio::io_service m_ios;
asio::ip::tcp::acceptor m_acceptor;
asio::ip::tcp::socket m_in_socket;
asio::ip::tcp::socket m_out_socket;
bool m_tripped;
asio::ip::tcp::socket m_socket;
lt::sha1_hash m_info_hash;
// set to true if this peer received an incoming connection
// if this is an outgoing connection, this will always be false
bool m_accepted;
// set to true if this peer completed a bittorrent handshake
bool m_connected;
// set to true if this peer has been disconnected by the other end
bool m_disconnected;
};
inline void add_fake_peers(lt::torrent_handle h)
inline void add_fake_peer(lt::torrent_handle& h, int const i)
{
char ep[30];
std::snprintf(ep, sizeof(ep), "60.0.0.%d", i);
h.connect_peer(lt::tcp::endpoint(
lt::address_v4::from_string(ep), 6881));
}
inline void add_fake_peers(lt::torrent_handle& h, int const n = 5)
{
// add the fake peers
for (int i = 0; i < 5; ++i)
for (int i = 0; i < n; ++i)
{
char ep[30];
std::snprintf(ep, sizeof(ep), "60.0.0.%d", i);
h.connect_peer(lt::tcp::endpoint(
lt::address_v4::from_string(ep), 6881));
add_fake_peer(h, i);
}
}
inline void check_tripped(std::array<fake_peer*, 5>& test_peers, std::array<bool, 5> expected)
template<unsigned long N>
void check_accepted(std::array<fake_peer*, N>& test_peers
, std::array<bool, N> expected)
{
int idx = 0;
for (auto p : test_peers)
{
TEST_EQUAL(p->tripped(), expected[idx]);
TEST_EQUAL(p->accepted(), expected[idx]);
++idx;
}
}
template<unsigned long N>
void check_connected(std::array<fake_peer*, N>& test_peers
, std::array<bool, N> expected)
{
int idx = 0;
for (auto p : test_peers)
{
TEST_EQUAL(p->connected(), expected[idx]);
++idx;
}
}
template<unsigned long N>
void check_disconnected(std::array<fake_peer*, N>& test_peers
, std::array<bool, N> expected)
{
int idx = 0;
for (auto p : test_peers)
{
TEST_EQUAL(p->disconnected(), expected[idx]);
++idx;
}
}

View File

@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert_types.hpp"
#include "libtorrent/deadline_timer.hpp"
#include "settings.hpp"
#include "utils.hpp"
#include "create_torrent.hpp"
#include "simulator/simulator.hpp"
#include "simulator/utils.hpp"
@ -49,14 +50,6 @@ namespace lt = libtorrent;
using sim::asio::ip::address_v4;
std::unique_ptr<sim::asio::io_service> make_io_service(sim::simulation& sim, int i)
{
char ep[30];
std::snprintf(ep, sizeof(ep), "50.0.%d.%d", (i + 1) >> 8, (i + 1) & 0xff);
return std::unique_ptr<sim::asio::io_service>(new sim::asio::io_service(
sim, asio::ip::address_v4::from_string(ep)));
}
// this is the general template for these tests. create the session with custom
// settings (Settings), set up the test, by adding torrents with certain
// arguments (Setup), run the test and verify the end state (Test)

View File

@ -137,7 +137,7 @@ TORRENT_TEST(apply_ip_filter)
[](lt::session& ses, std::array<fake_peer*, 5>& test_peers)
{
check_tripped(test_peers, {{false, false, false, true, true}} );
check_accepted(test_peers, {{false, false, false, true, true}} );
}
);
}
@ -170,7 +170,7 @@ TORRENT_TEST(update_ip_filter)
[](lt::session& ses, std::array<fake_peer*, 5>& test_peers)
{
check_tripped(test_peers, {{false, false, false, true, true}} );
check_accepted(test_peers, {{false, false, false, true, true}} );
}
);
}
@ -204,7 +204,7 @@ TORRENT_TEST(apply_ip_filter_to_torrent)
{
// since the IP filter didn't apply to this torrent, it should have hit
// all peers
check_tripped(test_peers, {{true, true, true, true, true}} );
check_accepted(test_peers, {{true, true, true, true, true}} );
}
);
}
@ -233,7 +233,7 @@ TORRENT_TEST(ip_filter_trackers)
[](lt::session& ses, lt::alert const* a) {},
[](lt::session& ses, std::array<fake_peer*, 5>& test_peers)
{
check_tripped(test_peers, {{false, false, false, true, true}} );
check_accepted(test_peers, {{false, false, false, true, true}} );
}
);
}

337
simulation/test_pause.cpp Normal file
View File

@ -0,0 +1,337 @@
/*
Copyright (c) 2016, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/session.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/settings_pack.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/deadline_timer.hpp"
#include "settings.hpp"
#include "fake_peer.hpp"
#include "utils.hpp"
#include "create_torrent.hpp"
#include "simulator/simulator.hpp"
#include "simulator/utils.hpp"
#include <iostream>
using namespace sim;
using namespace libtorrent;
namespace lt = libtorrent;
using sim::asio::ip::address_v4;
// this is the general template for these tests. create the session with custom
// settings (Settings), set up the test, by adding torrents with certain
// arguments (Setup), run the test and verify the end state (Test)
template <typename Setup, typename Torrent, typename Test, typename Check>
void run_test(Setup const& setup, Torrent const& torrent
, Test const& test, Check const& check)
{
// setup the simulation
sim::default_config network_cfg;
sim::simulation sim{network_cfg};
std::unique_ptr<sim::asio::io_service> ios = make_io_service(sim, 0);
lt::session_proxy zombie;
// setup settings pack to use for the session (customization point)
lt::settings_pack pack = settings();
// create session
std::shared_ptr<lt::session> ses = std::make_shared<lt::session>(pack, *ios);
setup(*ses);
fake_peer p1(sim, "60.0.0.0");
fake_peer p2(sim, "60.0.0.1");
fake_peer p3(sim, "60.0.0.2");
std::array<fake_peer*, 3> test_peers = {{ &p1, &p2, &p3 }};
// add torrent
lt::add_torrent_params params = create_torrent(0, false);
params.flags &= ~lt::add_torrent_params::flag_auto_managed;
params.flags &= ~lt::add_torrent_params::flag_paused;
ses->async_add_torrent(params);
lt::torrent_handle h;
print_alerts(*ses, [&](lt::session& ses, lt::alert const* a) {
auto at = lt::alert_cast<torrent_added_alert>(a);
if (at == nullptr) return;
h = at->handle;
// disable the print_alert object from polling any more alerts
ses.set_alert_notify([]{});
torrent(ses, h, test_peers);
});
sim::timer t1(sim, lt::seconds(5)
, [&](boost::system::error_code const& ec)
{
test(*ses, h, test_peers);
});
// set up a timer to fire later, to verify everything we expected to happen
// happened
sim::timer t2(sim, lt::seconds(10)
, [&](boost::system::error_code const& ec)
{
check(*ses, h, test_peers);
// shut down
zombie = ses->abort();
ses.reset();
});
sim.run();
}
// make sure the torrent disconnects all its peers when it's paused
TORRENT_TEST(torrent_paused_disconnect)
{
run_test(
[](lt::session& ses) {},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
add_fake_peers(h, 3);
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
check_accepted(test_peers, {{true, true, true}});
check_connected(test_peers, {{true, true, true}});
check_disconnected(test_peers, {{false, false, false}});
h.pause();
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
check_disconnected(test_peers, {{true, true, true}});
TEST_EQUAL(h.status().paused, true);
});
}
// make sure the torrent disconnects all its peers when the session is paused
TORRENT_TEST(session_paused_disconnect)
{
run_test(
[](lt::session& ses) {},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
add_fake_peers(h, 3);
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
check_accepted(test_peers, {{true, true, true}});
check_connected(test_peers, {{true, true, true}});
check_disconnected(test_peers, {{false, false, false}});
ses.pause();
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
check_disconnected(test_peers, {{true, true, true}});
// the torrent isn't paused, the session is
TEST_EQUAL(h.status().paused, false);
});
}
// make sure a torrent is not connecting to any peers when added to a paused
// session
TORRENT_TEST(paused_session_add_torrent)
{
run_test(
[](lt::session& ses) { ses.pause(); },
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
add_fake_peers(h, 3);
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
check_accepted(test_peers, {{false, false, false}});
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
// the torrent isn't paused, the session is
TEST_EQUAL(h.status().paused, false);
});
}
// make sure the torrent isn't connecting to peers when it's paused
TORRENT_TEST(paused_torrent_add_peers)
{
run_test(
[](lt::session& ses) {},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
h.pause();
add_fake_peers(h, 3);
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
check_accepted(test_peers, {{false, false, false}});
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, true);
});
}
// make sure we post the torrent_paused alert when pausing a torrent
TORRENT_TEST(torrent_paused_alert)
{
run_test(
[](lt::session& ses) {},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, false);
h.pause();
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, true);
std::vector<lt::alert*> alerts;
ses.pop_alerts(&alerts);
lt::time_point start_time = alerts[0]->timestamp();
int num_resume = 0;
int num_paused = 0;
for (alert* a : alerts)
{
std::printf("%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
- start_time).count()), a->message().c_str());
if (lt::alert_cast<torrent_resumed_alert>(a)) ++num_resume;
if (lt::alert_cast<torrent_paused_alert>(a)) ++num_paused;
}
TEST_EQUAL(num_resume, 0);
TEST_EQUAL(num_paused, 1);
});
}
// make sure we post the torrent_paused alert when pausing the session
TORRENT_TEST(session_paused_alert)
{
run_test(
[](lt::session& ses) {},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, false);
ses.pause();
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, false);
std::vector<lt::alert*> alerts;
ses.pop_alerts(&alerts);
lt::time_point start_time = alerts[0]->timestamp();
int num_resume = 0;
int num_paused = 0;
for (alert* a : alerts)
{
std::printf("%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
- start_time).count()), a->message().c_str());
if (lt::alert_cast<torrent_resumed_alert>(a)) ++num_resume;
if (lt::alert_cast<torrent_paused_alert>(a)) ++num_paused;
}
TEST_EQUAL(num_resume, 0);
TEST_EQUAL(num_paused, 1);
});
}
// make sure we post both the paused and resumed alert when pausing and resuming
// the session.
TORRENT_TEST(session_pause_resume)
{
run_test(
[](lt::session& ses) {},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, false);
ses.pause();
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, false);
ses.resume();
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, false);
std::vector<lt::alert*> alerts;
ses.pop_alerts(&alerts);
lt::time_point start_time = alerts[0]->timestamp();
int num_resume = 0;
int num_paused = 0;
for (alert* a : alerts)
{
std::printf("%-3d %s\n", int(duration_cast<lt::seconds>(a->timestamp()
- start_time).count()), a->message().c_str());
if (lt::alert_cast<torrent_resumed_alert>(a)) ++num_resume;
if (lt::alert_cast<torrent_paused_alert>(a)) ++num_paused;
}
TEST_EQUAL(num_resume, 1);
TEST_EQUAL(num_paused, 1);
});
}
// make sure peers added to a (non-paused) torrent in a paused session are
// connected once the session is resumed
TORRENT_TEST(session_pause_resume_connect)
{
run_test(
[](lt::session& ses) {},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, false);
ses.pause();
add_fake_peers(h, 3);
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, false);
check_accepted(test_peers, {{false, false, false}});
ses.resume();
},
[](lt::session& ses, lt::torrent_handle h, std::array<fake_peer*, 3>& test_peers) {
TEST_EQUAL(h.status().paused, false);
check_accepted(test_peers, {{true, true, true}});
});
}

View File

@ -51,14 +51,6 @@ using namespace libtorrent;
namespace lt = libtorrent;
std::unique_ptr<sim::asio::io_service> make_io_service(sim::simulation& sim, int i)
{
char ep[30];
std::snprintf(ep, sizeof(ep), "50.0.%d.%d", (i + 1) >> 8, (i + 1) & 0xff);
return std::unique_ptr<sim::asio::io_service>(new sim::asio::io_service(
sim, address_v4::from_string(ep)));
}
// this is the general template for these tests. create the session with custom
// settings (Settings), set up the test, by adding torrents with certain
// arguments (Setup), run the test and verify the end state (Test)

View File

@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert_types.hpp"
#include "libtorrent/session_stats.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/io_service.hpp"
#include "setup_swarm.hpp"
using namespace libtorrent;
@ -142,3 +143,11 @@ void print_alerts(lt::session& ses
} ); } );
}
std::unique_ptr<sim::asio::io_service> make_io_service(sim::simulation& sim, int i)
{
char ep[30];
std::snprintf(ep, sizeof(ep), "50.0.%d.%d", (i + 1) >> 8, (i + 1) & 0xff);
return std::unique_ptr<sim::asio::io_service>(new sim::asio::io_service(
sim, lt::address_v4::from_string(ep)));
}

View File

@ -50,6 +50,9 @@ void filter_ips(lt::session& ses);
void set_cache_size(lt::session& ses, int val);
int get_cache_size(lt::session& ses);
std::unique_ptr<sim::asio::io_service> make_io_service(
sim::simulation& sim, int i);
enum flags_t
{
ipv6 = 1,

View File

@ -851,11 +851,9 @@ namespace aux {
session_log(" *** session paused ***");
#endif
m_paused = true;
for (torrent_map::iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; ++i)
for (auto& te : m_torrents)
{
torrent& t = *i->second;
t.do_pause();
te.second->set_session_paused(true);
}
}
@ -865,12 +863,10 @@ namespace aux {
if (!m_paused) return;
m_paused = false;
for (torrent_map::iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; ++i)
for (auto& te : m_torrents)
{
torrent& t = *i->second;
t.do_resume();
if (t.should_check_files()) t.start_checking();
te.second->set_session_paused(false);
}
}
@ -3293,7 +3289,7 @@ namespace aux {
// scrape paused torrents that are auto managed
// (unless the session is paused)
// --------------------------------------------------------------
if (!is_paused())
if (!m_paused)
{
INVARIANT_CHECK;
--m_auto_scrape_time_scaler;
@ -3663,8 +3659,6 @@ namespace aux {
t->log_to_all_peers("auto manager starting (inactive) torrent");
#endif
t->set_paused(false);
t->update_gauge();
t->update_want_peers();
continue;
}
@ -3681,8 +3675,6 @@ namespace aux {
t->log_to_all_peers("auto manager starting torrent");
#endif
t->set_paused(false);
t->update_gauge();
t->update_want_peers();
continue;
}
@ -3696,8 +3688,6 @@ namespace aux {
t->set_announce_to_dht(false);
t->set_announce_to_trackers(false);
t->set_announce_to_lsd(false);
t->update_gauge();
t->update_want_peers();
}
}
@ -3715,7 +3705,7 @@ namespace aux {
m_last_auto_manage = time_now();
m_need_auto_manage = false;
if (is_paused()) return;
if (m_paused) return;
// make copies of the lists of torrents that we want to consider for auto
// management. We need copies because they will be sorted.
@ -4908,7 +4898,8 @@ namespace aux {
int queue_pos = ++m_max_queue_pos;
torrent_ptr = boost::make_shared<torrent>(boost::ref(*this)
, 16 * 1024, queue_pos, boost::cref(params), boost::cref(params.info_hash));
, 16 * 1024, queue_pos, m_paused
, boost::cref(params), boost::cref(params.info_hash));
return torrent_ptr;
}

View File

@ -168,13 +168,15 @@ namespace libtorrent
#endif
torrent_hot_members::torrent_hot_members(aux::session_interface& ses
, add_torrent_params const& p, int block_size)
, add_torrent_params const& p, int const block_size
, bool const session_paused)
: m_ses(ses)
, m_complete(0xffffff)
, m_upload_mode((p.flags & add_torrent_params::flag_upload_mode) != 0)
, m_connections_initialized(false)
, m_abort(false)
, m_paused((p.flags & add_torrent_params::flag_paused) != 0)
, m_session_paused(session_paused)
, m_share_mode((p.flags & add_torrent_params::flag_share_mode) != 0)
, m_have_all(false)
, m_graceful_pause_mode(false)
@ -186,11 +188,12 @@ namespace libtorrent
torrent::torrent(
aux::session_interface& ses
, int block_size
, int seq
, int const block_size
, int const seq
, bool const session_paused
, add_torrent_params const& p
, sha1_hash const& info_hash)
: torrent_hot_members(ses, p, block_size)
: torrent_hot_members(ses, p, block_size, session_paused)
, m_total_uploaded(0)
, m_total_downloaded(0)
, m_tracker_timer(ses.get_io_service())
@ -322,19 +325,18 @@ namespace libtorrent
bool const multi_file = m_torrent_file->is_valid()
&& m_torrent_file->num_files() > 1;
for (std::vector<std::string>::const_iterator i = p.url_seeds.begin()
, end(p.url_seeds.end()); i != end; ++i)
for (auto const& u : p.url_seeds)
{
m_web_seeds.push_back(web_seed_t(*i, web_seed_entry::url_seed));
m_web_seeds.push_back(web_seed_t(u, web_seed_entry::url_seed));
// correct URLs to end with a "/" for multi-file torrents
std::string& url = m_web_seeds.back().url;
if (multi_file && url[url.size()-1] != '/') url += '/';
}
for (std::vector<std::string>::const_iterator i = p.http_seeds.begin()
, end(p.http_seeds.end()); i != end; ++i)
for (auto const& e : p.http_seeds)
{
m_web_seeds.push_back(web_seed_t(*i, web_seed_entry::http_seed));
m_web_seeds.push_back(web_seed_t(e, web_seed_entry::http_seed));
}
// --- TRACKERS ---
@ -346,14 +348,12 @@ namespace libtorrent
}
int tier = 0;
std::vector<int>::const_iterator tier_iter = p.tracker_tiers.begin();
for (std::vector<std::string>::const_iterator i = p.trackers.begin()
, end(p.trackers.end()); i != end; ++i)
auto tier_iter = p.tracker_tiers.begin();
for (announce_entry e : p.trackers)
{
if (tier_iter != p.tracker_tiers.end())
tier = *tier_iter++;
announce_entry e(*i);
e.fail_limit = 0;
e.source = announce_entry::source_magnet_link;
e.tier = tier;
@ -8941,7 +8941,7 @@ namespace libtorrent
&& !has_error()
&& !m_abort
&& !m_graceful_pause_mode
&& !m_ses.is_paused();
&& !m_session_paused;
}
void torrent::flush_cache()
@ -8972,7 +8972,7 @@ namespace libtorrent
bool torrent::is_paused() const
{
return m_paused || m_ses.is_paused() || m_graceful_pause_mode;
return m_paused || m_session_paused || m_graceful_pause_mode;
}
void torrent::pause(bool graceful)
@ -9028,9 +9028,15 @@ namespace libtorrent
if (is_finished())
m_finished_time += m_ses.session_time() - m_became_finished;
m_announce_to_dht = false;
m_announce_to_trackers = false;
m_announce_to_lsd = false;
state_updated();
update_want_peers();
update_want_scrape();
update_gauge();
update_state_list();
#ifndef TORRENT_DISABLE_LOGGING
log_to_all_peers("pausing");
@ -9055,7 +9061,7 @@ namespace libtorrent
// files and flush all cached data
if (m_storage.get() && clear_disk_cache)
{
TORRENT_ASSERT(m_storage);
// the torrent_paused alert will be posted from on_torrent_paused
m_ses.disk_thread().async_stop_torrent(m_storage.get()
, std::bind(&torrent::on_torrent_paused, shared_from_this(), _1));
}
@ -9073,10 +9079,8 @@ namespace libtorrent
// and choke all remaining peers to prevent responding to new
// requests
std::vector<peer_connection*> to_disconnect;
for (peer_iterator i = m_connections.begin();
i != m_connections.end(); ++i)
for (peer_connection* p : m_connections)
{
peer_connection* p = *i;
TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
if (p->is_disconnecting()) continue;
@ -9095,10 +9099,9 @@ namespace libtorrent
to_disconnect.push_back(p);
}
for (peer_iterator i = to_disconnect.begin(); i != to_disconnect.end(); ++i)
{
peer_connection* p = *i;
for (peer_connection* p : to_disconnect)
{
// since we're currently in graceful pause mode, the last peer to
// disconnect (assuming all peers end up begin disconnected here)
// will post the torrent_paused_alert
@ -9146,6 +9149,18 @@ namespace libtorrent
set_need_save_resume();
}
void torrent::set_session_paused(bool const b)
{
if (m_session_paused == b) return;
bool const paused_before = is_paused();
m_session_paused = b;
if (paused_before == is_paused()) return;
if (b) do_pause();
else do_resume();
}
void torrent::set_paused(bool b, int flags)
{
TORRENT_ASSERT(is_single_thread());
@ -9174,32 +9189,16 @@ namespace libtorrent
return;
}
bool const paused_before = is_paused();
m_paused = b;
if (!m_ses.is_paused())
m_graceful_pause_mode = (flags & flag_graceful_pause) ? true : false;
if (b)
{
m_announce_to_dht = false;
m_announce_to_trackers = false;
m_announce_to_lsd = false;
}
if (paused_before == is_paused()) return;
update_gauge();
update_want_scrape();
update_want_peers();
update_state_list();
state_updated();
if (b)
{
do_pause((flags & flag_clear_disk_cache) != 0);
}
else
{
do_resume();
}
m_graceful_pause_mode = (flags & flag_graceful_pause) ? true : false;
if (b) do_pause((flags & flag_clear_disk_cache) != 0);
else do_resume();
}
void torrent::resume()
@ -9216,7 +9215,7 @@ namespace libtorrent
m_announce_to_trackers = true;
m_announce_to_lsd = true;
m_paused = false;
if (!m_ses.is_paused()) m_graceful_pause_mode = false;
if (!m_session_paused) m_graceful_pause_mode = false;
update_gauge();
@ -9265,6 +9264,9 @@ namespace libtorrent
update_want_peers();
update_want_tick();
update_want_scrape();
update_gauge();
if (should_check_files()) start_checking();
if (m_state == torrent_status::checking_files) return;
@ -9837,8 +9839,8 @@ namespace libtorrent
return;
// now, pick one of the rarest pieces to download
int pick = random() % rarest_pieces.size();
bool was_finished = is_finished();
int const pick = random() % rarest_pieces.size();
bool const was_finished = is_finished();
m_picker->set_piece_priority(rarest_pieces[pick], 1);
update_gauge();
update_peer_interest(was_finished);