diff --git a/simulation/test_swarm.cpp b/simulation/test_swarm.cpp index fc40f8021..47c246051 100644 --- a/simulation/test_swarm.cpp +++ b/simulation/test_swarm.cpp @@ -451,6 +451,107 @@ TORRENT_TEST(torrent_completed_alert) TEST_EQUAL(num_file_completed, 1); } +// template for testing running swarms with edge case settings +template +void test_settings(SettingsFun fun) +{ + setup_swarm(2, swarm_test::download + // add session + , fun + // add torrent + , [](lt::add_torrent_params& params) {} + // on alert + , [](lt::alert const* a, lt::session& ses) {} + // terminate + , [](int ticks, lt::session& ses) -> bool + { + if (ticks > 80) + { + TEST_ERROR("timeout"); + return true; + } + if (!is_seed(ses)) return false; + return true; + }); +} + +TORRENT_TEST(unlimited_connections) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_int(settings_pack::connections_limit, std::numeric_limits::max()); } + ); +} + +TORRENT_TEST(default_connections_limit) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_int(settings_pack::connections_limit, 0); } + ); +} + +TORRENT_TEST(redundant_have) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_bool(settings_pack::send_redundant_have, false); } + ); +} + +TORRENT_TEST(lazy_bitfields) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_bool(settings_pack::lazy_bitfields, true); } + ); +} + +TORRENT_TEST(prioritize_partial_pieces) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_bool(settings_pack::prioritize_partial_pieces, true); } + ); +} + +TORRENT_TEST(active_downloads) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_int(settings_pack::active_downloads, std::numeric_limits::max()); } + ); +} + +TORRENT_TEST(active_seeds) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_int(settings_pack::active_seeds, std::numeric_limits::max()); } + ); +} + +TORRENT_TEST(active_limit) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_int(settings_pack::active_limit, std::numeric_limits::max()); } + ); +} + +TORRENT_TEST(upload_rate_limit) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_int(settings_pack::upload_rate_limit, std::numeric_limits::max()); } + ); +} + +TORRENT_TEST(download_rate_limit) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_int(settings_pack::download_rate_limit, std::numeric_limits::max()); } + ); +} + +TORRENT_TEST(unchoke_slots_limit) +{ + test_settings([](lt::settings_pack& pack) { + pack.set_int(settings_pack::unchoke_slots_limit, std::numeric_limits::max()); } + ); +} + // TODO: add test that makes sure a torrent in graceful pause mode won't make // outgoing connections // TODO: add test that makes sure a torrent in graceful pause mode won't accept diff --git a/src/bandwidth_limit.cpp b/src/bandwidth_limit.cpp index ea1cd33fb..01d6f7f6b 100644 --- a/src/bandwidth_limit.cpp +++ b/src/bandwidth_limit.cpp @@ -50,7 +50,7 @@ namespace libtorrent TORRENT_ASSERT(limit < INT_MAX); m_limit = limit; } - + int bandwidth_channel::quota_left() const { if (m_limit == 0) return inf; @@ -60,12 +60,18 @@ namespace libtorrent void bandwidth_channel::update_quota(int dt_milliseconds) { if (m_limit == 0) return; - m_quota_left += (m_limit * dt_milliseconds + 500) / 1000; - if (m_quota_left > m_limit * 3) m_quota_left = m_limit * 3; + + // avoid integer overflow + if (m_limit >= std::numeric_limits::max() / dt_milliseconds) + { + m_quota_left = std::numeric_limits::max(); + } + else + { + m_quota_left += (m_limit * dt_milliseconds + 500) / 1000; + if (m_quota_left / 3 > m_limit) m_quota_left = m_limit * 3; + } distribute_quota = int((std::max)(m_quota_left, boost::int64_t(0))); -// fprintf(stderr, "%p: [%d]: + %"PRId64" limit: %"PRId64" quota_left: %"PRId64"\n", this -// , dt_milliseconds, (m_limit * dt_milliseconds + 500) / 1000, m_limit -// , m_quota_left); } // this is used when connections disconnect with @@ -85,8 +91,6 @@ namespace libtorrent TORRENT_ASSERT(m_limit >= 0); if (m_limit == 0) return; -// fprintf(stderr, "%p: - %"PRId64" limit: %"PRId64" quota_left: %"PRId64"\n", this -// , amount, m_limit, m_quota_left); m_quota_left -= amount; } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 713417aef..ae1b66555 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -3024,6 +3024,7 @@ retry: peer_class* pc = m_classes.at(c); if (pc == 0) return; if (limit <= 0) limit = 0; + else limit = std::min(limit, std::numeric_limits::max() - 1); pc->channel[channel].throttle(limit); } @@ -4148,8 +4149,9 @@ retry: // TODO: use a lower limit than m_settings.connections_limit // to allocate the to 10% or so of connection slots for incoming // connections - int limit = m_settings.get_int(settings_pack::connections_limit) - - num_connections(); + // cap this at max - 1, since we may add one below + int const limit = std::min(m_settings.get_int(settings_pack::connections_limit) + - num_connections(), std::numeric_limits::max() - 1); // this logic is here to smooth out the number of new connection // attempts over time, to prevent connecting a large number of diff --git a/test/test_bandwidth_limiter.cpp b/test/test_bandwidth_limiter.cpp index 1119511ea..097b16a7b 100644 --- a/test/test_bandwidth_limiter.cpp +++ b/test/test_bandwidth_limiter.cpp @@ -87,7 +87,7 @@ struct peer_connection: bandwidth_socket, boost::enable_shared_from_this