Range-check global throttle rates before narrowing them to kB.

Multiplying kB back to bytes in unsigned int wrapped 2^32 to 0, which means unlimited.
This commit is contained in:
xirvik
2026-09-19 00:55:27 +00:00
committed by Jari Sundell
parent 05cdd03cd2
commit 83b03c2c1e
5 changed files with 151 additions and 8 deletions
+22 -4
View File
@@ -89,6 +89,24 @@ throttle_update(const char* variable, int64_t value) {
return torrent::Object();
}
static unsigned int
throttle_rate_to_kb(int64_t rate) {
if (rate < 0 || rate > std::numeric_limits<unsigned int>::max() - 1)
throw torrent::input_error("Throttle rate must be between 0 and 4294967294.");
return static_cast<unsigned int>(rate >> 10);
}
static void
set_up_throttle_i64(ui::Root* root, int64_t rate) {
root->set_up_throttle(throttle_rate_to_kb(rate));
}
static void
set_down_throttle_i64(ui::Root* root, int64_t rate) {
root->set_down_throttle(throttle_rate_to_kb(rate));
}
void
initialize_command_throttle() {
CMD2_ANY ("throttle.unchoked_uploads", std::bind(&torrent::ResourceManager::currently_upload_unchoked, torrent::resource_manager()));
@@ -125,13 +143,13 @@ initialize_command_throttle() {
CMD2_ANY ("throttle.global_up.rate", std::bind(&torrent::Rate::rate, torrent::up_rate()));
CMD2_ANY ("throttle.global_up.total", std::bind(&torrent::Rate::total, torrent::up_rate()));
CMD2_ANY ("throttle.global_up.max_rate", std::bind(&torrent::Throttle::max_rate, torrent::up_throttle_global()));
CMD2_ANY_VALUE_V ("throttle.global_up.max_rate.set", std::bind(&ui::Root::set_up_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY_VALUE_KB("throttle.global_up.max_rate.set_kb", std::bind(&ui::Root::set_up_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY_VALUE_V ("throttle.global_up.max_rate.set", std::bind(&set_up_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY_VALUE_KB("throttle.global_up.max_rate.set_kb", std::bind(&set_up_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY ("throttle.global_down.rate", std::bind(&torrent::Rate::rate, torrent::down_rate()));
CMD2_ANY ("throttle.global_down.total", std::bind(&torrent::Rate::total, torrent::down_rate()));
CMD2_ANY ("throttle.global_down.max_rate", std::bind(&torrent::Throttle::max_rate, torrent::down_throttle_global()));
CMD2_ANY_VALUE_V ("throttle.global_down.max_rate.set", std::bind(&ui::Root::set_down_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY_VALUE_KB("throttle.global_down.max_rate.set_kb", std::bind(&ui::Root::set_down_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY_VALUE_V ("throttle.global_down.max_rate.set", std::bind(&set_down_throttle_i64, control->ui(), std::placeholders::_2));
CMD2_ANY_VALUE_KB("throttle.global_down.max_rate.set_kb", std::bind(&set_down_throttle_i64, control->ui(), std::placeholders::_2));
// Temporary names, need to change this to accept real rates rather
// than kB.
-4
View File
@@ -70,10 +70,6 @@ public:
void set_down_throttle(unsigned int throttle);
void set_up_throttle(unsigned int throttle);
// Rename to raw or something, make base function.
void set_down_throttle_i64(int64_t throttle) { set_down_throttle(throttle >> 10); }
void set_up_throttle_i64(int64_t throttle) { set_up_throttle(throttle >> 10); }
void adjust_down_throttle(int throttle);
void adjust_up_throttle(int throttle);
+2
View File
@@ -67,6 +67,8 @@ rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
src/test_command_path.h \
src/test_command_string.cc \
src/test_command_string.h \
src/test_command_throttle.cc \
src/test_command_throttle.h \
src/test_setup.cc \
src/test_setup.h \
src/test_ui_download_list.cc \
+102
View File
@@ -0,0 +1,102 @@
#include "config.h"
#include "test/src/test_command_throttle.h"
#include <torrent/throttle.h>
#include <torrent/torrent.h>
#include "core/manager.h"
#include "control.h"
#include "globals.h"
#include "rpc/parse_commands.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandThrottle);
void initialize_command_throttle();
static void
call_set(const char* key, const char* value) {
rpc::commands.call_command(key, torrent::Object(std::string(value)));
}
static void
call_named(const char* key, const char* name, const char* value) {
torrent::Object::list_type args;
args.push_back(torrent::Object(std::string(name)));
args.push_back(torrent::Object(std::string(value)));
rpc::commands.call_command(key, torrent::Object::create_list_range(args.begin(), args.end()));
}
static uint64_t
down_rate() {
return torrent::down_throttle_global()->max_rate();
}
void
TestCommandThrottle::setUp() {
torrent::initialize_main_thread();
torrent::initialize();
if (control == nullptr)
control = new Control;
if (!rpc::commands.has("throttle.global_down.max_rate.set_kb"))
initialize_command_throttle();
}
void
TestCommandThrottle::tearDown() {
torrent::cleanup();
}
void
TestCommandThrottle::test_global_rate_in_range() {
call_set("throttle.global_down.max_rate.set_kb", "1024");
CPPUNIT_ASSERT_EQUAL(uint64_t{1048576}, down_rate());
call_set("throttle.global_down.max_rate.set_kb", "4194303");
CPPUNIT_ASSERT_EQUAL(uint64_t{4294966272}, down_rate());
call_set("throttle.global_down.max_rate.set", "4294966272");
CPPUNIT_ASSERT_EQUAL(uint64_t{4294966272}, down_rate());
}
void
TestCommandThrottle::test_global_rate_kb_out_of_range() {
call_set("throttle.global_down.max_rate.set_kb", "1024");
CPPUNIT_ASSERT_THROW(call_set("throttle.global_down.max_rate.set_kb", "4194304"), torrent::input_error);
CPPUNIT_ASSERT_EQUAL(uint64_t{1048576}, down_rate());
}
void
TestCommandThrottle::test_global_rate_bytes_out_of_range() {
call_set("throttle.global_down.max_rate.set", "1048576");
CPPUNIT_ASSERT_THROW(call_set("throttle.global_down.max_rate.set", "4294967296"), torrent::input_error);
CPPUNIT_ASSERT_EQUAL(uint64_t{1048576}, down_rate());
}
void
TestCommandThrottle::test_global_rate_negative() {
call_set("throttle.global_down.max_rate.set", "1048576");
CPPUNIT_ASSERT_THROW(call_set("throttle.global_down.max_rate.set", "-1"), torrent::input_error);
CPPUNIT_ASSERT_EQUAL(uint64_t{1048576}, down_rate());
}
void
TestCommandThrottle::test_named_rate_in_range() {
call_named("throttle.down", "test_named_in_range", "1024");
auto itr = control->core()->throttles().find("test_named_in_range");
CPPUNIT_ASSERT(itr != control->core()->throttles().end());
CPPUNIT_ASSERT_EQUAL(uint64_t{1048576}, itr->second.second->max_rate());
}
void
TestCommandThrottle::test_named_rate_out_of_range() {
CPPUNIT_ASSERT_THROW(call_named("throttle.down", "test_named_out_of_range", "18014398509481984"), torrent::input_error);
}
+25
View File
@@ -0,0 +1,25 @@
#include "test/helpers/test_fixture.h"
class TestCommandThrottle : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommandThrottle);
CPPUNIT_TEST(test_global_rate_in_range);
CPPUNIT_TEST(test_global_rate_kb_out_of_range);
CPPUNIT_TEST(test_global_rate_bytes_out_of_range);
CPPUNIT_TEST(test_global_rate_negative);
CPPUNIT_TEST(test_named_rate_in_range);
CPPUNIT_TEST(test_named_rate_out_of_range);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void test_global_rate_in_range();
void test_global_rate_kb_out_of_range();
void test_global_rate_bytes_out_of_range();
void test_global_rate_negative();
void test_named_rate_in_range();
void test_named_rate_out_of_range();
};