add limit for number of web seed connections (#1817)
add limit for number of web seed connections
This commit is contained in:
parent
1280c7f7ae
commit
642cfa387d
|
@ -1,3 +1,4 @@
|
||||||
|
* add limit for number of web seed connections
|
||||||
* added support for retrieval of DHT live nodes
|
* added support for retrieval of DHT live nodes
|
||||||
* complete UNC path support
|
* complete UNC path support
|
||||||
* add packets pool allocator
|
* add packets pool allocator
|
||||||
|
|
|
@ -1625,6 +1625,10 @@ namespace libtorrent
|
||||||
// systems.
|
// systems.
|
||||||
close_file_interval,
|
close_file_interval,
|
||||||
|
|
||||||
|
// the max number of web seeds to have connected per torrent at any
|
||||||
|
// given time.
|
||||||
|
max_web_seed_connections,
|
||||||
|
|
||||||
max_int_setting_internal
|
max_int_setting_internal
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,31 @@ namespace libtorrent
|
||||||
// if this bitfield is non-empty, it represents the files this web server
|
// if this bitfield is non-empty, it represents the files this web server
|
||||||
// has.
|
// has.
|
||||||
typed_bitfield<file_index_t> have_files;
|
typed_bitfield<file_index_t> have_files;
|
||||||
|
#if defined __GNUC__ && defined _GLIBCXX_DEBUG
|
||||||
|
// this works around a bug in libstdc++'s checked iterators
|
||||||
|
// http://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle
|
||||||
|
web_seed_t& operator=(web_seed_t&& rhs)
|
||||||
|
{
|
||||||
|
if (&rhs == this) return *this;
|
||||||
|
|
||||||
|
web_seed_entry::operator=(std::move(rhs));
|
||||||
|
retry = std::move(rhs.retry);
|
||||||
|
endpoints = std::move(rhs.endpoints);
|
||||||
|
peer_info = std::move(rhs.peer_info);
|
||||||
|
supports_keepalive = std::move(rhs.supports_keepalive);
|
||||||
|
resolving = std::move(rhs.resolving);
|
||||||
|
removed = std::move(rhs.removed);
|
||||||
|
ephemeral = std::move(rhs.ephemeral);
|
||||||
|
restart_request = std::move(rhs.restart_request);
|
||||||
|
restart_piece = std::move(rhs.restart_piece);
|
||||||
|
redirects = std::move(rhs.redirects);
|
||||||
|
have_files = std::move(rhs.have_files);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
web_seed_t& operator=(web_seed_t const&) = default;
|
||||||
|
web_seed_t(web_seed_t const&) = default;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXTRA_EXPORT torrent_hot_members
|
struct TORRENT_EXTRA_EXPORT torrent_hot_members
|
||||||
|
|
|
@ -201,6 +201,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
ipv4_peer(tcp::endpoint const& ip, bool connectable, int src);
|
ipv4_peer(tcp::endpoint const& ip, bool connectable, int src);
|
||||||
ipv4_peer(ipv4_peer const& p);
|
ipv4_peer(ipv4_peer const& p);
|
||||||
|
ipv4_peer& operator=(ipv4_peer const& p);
|
||||||
|
|
||||||
address_v4 addr;
|
address_v4 addr;
|
||||||
};
|
};
|
||||||
|
@ -209,7 +210,7 @@ namespace libtorrent
|
||||||
struct TORRENT_EXTRA_EXPORT i2p_peer : torrent_peer
|
struct TORRENT_EXTRA_EXPORT i2p_peer : torrent_peer
|
||||||
{
|
{
|
||||||
i2p_peer(char const* destination, bool connectable, int src);
|
i2p_peer(char const* destination, bool connectable, int src);
|
||||||
i2p_peer(const i2p_peer&);
|
i2p_peer(i2p_peer const&);
|
||||||
~i2p_peer();
|
~i2p_peer();
|
||||||
i2p_peer& operator=(i2p_peer const&);
|
i2p_peer& operator=(i2p_peer const&);
|
||||||
|
|
||||||
|
@ -221,6 +222,7 @@ namespace libtorrent
|
||||||
struct TORRENT_EXTRA_EXPORT ipv6_peer : torrent_peer
|
struct TORRENT_EXTRA_EXPORT ipv6_peer : torrent_peer
|
||||||
{
|
{
|
||||||
ipv6_peer(tcp::endpoint const& ip, bool connectable, int src);
|
ipv6_peer(tcp::endpoint const& ip, bool connectable, int src);
|
||||||
|
ipv6_peer(ipv6_peer const& p);
|
||||||
|
|
||||||
const address_v6::bytes_type addr;
|
const address_v6::bytes_type addr;
|
||||||
};
|
};
|
||||||
|
@ -229,7 +231,7 @@ namespace libtorrent
|
||||||
struct peer_address_compare
|
struct peer_address_compare
|
||||||
{
|
{
|
||||||
bool operator()(
|
bool operator()(
|
||||||
torrent_peer const* lhs, libtorrent::address const& rhs) const
|
torrent_peer const* lhs, libtorrent::address const& rhs) const
|
||||||
{
|
{
|
||||||
return lhs->address() < rhs;
|
return lhs->address() < rhs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "make_proxy_settings.hpp"
|
#include "make_proxy_settings.hpp"
|
||||||
#include "simulator/utils.hpp"
|
#include "simulator/utils.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
using namespace sim;
|
using namespace sim;
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
@ -105,7 +106,8 @@ add_torrent_params create_torrent(file_storage& fs, bool const pad_files = false
|
||||||
template <typename Setup, typename HandleAlerts, typename Test>
|
template <typename Setup, typename HandleAlerts, typename Test>
|
||||||
void run_test(Setup const& setup
|
void run_test(Setup const& setup
|
||||||
, HandleAlerts const& on_alert
|
, HandleAlerts const& on_alert
|
||||||
, Test const& test)
|
, Test const& test
|
||||||
|
, lt::seconds const timeout = lt::seconds{100})
|
||||||
{
|
{
|
||||||
// setup the simulation
|
// setup the simulation
|
||||||
sim::default_config network_cfg;
|
sim::default_config network_cfg;
|
||||||
|
@ -127,7 +129,7 @@ void run_test(Setup const& setup
|
||||||
|
|
||||||
// set up a timer to fire later, to verify everything we expected to happen
|
// set up a timer to fire later, to verify everything we expected to happen
|
||||||
// happened
|
// happened
|
||||||
sim::timer t(sim, lt::seconds(100), [&](boost::system::error_code const& ec)
|
sim::timer t(sim, timeout, [&](boost::system::error_code const& ec)
|
||||||
{
|
{
|
||||||
std::printf("shutting down\n");
|
std::printf("shutting down\n");
|
||||||
// shut down
|
// shut down
|
||||||
|
@ -572,3 +574,65 @@ TORRENT_TEST(no_close_redudant_webseed)
|
||||||
|
|
||||||
TEST_CHECK(expected);
|
TEST_CHECK(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure the max_web_seed_connections limit is honored
|
||||||
|
TORRENT_TEST(web_seed_connection_limit)
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
file_storage fs;
|
||||||
|
fs.add_file("file1", 1);
|
||||||
|
lt::add_torrent_params params = ::create_torrent(fs);
|
||||||
|
params.url_seeds.push_back("http://2.2.2.1:8080/");
|
||||||
|
params.url_seeds.push_back("http://2.2.2.2:8080/");
|
||||||
|
params.url_seeds.push_back("http://2.2.2.3:8080/");
|
||||||
|
params.url_seeds.push_back("http://2.2.2.4:8080/");
|
||||||
|
|
||||||
|
std::array<int, 4> expected = {};
|
||||||
|
run_test(
|
||||||
|
[¶ms](lt::session& ses)
|
||||||
|
{
|
||||||
|
lt::settings_pack pack;
|
||||||
|
pack.set_int(settings_pack::max_web_seed_connections, 2);
|
||||||
|
ses.apply_settings(pack);
|
||||||
|
ses.async_add_torrent(params);
|
||||||
|
},
|
||||||
|
[](lt::session& ses, lt::alert const* alert) {},
|
||||||
|
[&expected](sim::simulation& sim, lt::session& ses)
|
||||||
|
{
|
||||||
|
using ios = sim::asio::io_service;
|
||||||
|
ios web_server1{sim, address_v4::from_string("2.2.2.1")};
|
||||||
|
ios web_server2{sim, address_v4::from_string("2.2.2.2")};
|
||||||
|
ios web_server3{sim, address_v4::from_string("2.2.2.3")};
|
||||||
|
ios web_server4{sim, address_v4::from_string("2.2.2.4")};
|
||||||
|
|
||||||
|
// listen on port 8080
|
||||||
|
using ws = sim::http_server;
|
||||||
|
ws http1{web_server1, 8080};
|
||||||
|
ws http2{web_server2, 8080};
|
||||||
|
ws http3{web_server3, 8080};
|
||||||
|
ws http4{web_server4, 8080};
|
||||||
|
|
||||||
|
auto const handler = [&expected](std::string method, std::string req
|
||||||
|
, std::map<std::string, std::string>&, int idx)
|
||||||
|
{
|
||||||
|
++expected[idx];
|
||||||
|
// deliberately avoid sending the content, to cause a hang
|
||||||
|
return sim::send_response(206, "Partial Content", 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
using namespace std::placeholders;
|
||||||
|
http1.register_handler("/file1", std::bind(handler, _1, _2, _3, 0));
|
||||||
|
http2.register_handler("/file1", std::bind(handler, _1, _2, _3, 1));
|
||||||
|
http3.register_handler("/file1", std::bind(handler, _1, _2, _3, 2));
|
||||||
|
http4.register_handler("/file1", std::bind(handler, _1, _2, _3, 3));
|
||||||
|
|
||||||
|
sim.run();
|
||||||
|
},
|
||||||
|
lt::seconds(15)
|
||||||
|
);
|
||||||
|
|
||||||
|
// make sure we only connected to 2 of the web seeds, since that's the limit
|
||||||
|
TEST_CHECK(std::accumulate(expected.begin(), expected.end(), 0) == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -334,6 +334,7 @@ namespace libtorrent
|
||||||
SET(urlseed_max_request_bytes, 16 * 1024 * 1024, 0),
|
SET(urlseed_max_request_bytes, 16 * 1024 * 1024, 0),
|
||||||
SET(web_seed_name_lookup_retry, 1800, nullptr),
|
SET(web_seed_name_lookup_retry, 1800, nullptr),
|
||||||
SET(close_file_interval, CLOSE_FILE_INTERVAL, &session_impl::update_close_file_interval),
|
SET(close_file_interval, CLOSE_FILE_INTERVAL, &session_impl::update_close_file_interval),
|
||||||
|
SET(max_web_seed_connections, 3, nullptr),
|
||||||
}});
|
}});
|
||||||
|
|
||||||
#undef SET
|
#undef SET
|
||||||
|
|
|
@ -250,10 +250,11 @@ namespace libtorrent
|
||||||
|
|
||||||
// if override web seed flag is set, don't load any web seeds from the
|
// if override web seed flag is set, don't load any web seeds from the
|
||||||
// torrent file.
|
// torrent file.
|
||||||
|
std::vector<web_seed_t> ws;
|
||||||
if ((p.flags & add_torrent_params::flag_override_web_seeds) == 0)
|
if ((p.flags & add_torrent_params::flag_override_web_seeds) == 0)
|
||||||
{
|
{
|
||||||
std::vector<web_seed_entry> const& web_seeds = m_torrent_file->web_seeds();
|
for (auto const& e : m_torrent_file->web_seeds())
|
||||||
m_web_seeds.insert(m_web_seeds.end(), web_seeds.begin(), web_seeds.end());
|
ws.emplace_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add web seeds from add_torrent_params
|
// add web seeds from add_torrent_params
|
||||||
|
@ -262,17 +263,18 @@ namespace libtorrent
|
||||||
|
|
||||||
for (auto const& u : p.url_seeds)
|
for (auto const& u : p.url_seeds)
|
||||||
{
|
{
|
||||||
m_web_seeds.push_back(web_seed_t(u, web_seed_entry::url_seed));
|
ws.emplace_back(web_seed_t(u, web_seed_entry::url_seed));
|
||||||
|
|
||||||
// correct URLs to end with a "/" for multi-file torrents
|
// correct URLs to end with a "/" for multi-file torrents
|
||||||
std::string& url = m_web_seeds.back().url;
|
std::string& url = ws.back().url;
|
||||||
if (multi_file && url[url.size()-1] != '/') url += '/';
|
if (multi_file && url[url.size()-1] != '/') url += '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& e : p.http_seeds)
|
for (auto const& e : p.http_seeds)
|
||||||
{
|
ws.push_back(web_seed_t(e, web_seed_entry::http_seed));
|
||||||
m_web_seeds.push_back(web_seed_t(e, web_seed_entry::http_seed));
|
|
||||||
}
|
aux::random_shuffle(ws.begin(), ws.end());
|
||||||
|
for (auto& w : ws) m_web_seeds.emplace_back(std::move(w));
|
||||||
|
|
||||||
// --- TRACKERS ---
|
// --- TRACKERS ---
|
||||||
|
|
||||||
|
@ -470,7 +472,9 @@ namespace libtorrent
|
||||||
|
|
||||||
// add the web seeds from the .torrent file
|
// add the web seeds from the .torrent file
|
||||||
std::vector<web_seed_entry> const& web_seeds = m_torrent_file->web_seeds();
|
std::vector<web_seed_entry> const& web_seeds = m_torrent_file->web_seeds();
|
||||||
m_web_seeds.insert(m_web_seeds.end(), web_seeds.begin(), web_seeds.end());
|
std::vector<web_seed_t> ws(web_seeds.begin(), web_seeds.end());
|
||||||
|
aux::random_shuffle(ws.begin(), ws.end());
|
||||||
|
for (auto& w : ws) m_web_seeds.push_back(std::move(w));
|
||||||
|
|
||||||
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
||||||
static char const req2[4] = {'r', 'e', 'q', '2'};
|
static char const req2[4] = {'r', 'e', 'q', '2'};
|
||||||
|
@ -8897,28 +8901,45 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
catch (...) { handle_exception(); }
|
catch (...) { handle_exception(); }
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int zero_or(int const val, int const def_val)
|
||||||
|
{ return (val <= 0) ? def_val : val; }
|
||||||
|
}
|
||||||
|
|
||||||
void torrent::maybe_connect_web_seeds()
|
void torrent::maybe_connect_web_seeds()
|
||||||
{
|
{
|
||||||
if (m_abort) return;
|
if (m_abort) return;
|
||||||
|
|
||||||
// if we have everything we want we don't need to connect to any web-seed
|
// if we have everything we want we don't need to connect to any web-seed
|
||||||
if (!is_finished() && !m_web_seeds.empty() && m_files_checked
|
if (m_web_seeds.empty()
|
||||||
&& num_peers() < int(m_max_connections)
|
|| is_finished()
|
||||||
&& m_ses.num_connections() < settings().get_int(settings_pack::connections_limit))
|
|| !m_files_checked
|
||||||
|
|| num_peers() >= int(m_max_connections)
|
||||||
|
|| m_ses.num_connections() >= settings().get_int(settings_pack::connections_limit))
|
||||||
{
|
{
|
||||||
// keep trying web-seeds if there are any
|
return;
|
||||||
// first find out which web seeds we are connected to
|
}
|
||||||
for (std::list<web_seed_t>::iterator i = m_web_seeds.begin();
|
|
||||||
i != m_web_seeds.end();)
|
|
||||||
{
|
|
||||||
std::list<web_seed_t>::iterator w = i++;
|
|
||||||
if (w->peer_info.connection) continue;
|
|
||||||
if (w->retry > aux::time_now()) continue;
|
|
||||||
if (w->resolving) continue;
|
|
||||||
if (w->removed) continue;
|
|
||||||
|
|
||||||
connect_to_url_seed(w);
|
// when set to unlimited, use 100 as the limit
|
||||||
}
|
int limit = zero_or(settings().get_int(settings_pack::max_web_seed_connections)
|
||||||
|
, 100);
|
||||||
|
|
||||||
|
auto const now = aux::time_now();
|
||||||
|
|
||||||
|
// keep trying web-seeds if there are any
|
||||||
|
// first find out which web seeds we are connected to
|
||||||
|
for (std::list<web_seed_t>::iterator i = m_web_seeds.begin();
|
||||||
|
i != m_web_seeds.end() && limit > 0;)
|
||||||
|
{
|
||||||
|
std::list<web_seed_t>::iterator w = i++;
|
||||||
|
if (w->removed || w->retry > now)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
--limit;
|
||||||
|
if (w->peer_info.connection || w->resolving)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
connect_to_url_seed(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,6 +241,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
ipv4_peer::ipv4_peer(ipv4_peer const&) = default;
|
ipv4_peer::ipv4_peer(ipv4_peer const&) = default;
|
||||||
|
ipv4_peer& ipv4_peer::operator=(ipv4_peer const& p) = default;
|
||||||
|
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
i2p_peer::i2p_peer(char const* dest, bool connectable, int src)
|
i2p_peer::i2p_peer(char const* dest, bool connectable, int src)
|
||||||
|
@ -282,6 +283,8 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipv6_peer::ipv6_peer(ipv6_peer const&) = default;
|
||||||
|
|
||||||
#endif // TORRENT_USE_IPV6
|
#endif // TORRENT_USE_IPV6
|
||||||
|
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
|
|
Loading…
Reference in New Issue