forked from premiere/premiere-libtorrent
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:
parent
42a9022065
commit
be67553897
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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 ]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}} );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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}});
|
||||
});
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue