mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-05 21:59:21 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1ce2febf0 | |||
| 5ebb7bd151 | |||
| 50f0cad0c6 | |||
| 3717649bb3 | |||
| c32b56e9d8 | |||
| de54a4c2ad | |||
| 26fdca8f4d | |||
| 00bcdaee23 | |||
| 3787dbe7f3 |
+3
-3
@@ -1,6 +1,6 @@
|
||||
m4_pattern_allow([PKG_CHECK_EXISTS])
|
||||
|
||||
AC_INIT([rtorrent],[0.16.22],[sundell.software@gmail.com])
|
||||
AC_INIT([rtorrent],[0.16.23],[sundell.software@gmail.com])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIRS([scripts])
|
||||
@@ -14,7 +14,7 @@ AX_CXX_COMPILE_STDCXX(20, noext, mandatory)
|
||||
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
AC_DEFINE([API_VERSION], [26], [api version])
|
||||
AC_DEFINE([API_VERSION], [27], [api version])
|
||||
|
||||
RAK_CHECK_CFLAGS
|
||||
RAK_CHECK_CXXFLAGS
|
||||
@@ -49,7 +49,7 @@ fi
|
||||
|
||||
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
|
||||
PKG_CHECK_MODULES([ZLIB], [zlib])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.22])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.23])
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
TORRENT_WITH_XMLRPC_C
|
||||
|
||||
@@ -431,6 +431,9 @@ p_call_target(const torrent::Object::list_type& args) {
|
||||
const std::string& peer_id = itr++->as_string();
|
||||
const std::string& command_key = itr++->as_string();
|
||||
|
||||
if (download == nullptr)
|
||||
throw torrent::input_error("invalid parameters: info-hash not found");
|
||||
|
||||
torrent::HashString hash;
|
||||
|
||||
if (peer_id.size() != 40)
|
||||
|
||||
@@ -157,7 +157,7 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) {
|
||||
torrent::Object valueList = torrent::Object::create_list();
|
||||
torrent::Object::list_type& valueListType = valueList.as_list();
|
||||
|
||||
if ((itrArgs)->is_list())
|
||||
if (itrArgs != args.end() && (itrArgs)->is_list())
|
||||
valueListType = (itrArgs)->as_list();
|
||||
|
||||
control->object_storage()->insert_str(raw_key, valueList, flags);
|
||||
|
||||
@@ -319,6 +319,11 @@ apply_ipv4_filter_load(const torrent::Object::list_type& args) {
|
||||
ipv4_filter_parse(buffer, value);
|
||||
}
|
||||
|
||||
if (file.fail() && !file.eof()) {
|
||||
lineNumber++;
|
||||
throw torrent::input_error("Exceeded max line length.");
|
||||
}
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
snprintf(buffer, 2048, "Error in ip filter file: %s:%u: %s", filename.c_str(), lineNumber, e.what());
|
||||
|
||||
|
||||
+2
-2
@@ -216,7 +216,7 @@ View::set_not_visible(Download* download) {
|
||||
|
||||
void
|
||||
View::next_focus(unsigned int i) {
|
||||
if (empty())
|
||||
if (empty_visible())
|
||||
return;
|
||||
|
||||
// If at the boundary, roll over
|
||||
@@ -239,7 +239,7 @@ View::next_focus(unsigned int i) {
|
||||
|
||||
void
|
||||
View::prev_focus(unsigned int i) {
|
||||
if (empty())
|
||||
if (empty_visible())
|
||||
return;
|
||||
|
||||
// If at the boundary, roll over
|
||||
|
||||
@@ -25,7 +25,10 @@ WindowFileList::WindowFileList(const ui::ElementFileList* element) :
|
||||
// Convert std::string to std::wstring of given width (in screen positions),
|
||||
// taking into account that some characters may be occupying two screen positions.
|
||||
std::wstring
|
||||
wstring_width(const std::string& i_str, [[maybe_unused]] int width) {
|
||||
wstring_width(const std::string& i_str, int width) {
|
||||
if (width < 0)
|
||||
width = 0;
|
||||
|
||||
std::wstring result(width + 1, L' ');
|
||||
size_t length = std::mbstowcs(result.data(), i_str.c_str(), width);
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace input {
|
||||
|
||||
void
|
||||
InputEvent::insert() {
|
||||
torrent::this_thread::poll()->open_and_insert_read(this);
|
||||
torrent::this_thread::poll()->open(this);
|
||||
torrent::this_thread::poll()->insert_read(this);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+15
-16
@@ -112,9 +112,8 @@ main(int argc, char** argv) {
|
||||
|
||||
torrent::log_initialize();
|
||||
|
||||
torrent::runtime::initialize_worker_process_and_main_thread([argc, argv]() {
|
||||
parse_config_file(argc, argv, [](auto& path) { parse_config_file_comments("worker", path); });
|
||||
});
|
||||
// TODO: Create a fake thread object for initializing other processes and enabling logging.
|
||||
torrent::initialize_main_thread();
|
||||
|
||||
// Block SIGCHLD until all threads are created, then unblock on main-thread, to avoid SIGCHLD
|
||||
// interrupting other threads.
|
||||
@@ -126,9 +125,9 @@ main(int argc, char** argv) {
|
||||
SignalHandler::set_block(SIGCHLD);
|
||||
|
||||
// All signal handlers must restore errno if they return.
|
||||
SignalHandler::set_handler(SIGSEGV, []() { do_panic(SIGSEGV); });
|
||||
SignalHandler::set_handler(SIGILL, []() { do_panic(SIGILL); });
|
||||
SignalHandler::set_handler(SIGFPE, []() { do_panic(SIGFPE); });
|
||||
SignalHandler::set_handler(SIGSEGV, std::bind(&do_panic, SIGSEGV));
|
||||
SignalHandler::set_handler(SIGILL, std::bind(&do_panic, SIGILL));
|
||||
SignalHandler::set_handler(SIGFPE, std::bind(&do_panic, SIGFPE));
|
||||
|
||||
// Limited list of commands with the following format:
|
||||
//
|
||||
@@ -137,17 +136,19 @@ main(int argc, char** argv) {
|
||||
// # do:log.open_file=system,/usr/rakshasa/system.log
|
||||
// # do:log.add_output=system,system
|
||||
//
|
||||
// # do-worker:log.open_file=system,/usr/rakshasa/system-worker.log
|
||||
// # do-worker:log.add_output=system,system
|
||||
//
|
||||
parse_config_file(argc, argv, [](auto& path) { parse_config_file_comments("", path); });
|
||||
parse_config_file(argc, argv, [](auto& path) {
|
||||
if (path.empty())
|
||||
return;
|
||||
|
||||
parse_config_file_comments(path);
|
||||
});
|
||||
|
||||
control = new Control;
|
||||
|
||||
SignalHandler::set_handler(SIGINT, []() { control->receive_normal_shutdown(); });
|
||||
SignalHandler::set_handler(SIGHUP, []() { control->receive_normal_shutdown(); });
|
||||
SignalHandler::set_handler(SIGTERM, []() { control->receive_quick_shutdown(); });
|
||||
SignalHandler::set_handler(SIGWINCH, []() { control->display()->force_redraw(); });
|
||||
SignalHandler::set_handler(SIGINT, std::bind(&Control::receive_normal_shutdown, control));
|
||||
SignalHandler::set_handler(SIGHUP, std::bind(&Control::receive_normal_shutdown, control));
|
||||
SignalHandler::set_handler(SIGTERM, std::bind(&Control::receive_quick_shutdown, control));
|
||||
SignalHandler::set_handler(SIGWINCH, std::bind(&display::Manager::force_redraw, control->display()));
|
||||
|
||||
SignalHandler::set_sigaction_handler(SIGBUS, &handle_sigbus);
|
||||
|
||||
@@ -468,8 +469,6 @@ main(int argc, char** argv) {
|
||||
control->ui()->load_input_history();
|
||||
|
||||
torrent::net_thread::http_stack()->set_user_agent(USER_AGENT);
|
||||
|
||||
torrent::runtime::initialize_worker_process();
|
||||
torrent::runtime::initialize_network();
|
||||
|
||||
// Load session torrents and perform scheduled tasks to ensure session torrents are loaded
|
||||
|
||||
@@ -108,6 +108,6 @@ OptionParser::call_int_pair(slot_int_pair slot, const std::string& arg) {
|
||||
|
||||
if (a < 0 || b < 0)
|
||||
throw std::runtime_error("Invalid argument, \"" + arg + "\" should be positive numbers");
|
||||
|
||||
|
||||
slot(a, b);
|
||||
}
|
||||
|
||||
@@ -61,14 +61,20 @@ CommandScheduler::call_item(value_type item) {
|
||||
// Remove the item before calling the command if it should be
|
||||
// removed.
|
||||
|
||||
std::string key = item->key();
|
||||
|
||||
try {
|
||||
rpc::call_object(item->command());
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
if (m_slotErrorMessage)
|
||||
m_slotErrorMessage("Scheduled command failed: " + item->key() + ": " + e.what());
|
||||
m_slotErrorMessage("Scheduled command failed: " + key + ": " + e.what());
|
||||
}
|
||||
|
||||
// The command is allowed to erase or replace this item, which deletes it.
|
||||
if (std::find(begin(), end(), item) == end())
|
||||
return;
|
||||
|
||||
// Still schedule if we caught a torrrent::input_error?
|
||||
auto next = item->next_time_scheduled();
|
||||
|
||||
|
||||
@@ -181,6 +181,11 @@ parse_command_file(const std::string& path) {
|
||||
getCount = 0;
|
||||
}
|
||||
|
||||
if (file.fail() && !file.eof()) {
|
||||
lineNumber++;
|
||||
throw torrent::input_error("Exceeded max line length.");
|
||||
}
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
snprintf(buffer, 2048, "Error in option file: %s:%u: %s", path.c_str(), lineNumber, e.what());
|
||||
|
||||
|
||||
+2
-1
@@ -109,7 +109,8 @@ void
|
||||
SCgi::activate() {
|
||||
assert(torrent::this_thread::thread() == scgi_thread::thread());
|
||||
|
||||
torrent::this_thread::poll()->open_and_insert_read(this);
|
||||
torrent::this_thread::poll()->open(this);
|
||||
torrent::this_thread::poll()->insert_read(this);
|
||||
}
|
||||
|
||||
// TODO: This should close the fd to avoid reuse.
|
||||
|
||||
@@ -50,7 +50,8 @@ SCgiTask::open(SCgi* parent, int fd) {
|
||||
// m_trusted=false into the next reuse, given that the
|
||||
// UNTRUSTED_CONNECTION=0 parse branch is a no-op.
|
||||
|
||||
torrent::this_thread::poll()->open_and_insert_read(this);
|
||||
torrent::this_thread::poll()->open(this);
|
||||
torrent::this_thread::poll()->insert_read(this);
|
||||
|
||||
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&m_task_timeout, timeout_request);
|
||||
|
||||
|
||||
+4
-5
@@ -44,10 +44,9 @@ xmlrpc_list_entry_to_object(xmlrpc_env* env, xmlrpc_value* src, int index) {
|
||||
if (env->fault_occurred)
|
||||
throw xmlrpc_error_c(env);
|
||||
|
||||
torrent::Object obj = xmlrpc_to_object(env, tmp);
|
||||
xmlrpc_DECREF(tmp);
|
||||
utils::scope_guard guard([tmp]() { xmlrpc_DECREF(tmp); });
|
||||
|
||||
return obj;
|
||||
return xmlrpc_to_object(env, tmp);
|
||||
}
|
||||
|
||||
int64_t
|
||||
@@ -213,11 +212,11 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int call_type, rpc::targe
|
||||
if (env->fault_occurred)
|
||||
throw xmlrpc_error_c(env);
|
||||
|
||||
utils::scope_guard guard([tmp]() { xmlrpc_DECREF(tmp); });
|
||||
|
||||
if (target != nullptr)
|
||||
std::tie(*target, *deleter) = xmlrpc_to_target(env, tmp, call_type);
|
||||
|
||||
xmlrpc_DECREF(tmp);
|
||||
|
||||
if (env->fault_occurred)
|
||||
throw xmlrpc_error_c(env);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "rpc/tinyxml2/tinyxml2.h"
|
||||
#include "rpc/rpc_manager.h"
|
||||
#include "utils/base64.h"
|
||||
#include "utils/functional.h"
|
||||
#include "xmlrpc.h"
|
||||
|
||||
namespace rpc {
|
||||
@@ -258,6 +259,8 @@ execute_command(std::string method_name, const tinyxml2::XMLElement* params_elem
|
||||
torrent::Object params_raw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& params = params_raw.as_list();
|
||||
rpc::target_type target = rpc::make_target();
|
||||
std::function<void()> deleter = []() {};
|
||||
utils::scope_guard guard([&deleter]() { deleter(); });
|
||||
|
||||
if (params_element != nullptr) {
|
||||
if (std::strncmp(params_element->Name(), "params", sizeof("params")) == 0) {
|
||||
@@ -265,8 +268,6 @@ execute_command(std::string method_name, const tinyxml2::XMLElement* params_elem
|
||||
const auto* child = params_element->FirstChildElement("param");
|
||||
|
||||
if (child != nullptr) {
|
||||
std::function<void()> deleter = []() {};
|
||||
|
||||
RpcManager::object_to_target(xml_value_to_object(child->FirstChildElement("value")), cmd_itr->second.m_flags, &target, &deleter);
|
||||
child = child->NextSiblingElement("param");
|
||||
|
||||
@@ -282,8 +283,6 @@ execute_command(std::string method_name, const tinyxml2::XMLElement* params_elem
|
||||
const auto* child = params_element->FirstChildElement("data")->FirstChildElement("value");
|
||||
|
||||
if (child != nullptr) {
|
||||
std::function<void()> deleter = []() {};
|
||||
|
||||
RpcManager::object_to_target(xml_value_to_object(child), cmd_itr->second.m_flags, &target, &deleter);
|
||||
child = child->NextSiblingElement("value");
|
||||
|
||||
|
||||
+5
-9
@@ -108,22 +108,18 @@ config_comment_log(const std::string& command, const std::string& raw_args) {
|
||||
throw torrent::input_error("Unknown log command: " + command);
|
||||
}
|
||||
|
||||
// Call special commands in the format "# do:command=args" or "# do-<category>:command=args" in the config file.
|
||||
// Call special commands in the format "# do:command=args" in the config file.
|
||||
void
|
||||
parse_config_file_comments(const std::string& category, const std::string& path) {
|
||||
if (path.empty())
|
||||
return;
|
||||
|
||||
parse_config_file_comments(const std::string& path) {
|
||||
std::fstream file(path, std::ios::in);
|
||||
|
||||
if (!file.is_open())
|
||||
return;
|
||||
|
||||
std::string line;
|
||||
std::string prefix = category.empty() ? "# do:" : "# do-" + category + ":";
|
||||
|
||||
while (std::getline(file, line)) {
|
||||
if (line.size() <= prefix.size() || line.compare(0, prefix.size(), prefix) != 0)
|
||||
if (line.size() <= 5 || line.compare(0, 5, "# do:") != 0)
|
||||
continue;
|
||||
|
||||
auto equal_pos = line.find('=');
|
||||
@@ -131,8 +127,8 @@ parse_config_file_comments(const std::string& category, const std::string& path)
|
||||
if (equal_pos == std::string::npos)
|
||||
throw torrent::input_error("Invalid command in config file comment: " + line);
|
||||
|
||||
auto command = line.substr(prefix.size(), equal_pos - prefix.size());
|
||||
auto args = line.substr(equal_pos + 1);
|
||||
std::string command = line.substr(5, equal_pos - 5);
|
||||
std::string args = line.substr(equal_pos + 1);
|
||||
|
||||
if (command.empty())
|
||||
throw torrent::input_error("Invalid command in config file comment: " + line);
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
int parse_main_options(int argc, char** argv);
|
||||
void parse_config_file(int argc, char** argv, std::function<void (const std::string&)> parse_fn);
|
||||
void parse_config_file_comments(const std::string& category, const std::string& path);
|
||||
void parse_config_file_comments(const std::string& path);
|
||||
|
||||
void load_session_torrents(const std::string& path);
|
||||
void load_arg_torrents(char** first, char** last);
|
||||
|
||||
@@ -61,3 +61,24 @@ TestCommandDynamic::test_old_style() {
|
||||
rpc::commands.call_command("method.insert", rpc::create_object_list("test_old_style.4", "simple", "cat=test.3"));
|
||||
CPPUNIT_ASSERT(rpc::commands.call_command("test_old_style.4", torrent::Object()).as_string() == "test.3");
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandDynamic::test_insert_list() {
|
||||
torrent::Object key_only = torrent::Object::create_list();
|
||||
key_only.as_list().push_back("test_insert_list.1");
|
||||
|
||||
rpc::commands.call_command("method.insert.list", key_only);
|
||||
|
||||
torrent::Object result = rpc::commands.call_command("test_insert_list.1", torrent::Object());
|
||||
|
||||
CPPUNIT_ASSERT(result.is_list());
|
||||
CPPUNIT_ASSERT(result.as_list().empty());
|
||||
|
||||
rpc::commands.call_command("method.insert.list",
|
||||
rpc::create_object_list("test_insert_list.2", rpc::create_object_list("a", "b")));
|
||||
|
||||
torrent::Object filled = rpc::commands.call_command("test_insert_list.2", torrent::Object());
|
||||
|
||||
CPPUNIT_ASSERT(filled.is_list());
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, filled.as_list().size());
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ class TestCommandDynamic : public test_fixture {
|
||||
CPPUNIT_TEST(test_basics);
|
||||
CPPUNIT_TEST(test_get_set);
|
||||
CPPUNIT_TEST(test_old_style);
|
||||
CPPUNIT_TEST(test_insert_list);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
@@ -18,6 +19,7 @@ public:
|
||||
void test_get_set();
|
||||
|
||||
void test_old_style();
|
||||
void test_insert_list();
|
||||
|
||||
private:
|
||||
std::unique_ptr<TestMainThread> m_test_main_thread;
|
||||
|
||||
Reference in New Issue
Block a user