Compare commits

..

9 Commits

Author SHA1 Message Date
rakshasa ee64f8ea50 Merge branch 'master' into feature/ipc-worker 2026-08-09 13:13:20 +02:00
rakshasa bf1265d954 Stuff. 2026-08-09 10:44:29 +02:00
rakshasa 6c3c77a2b7 Stuff. 2026-08-07 11:58:33 +02:00
rakshasa 120fcb0273 Merge branch 'master' into feature/ipc-worker 2026-08-06 11:03:44 +02:00
rakshasa c36956813d Merge branch 'master' into feature/ipc-worker 2026-08-04 18:00:04 +02:00
rakshasa 05563b4c9b Stuff. 2026-07-28 10:56:25 +02:00
rakshasa a544f8ad68 Merge branch 'master' into feature/ipc-worker 2026-07-28 10:33:57 +02:00
rakshasa b35413ea71 Merge branch 'master' into feature/ipc-worker 2026-07-26 13:03:33 +02:00
rakshasa f9f19fb041 Stuff. 2026-07-26 09:14:39 +02:00
55 changed files with 565 additions and 1110 deletions
+3 -3
View File
@@ -1,6 +1,6 @@
m4_pattern_allow([PKG_CHECK_EXISTS])
AC_INIT([rtorrent],[0.16.21],[sundell.software@gmail.com])
AC_INIT([rtorrent],[0.16.20],[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], [25], [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.21])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.20])
AC_LANG_PUSH(C++)
TORRENT_WITH_XMLRPC_C
-8
View File
@@ -63,14 +63,6 @@
#network.local_address.set = 127.0.0.1
#network.local_address.set = rakshasa.no
# The port reported to the tracker, separate for ipv4/ipv6. A value of 0
# (the default) falls back to reporting the listening port. network.local_port.set
# sets both the ipv4 and ipv6 ports at once.
#
#network.local_port.set = 6881
#network.local_port.ipv4.set = 6881
#network.local_port.ipv6.set = 6882
# The IP address the listening socket and outgoing connections is
# bound to.
#
+2 -2
View File
@@ -53,8 +53,8 @@ rc.execute.throw(
cfg.watch..'/start'}))
-- Listening port for incoming peer traffic (fixed; you can also randomize it)
rc.network.listen.port.range = '50000-50000'
rc.network.listen.port.random = false
rc.network.port_range = '50000-50000'
rc.network.port_random = false
-- Tracker-less torrent and UDP tracker support
-- (conservative settings for 'private' trackers, change for 'public')
-2
View File
@@ -187,7 +187,6 @@ libsub_root_a_SOURCES = \
command_helpers.cc \
command_helpers.h \
command_groups.cc \
command_load.cc \
command_local.cc \
command_logging.cc \
command_network.cc \
@@ -196,7 +195,6 @@ libsub_root_a_SOURCES = \
command_tracker.cc \
command_scheduler.cc \
command_string.cc \
command_system.cc \
command_ui.cc \
control.cc \
control.h \
+18 -6
View File
@@ -142,6 +142,16 @@ apply_d_delete_tied(core::Download* download) {
return torrent::Object();
}
void
apply_d_directory(core::Download* download, const std::string& name) {
if (!download->file_list()->is_multi_file())
download->set_root_directory(name);
else if (name.empty() || *name.rbegin() == '/')
download->set_root_directory(name + download->info()->name().str());
else
download->set_root_directory(name + "/" + download->info()->name().str());
}
torrent::Object
apply_d_connection_type(core::Download* download, const std::string& name) {
torrent::Download::ConnectionType t =
@@ -708,7 +718,7 @@ initialize_command_download() {
CMD2_DL_V ("d.pause", std::bind(&core::DownloadList::pause_default, control->core()->download_list(), std::placeholders::_1));
CMD2_DL_V ("d.open", std::bind(&core::DownloadList::open_throw, control->core()->download_list(), std::placeholders::_1));
CMD2_DL_V ("d.close", std::bind(&core::DownloadList::close_throw, control->core()->download_list(), std::placeholders::_1));
CMD2_DL_V ("d.close.directly", std::bind(&core::DownloadList::close_files, control->core()->download_list(), std::placeholders::_1));
CMD2_DL_V ("d.close.directly", std::bind(&core::DownloadList::close_directly, control->core()->download_list(), std::placeholders::_1));
CMD2_DL_V ("d.erase", std::bind(&core::DownloadList::erase_ptr, control->core()->download_list(), std::placeholders::_1));
CMD2_DL_V ("d.check_hash", std::bind(&core::DownloadList::check_hash, control->core()->download_list(), std::placeholders::_1));
@@ -874,11 +884,12 @@ initialize_command_download() {
CMD2_DL_LIST ("d.tracker.insert", std::bind(&download_tracker_insert, std::placeholders::_1, std::placeholders::_2));
CMD2_DL_VALUE_V ("d.tracker.send_scrape", [](auto download, uint64_t arg) { download->tracker_controller().scrape_request(arg); });
CMD2_DL ("d.directory", CMD2_ON_FL(root_dir));
CMD2_DL ("d.directory.realpath.or_empty", [](auto* download, auto) { return resolve_path(download->file_list()->root_dir()); });
CMD2_DL ("d.directory.realpath.or_throw", [](auto* download, auto) { return resolve_path_or_throw(download->file_list()->root_dir()); });
CMD2_DL_STRING_V("d.directory.set", [](auto* download, auto arg) { download->set_directory(arg); });
CMD2_DL_STRING_V("d.directory.base.set", [](auto* download, auto arg) { download->set_base_directory(arg); });
CMD2_DL ("d.directory", CMD2_ON_FL(root_dir));
CMD2_DL ("d.directory.realpath.or_empty", [](auto* download, auto) { return resolve_path(download->file_list()->root_dir()); });
CMD2_DL ("d.directory.realpath.or_throw", [](auto* download, auto) { return resolve_path_or_throw(download->file_list()->root_dir()); });
CMD2_DL_STRING_V("d.directory.set", std::bind(&apply_d_directory, std::placeholders::_1, std::placeholders::_2));
CMD2_DL ("d.directory_base", CMD2_ON_FL(root_dir));
CMD2_DL_STRING_V("d.directory_base.set", std::bind(&core::Download::set_root_directory, std::placeholders::_1, std::placeholders::_2));
CMD2_DL ("d.priority", std::bind(&core::Download::priority, std::placeholders::_1));
CMD2_DL ("d.priority_str", std::bind(&retrieve_d_priority_str, std::placeholders::_1));
@@ -939,6 +950,7 @@ initialize_command_download() {
rpc::rpc.mark_safe("d.name.or_base64");
rpc::rpc.mark_safe("d.name.or_as_binary");
rpc::rpc.mark_safe("d.directory");
rpc::rpc.mark_safe("d.directory_base");
rpc::rpc.mark_safe("d.creation_date");
rpc::rpc.mark_safe("d.load_date");
rpc::rpc.mark_safe("d.up.rate");
+43 -30
View File
@@ -1,17 +1,25 @@
#include "config.h"
#include <torrent/exceptions.h>
#include <functional>
#include <cstdio>
#include <string>
#include <vector>
#include <torrent/rate.h>
#include <torrent/hash_string.h>
#include <torrent/utils/log.h>
#include <torrent/utils/directory_events.h>
#include <torrent/utils/file_stat.h>
#include <torrent/utils/string_manip.h>
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "core/download.h"
#include "core/download_list.h"
#include "core/manager.h"
#include "core/view_manager.h"
#include "rpc/command_scheduler.h"
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
#include "utils/watch_ready_queue.h"
@@ -43,7 +51,7 @@ apply_on_ratio(const torrent::Object& rawArgs) {
!(max_ratio > 0 && total_upload * 100 > total_done * max_ratio))
continue;
downloads.push_back(itr->get());
downloads.push_back(*itr);
}
auto ratio_command = "group." + group_name + ".ratio.command";
@@ -120,7 +128,7 @@ apply_remove_untied() {
}
torrent::Object
apply_schedule(const torrent::Object::list_type& args, bool if_absent) {
apply_schedule(const torrent::Object::list_type& args) {
if (args.size() != 4)
throw torrent::input_error("Wrong number of arguments.");
@@ -130,14 +138,29 @@ apply_schedule(const torrent::Object::list_type& args, bool if_absent) {
auto& arg2 = (itr++)->as_string();
auto& arg3 = (itr++)->as_string();
if (if_absent && control->command_scheduler()->find(arg1) != control->command_scheduler()->end())
return torrent::Object();
control->command_scheduler()->parse(arg1, arg2, arg3, *itr);
return torrent::Object();
}
torrent::Object
apply_load(const torrent::Object::list_type& args, int flags) {
torrent::Object::list_const_iterator argsItr = args.begin();
if (argsItr == args.end())
throw torrent::input_error("Too few arguments.");
auto& filename = argsItr->as_string();
core::Manager::command_list_type commands;
while (++argsItr != args.end())
commands.push_back(argsItr->as_string());
control->core()->try_create_download_expand(filename, flags, commands);
return torrent::Object();
}
void apply_import(const std::string& path) { if (!rpc::parse_command_file(path)) throw torrent::input_error("Could not open option file: " + path); }
void apply_try_import(const std::string& path) { if (!rpc::parse_command_file(path)) control->core()->push_log_std("Could not read resource file: " + path); }
@@ -147,7 +170,7 @@ apply_close_low_diskspace(int64_t arg, uint32_t skip_priority) {
torrent::FileList::cache_list cache;
for (const auto& download : *control->core()->download_list()) {
for (auto download : *control->core()->download_list()) {
if (!download->is_downloading())
continue;
if (download->priority() >= skip_priority)
@@ -214,25 +237,15 @@ d_multicall(const torrent::Object::list_type& args) {
// Add some pre-parsing of the commands, so we don't spend time
// parsing and searching command map for every single call.
// Hold a reference to each download so a command that erases one does not
// leave the rest of the loop dispatching on freed memory.
core::View::base_type dlist((*view_itr)->begin_visible(), (*view_itr)->end_visible());
std::vector<core::Download*> dlist((*view_itr)->begin_visible(), (*view_itr)->end_visible());
torrent::Object resultRaw = torrent::Object::create_list();
torrent::Object::list_type& result = resultRaw.as_list();
for (const auto& download : dlist) {
if (download.use_count() == 1)
continue;
for (auto download : dlist) {
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
// A command may erase this download, which destroys the torrent object it
// wraps; the list dropping its reference is what tells us.
if (download.use_count() == 1)
break;
auto& cmd = cItr->as_string();
row.push_back(rpc::parse_command(rpc::make_target(download), cmd.c_str(), cmd.c_str() + cmd.size()).first);
}
@@ -255,12 +268,10 @@ d_multicall_filtered(const torrent::Object::list_type& args) {
if (view_itr == viewManager->end())
throw torrent::input_error("Could not find view '" + arg->as_string() + "'.");
// Make a filtered copy of the current item list, holding a reference to each
// download so a command that erases one cannot free it under us.
// Make a filtered copy of the current item list
core::View::base_type dlist;
(*view_itr)->filter_by(*++arg, dlist);
// Generate result by iterating over all items
auto resultRaw = torrent::Object::create_list();
auto& result = resultRaw.as_list();
@@ -268,17 +279,11 @@ d_multicall_filtered(const torrent::Object::list_type& args) {
++arg; // skip to first command
for (const auto& item : dlist) {
if (item.use_count() == 1)
continue;
// Add empty row to result
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
// Call the provided commands and assemble their results
for (torrent::Object::list_const_iterator command = arg; command != args.end(); command++) {
if (item.use_count() == 1)
break;
auto& cmdstr = command->as_string();
row.push_back(rpc::parse_command(rpc::make_target(item), cmdstr.c_str(), cmdstr.c_str() + cmdstr.size()).first);
}
@@ -335,13 +340,21 @@ initialize_command_events() {
CMD2_ANY ("close_untied", [](auto, auto) { return apply_close_untied(); });
CMD2_ANY ("remove_untied", [](auto, auto) { return apply_remove_untied(); });
CMD2_ANY_LIST ("schedule", [](auto, auto& args) { return apply_schedule(args, false); });
CMD2_ANY_LIST ("schedule.if_absent", [](auto, auto& args) { return apply_schedule(args, true); });
CMD2_ANY_LIST ("schedule", [](auto, auto& args) { return apply_schedule(args); });
CMD2_ANY_STRING_V("schedule.remove", [](auto, auto& str) { return control->command_scheduler()->erase_str(str); });
CMD2_ANY_STRING_V("import", [](auto, auto& str) { return apply_import(str); });
CMD2_ANY_STRING_V("try_import", [](auto, auto& str) { return apply_try_import(str); });
CMD2_ANY_LIST ("load.normal", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_tied); });
CMD2_ANY_LIST ("load.verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_tied); });
CMD2_ANY_LIST ("load.start", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.start_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.raw", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start", [](auto, auto& args) { return apply_load(args, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start_verbose", [](auto, auto& args) { return apply_load(args, core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_VALUE ("close_low_diskspace", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 99); });
CMD2_ANY_VALUE ("close_low_diskspace.normal", [](auto, auto& arg) { return apply_close_low_diskspace(arg, 3); });
+9 -11
View File
@@ -1,7 +1,5 @@
#include "config.h"
#include <memory>
#include <torrent/download/resource_manager.h>
#include <torrent/download/choke_group.h>
#include <torrent/download/choke_queue.h>
@@ -113,7 +111,7 @@ apply_cg_all_update_balance(bool is_up) {
//
#else
std::vector<std::unique_ptr<torrent::choke_group>> cg_list_hack;
std::vector<torrent::choke_group*> cg_list_hack;
int64_t
cg_get_index(const torrent::Object& raw_args) {
@@ -123,7 +121,7 @@ cg_get_index(const torrent::Object& raw_args) {
if (arg.is_string()) {
if (!rpc::parse_whole_value_nothrow(arg.as_string().c_str(), &index)) {
auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](const auto& cg) { return arg.as_string() == cg->name(); });
auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](torrent::choke_group* cg) { return arg.as_string() == cg->name(); });
if (itr == cg_list_hack.end())
throw torrent::input_error("Choke group not found.");
@@ -151,7 +149,7 @@ cg_get_group(const torrent::Object& raw_args) {
if ((size_t)index >= cg_list_hack.size())
throw torrent::input_error("Choke group not found.");
return cg_list_hack.at(index).get();
return cg_list_hack.at(index);
}
int64_t cg_d_group(core::Download* download) { return download->group(); }
@@ -164,7 +162,7 @@ torrent::Object
apply_cg_list() {
torrent::Object::list_type result;
for (const auto& itr : cg_list_hack)
for (auto itr : cg_list_hack)
result.push_back(itr->name());
return torrent::Object::from_list(result);
@@ -182,10 +180,10 @@ apply_cg_insert(const std::string& arg) {
if (rpc::parse_whole_value_nothrow(arg.c_str(), &dummy))
throw torrent::input_error("Cannot use a value string as choke group name.");
if (arg.empty() || std::any_of(cg_list_hack.begin(), cg_list_hack.end(), [&arg](const auto& cg) { return arg == cg->name(); }))
if (arg.empty() || std::any_of(cg_list_hack.begin(), cg_list_hack.end(), [&arg](auto cg) { return arg == cg->name(); }))
throw torrent::input_error("Duplicate name for choke group.");
cg_list_hack.push_back(std::make_unique<torrent::choke_group>());
cg_list_hack.push_back(new torrent::choke_group());
cg_list_hack.back()->set_name(arg);
cg_list_hack.back()->up_queue()->set_heuristics(torrent::HEURISTICS_UPLOAD_LEECH);
@@ -196,7 +194,7 @@ apply_cg_insert(const std::string& arg) {
torrent::Object
apply_cg_index_of(const std::string& arg) {
auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](const auto& cg) { return arg == cg->name(); });
auto itr = std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](torrent::choke_group* cg) { return arg == cg->name(); });
if (itr == cg_list_hack.end())
throw torrent::input_error("Choke group not found.");
@@ -208,7 +206,7 @@ torrent::Object
apply_cg_all_update_balance(bool is_up) {
LT_LOG_SUBSYSTEM("apply update balance: hack is_up:%i", (int)is_up);
for (const auto& itr : cg_list_hack) {
for (auto itr : cg_list_hack) {
if (is_up)
itr->up_queue()->balance();
else
@@ -348,7 +346,7 @@ initialize_command_groups() {
#else
apply_cg_insert("default");
CMD_ANY ("choke_group.size", [](auto, auto) { return (int64_t)cg_list_hack.size(); });
CMD_ANY ("choke_group.size", std::bind(&std::vector<torrent::choke_group*>::size, cg_list_hack));
CMD_ANY_STRING ("choke_group.index_of", std::bind(&apply_cg_index_of, std::placeholders::_2));
#endif
-2
View File
@@ -20,7 +20,6 @@ void initialize_command_throttle();
void initialize_command_tracker();
void initialize_command_scheduler();
void initialize_command_string();
void initialize_command_system();
void initialize_command_ui();
void
@@ -40,5 +39,4 @@ initialize_commands() {
initialize_command_tracker();
initialize_command_scheduler();
initialize_command_string();
initialize_command_system();
}
-81
View File
@@ -1,81 +0,0 @@
#include "config.h"
#include "command_helpers.h"
#include "control.h"
#include "core/manager.h"
torrent::Object
apply_load_trusted(const torrent::Object::list_type& args, int flags) {
auto argsItr = args.begin();
if (argsItr == args.end())
throw torrent::input_error("Too few arguments.");
auto& filename = argsItr->as_string();
core::Manager::command_list_type commands;
while (++argsItr != args.end())
commands.push_back(argsItr->as_string());
control->core()->try_create_download_expand(filename, flags, commands);
return torrent::Object();
}
torrent::Object
apply_load_untrusted(const torrent::Object::list_type& args, int flags) {
auto argsItr = args.begin();
if (argsItr == args.end())
throw torrent::input_error("Too few arguments.");
auto& filename = argsItr->as_string();
core::Manager::command_list_type commands;
while (++argsItr != args.end())
commands.push_back(argsItr->as_string());
control->core()->try_create_download_untrusted(filename, flags, commands);
return torrent::Object();
}
void
initialize_command_load() {
CMD2_ANY_LIST ("load.normal", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_quiet | core::Manager::create_tied); });
CMD2_ANY_LIST ("load.verbose", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_tied); });
CMD2_ANY_LIST ("load.start", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.start_verbose", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_tied | core::Manager::create_start); });
CMD2_ANY_LIST ("load.raw", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_quiet | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_verbose", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.raw_start_verbose", [](auto, auto& args) { return apply_load_trusted(args, core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.untrusted.normal", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_quiet); });
CMD2_ANY_LIST ("load.untrusted.verbose", [](auto, auto& args) { return apply_load_untrusted(args, 0); });
CMD2_ANY_LIST ("load.untrusted.start", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_quiet | core::Manager::create_start); });
CMD2_ANY_LIST ("load.untrusted.start_verbose", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_start); });
CMD2_ANY_LIST ("load.untrusted.raw", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_quiet | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.untrusted.raw_verbose", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.untrusted.raw_start", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_LIST ("load.untrusted.raw_start_verbose", [](auto, auto& args) { return apply_load_untrusted(args, core::Manager::create_start | core::Manager::create_raw_data); });
CMD2_ANY_VALUE_V("load.untrusted.mark_safe", [](auto, auto& arg) {
if (arg == 0)
return;
// TODO: Add a bool to core::Manager.
rpc::rpc.mark_safe("load.untrusted.normal");
rpc::rpc.mark_safe("load.untrusted.verbose");
rpc::rpc.mark_safe("load.untrusted.start");
rpc::rpc.mark_safe("load.untrusted.start_verbose");
rpc::rpc.mark_safe("load.untrusted.raw");
rpc::rpc.mark_safe("load.untrusted.raw_verbose");
rpc::rpc.mark_safe("load.untrusted.raw_start");
rpc::rpc.mark_safe("load.untrusted.raw_start_verbose");
});
}
+174 -8
View File
@@ -1,16 +1,33 @@
#include "config.h"
#include <cerrno>
#include <fcntl.h>
#include <functional>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <torrent/torrent.h>
#include <torrent/data/file_manager.h>
#include <torrent/data/chunk_utils.h>
#include <torrent/runtime/runtime.h>
#include <torrent/runtime/memory_manager.h>
#include <torrent/utils/log.h>
#include <torrent/runtime/socket_manager.h>
#include <torrent/utils/chrono.h>
#include <torrent/utils/option_strings.h>
#include "command_helpers.h"
#include "control.h"
#include "core/download.h"
#include "core/download_list.h"
#include "core/manager.h"
#include "rpc/parse_commands.h"
#include "rpc/lua.h"
#include "rpc/scgi.h"
#include "session/session_manager.h"
#include "utils/file_status_cache.h"
#include "globals.h"
#include "rpc/lua.h"
#include "control.h"
#include "command_helpers.h"
typedef torrent::ChunkManager CM_t;
typedef torrent::FileManager FM_t;
@@ -26,6 +43,49 @@ apply_pieces_stats_total_size() {
return size;
}
torrent::Object
system_env(const torrent::Object::string_type& arg) {
if (arg.empty())
throw torrent::input_error("system.env: Missing variable name.");
char* val = getenv(arg.c_str());
return std::string(val ? val : "");
}
torrent::Object
system_hostname() {
char buffer[1024];
if (gethostname(buffer, 1023) == -1)
throw torrent::input_error("Unable to read hostname.");
// if (shorten)
// *std::find(buffer, buffer + 1023, '.') = '\0';
return std::string(buffer);
}
torrent::Object
system_get_cwd() {
char* buffer = getcwd(NULL, 0);
if (buffer == NULL)
throw torrent::input_error("Unable to read cwd.");
torrent::Object result = torrent::Object(std::string(buffer));
free(buffer);
return result;
}
torrent::Object
system_set_cwd(const torrent::Object::string_type& rawArgs) {
if (::chdir(rawArgs.c_str()) != 0)
throw torrent::input_error("Could not change current working directory.");
return torrent::Object();
}
inline torrent::Object::list_const_iterator
post_increment(torrent::Object::list_const_iterator& itr, const torrent::Object::list_const_iterator& last) {
if (itr == last)
@@ -127,17 +187,94 @@ cmd_file_append(const torrent::Object::list_type& args) {
void
initialize_command_local() {
core::DownloadList* dList = control->core()->download_list();
core::DownloadList* dList = control->core()->download_list();
torrent::FileManager* fileManager = torrent::file_manager();
CMD_ANY ("system.hostname", std::bind(&system_hostname));
CMD_ANY ("system.pid", std::bind(&getpid));
CMD_VAR_C_STRING("system.api_version", (int64_t)API_VERSION);
CMD_VAR_C_STRING("system.client_version", PACKAGE_VERSION);
CMD_VAR_C_STRING("system.library_version", torrent::runtime::version());
CMD_VAR_VALUE ("system.file.allocate", 0);
CMD_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30);
CMD_VAR_VALUE ("system.file.split_size", -1);
CMD_VAR_STRING ("system.file.split_suffix", ".part");
CMD_ANY ("system.file_status_cache.size", std::bind(&utils::FileStatusCache::size,
(utils::FileStatusCache::base_type*)control->core()->file_status_cache()));
CMD_ANY_V ("system.file_status_cache.prune", std::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
CMD_VAR_BOOL ("file.prioritize_toc", 0);
CMD_VAR_LIST ("file.prioritize_toc.first");
CMD_VAR_LIST ("file.prioritize_toc.last");
CMD_ANY ("system.files.advise_random", std::bind(&FM_t::advise_random, fileManager));
CMD_ANY_VALUE_V ("system.files.advise_random.set", std::bind(&FM_t::set_advise_random, fileManager, std::placeholders::_2));
CMD_ANY ("system.files.advise_random.hashing", std::bind(&FM_t::advise_random_hashing, fileManager));
CMD_ANY_VALUE_V ("system.files.advise_random.hashing.set", std::bind(&FM_t::set_advise_random_hashing, fileManager, std::placeholders::_2));
CMD_ANY ("system.files.session.fdatasync", [](auto, auto) { return session_thread::manager()->use_fsyncdisk(); });
CMD_ANY_VALUE_V ("system.files.session.fdatasync.set", [](auto, auto& value) { return session_thread::manager()->set_use_fsyncdisk(value); });
CMD_ANY ("system.files.opened_counter", std::bind(&FM_t::files_opened_counter, fileManager));
CMD_ANY ("system.files.closed_counter", std::bind(&FM_t::files_closed_counter, fileManager));
CMD_ANY ("system.files.failed_counter", std::bind(&FM_t::files_failed_counter, fileManager));
CMD_ANY_STRING ("system.env", [](auto, auto& str) { return system_env(str); });
CMD_ANY ("system.time", [](auto, auto) { return torrent::this_thread::cached_seconds().count(); });
CMD_ANY ("system.time_seconds", [](auto, auto) { return torrent::utils::cast_seconds(torrent::utils::time_since_epoch()).count(); });
CMD_ANY ("system.time_usec", [](auto, auto) { return torrent::utils::time_since_epoch().count(); });
CMD_ANY_VALUE_V ("system.umask.set", [](auto, auto& value) { return ::umask(value); });
CMD_VAR_BOOL ("system.daemon", false);
CMD_ANY_V ("system.shutdown.normal", [](auto, auto) { control->receive_normal_shutdown(); });
CMD_ANY_V ("system.shutdown.quick", [](auto, auto) { control->receive_quick_shutdown(); });
CMD_REDIRECT_NO_EXPORT("system.shutdown", "system.shutdown.normal");
CMD_ANY ("system.cwd", [](auto, auto) { return system_get_cwd(); });
CMD_ANY_STRING ("system.cwd.set", [](auto, auto& str) { return system_set_cwd(str); });
CMD_ANY ("system.sockets.size", [](auto, auto) { return torrent::runtime::socket_manager()->size(); });
CMD_ANY ("system.sockets.max_size", [](auto, auto) { return torrent::runtime::socket_manager()->max_size(); });
CMD_ANY_VALUE_V ("system.sockets.max_size.set", [](auto, auto& value) { return torrent::runtime::socket_manager()->set_max_size_and_adjust(value); });
CMD_ANY_V ("system.sockets.adjust_alloc", [](auto, auto) { torrent::runtime::socket_manager()->adjust_allocation(); });
CMD_ANY ("system.sockets.reserved_alloc", [](auto, auto) { return torrent::runtime::socket_manager()->reserved_allocation(); });
CMD_ANY ("system.sockets.available_alloc", [](auto, auto) { return torrent::runtime::socket_manager()->available_allocation(); });
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
auto category = static_cast<torrent::runtime::socket_manager_category_t>(i);
auto category_name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
CMD_ANY (category_name + ".size", [category](auto, auto) { return torrent::runtime::socket_manager()->category_managed_size(category); });
CMD_ANY (category_name + ".max_size", [category](auto, auto) { return torrent::runtime::socket_manager()->category_max_size(category); });
if (i == 0) {
CMD_ANY (category_name + ".min_alloc", [](auto, auto) { return torrent::runtime::socket_manager()->generic_min_allocation(); });
continue;
}
CMD_ANY (category_name + ".max_alloc.limit", [category](auto, auto) { return torrent::runtime::socket_manager()->category_alloc_limit(category); });
CMD_ANY (category_name + ".min_alloc.limit", [category](auto, auto) { return torrent::runtime::socket_manager()->category_alloc_minimum(category); });
CMD_ANY (category_name + ".min_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_min_allocation(category); });
CMD_ANY (category_name + ".max_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_max_allocation(category); });
CMD_ANY_VALUE_V(category_name + ".min_alloc.set", [category](auto, auto& value) { torrent::runtime::socket_manager()->set_category_min_allocation(category, value); });
CMD_ANY_VALUE_V(category_name + ".max_alloc.set", [category](auto, auto& value) { torrent::runtime::socket_manager()->set_category_max_allocation(category, value); });
}
CMD_ANY ("pieces.sync.always_safe", [](auto, auto) { return torrent::runtime::memory_manager()->safe_sync(); });
CMD_ANY_VALUE_V ("pieces.sync.always_safe.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_safe_sync(value); });
CMD_ANY ("pieces.sync.safe_free_diskspace", [](auto, auto) { return torrent::runtime::memory_manager()->sync_safe_free_diskspace(); });
CMD_ANY ("pieces.sync.timeout", [](auto, auto) { return torrent::runtime::memory_manager()->timeout_sync().count(); });
CMD_ANY_VALUE_V ("pieces.sync.timeout.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_timeout_sync(value); });
// CMD_ANY ("pieces.sync.timeout_safe", [](auto, auto) { return torrent::runtime::memory_manager()->timeout_safe_sync(); });
// CMD_ANY_VALUE_V ("pieces.sync.timeout_safe.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_timeout_safe_sync(value); });
CMD_ANY ("pieces.sync.timeout_safe", [](auto, auto) { return 0; });
CMD_ANY_VALUE_V ("pieces.sync.timeout_safe.set", [](auto, auto) {
lt_log_print(torrent::LOG_WARN, "pieces.sync.timeout_safe.set is no longer supported and does nothing.");
});
CMD_ANY_VALUE_V ("pieces.sync.timeout_safe.set", [](auto, auto) { });
CMD_ANY ("pieces.sync.queue_size", [](auto, auto) { return torrent::runtime::memory_manager()->sync_queue_block_count(); });
CMD_ANY ("pieces.preload.type", [](auto, auto) { return torrent::runtime::memory_manager()->preload_type(); });
@@ -212,6 +349,35 @@ initialize_command_local() {
CMD_ANY_LIST ("group.insert", std::bind(&group_insert, std::placeholders::_2));
rpc::rpc.mark_safe("system.api_version");
rpc::rpc.mark_safe("system.client_version");
rpc::rpc.mark_safe("system.library_version");
rpc::rpc.mark_safe("system.file.max_size");
rpc::rpc.mark_safe("system.file.split_size");
rpc::rpc.mark_safe("system.file.split_suffix");
rpc::rpc.mark_safe("system.sockets.size");
rpc::rpc.mark_safe("system.sockets.max_size");
rpc::rpc.mark_safe("system.sockets.reserved_alloc");
rpc::rpc.mark_safe("system.sockets.available_alloc");
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
auto category_name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
rpc::rpc.mark_safe(category_name + ".size");
rpc::rpc.mark_safe(category_name + ".max_size");
if (i == 0) {
rpc::rpc.mark_safe(category_name + ".min_alloc");
continue;
}
rpc::rpc.mark_safe(category_name + ".max_alloc.limit");
rpc::rpc.mark_safe(category_name + ".min_alloc.limit");
rpc::rpc.mark_safe(category_name + ".min_alloc");
rpc::rpc.mark_safe(category_name + ".max_alloc");
}
rpc::rpc.mark_safe("directory.default");
rpc::rpc.mark_safe("session.path");
rpc::rpc.mark_safe("session.path.realpath.or_empty");
+1 -1
View File
@@ -135,7 +135,7 @@ initialize_command_logging() {
CMD2_ANY_LIST ("log.open_gz_file_pid", std::bind(&apply_log_open, log_flag_append_pid | log_flag_use_gz, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_file.flush", std::bind(&apply_log_open, log_flag_append_file | log_flag_flush, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_gz_file", std::bind(&apply_log_open, log_flag_append_file | log_flag_use_gz, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_gz_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
-18
View File
@@ -54,14 +54,6 @@ set_listen_port_range(const std::string& arg) {
torrent::runtime::client_config()->set_listen_port_range(port_first, port_last);
}
uint16_t
checked_local_port_value(int64_t value, const char* label) {
if (value < 0 || value > 65535)
throw torrent::input_error(std::string("Invalid ") + label + " port number.");
return static_cast<uint16_t>(value);
}
torrent::Object
get_encryption() {
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
@@ -387,13 +379,6 @@ initialize_command_network() {
CMD_ANY ("network.local_address.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_address_str(); });
CMD_ANY_STRING_V("network.local_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet6_address_str(str); });
CMD_ANY ("network.local_port", [nw_config](auto, auto) { return nw_config->local_port_best_match(); });
CMD_ANY_VALUE_V ("network.local_port.set", [nw_config](auto, auto& value) { return nw_config->set_local_port(checked_local_port_value(value, "local")); });
CMD_ANY ("network.local_port.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_port(); });
CMD_ANY_VALUE_V ("network.local_port.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_local_inet_port(checked_local_port_value(value, "local ipv4")); });
CMD_ANY ("network.local_port.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_port(); });
CMD_ANY_VALUE_V ("network.local_port.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_local_inet6_port(checked_local_port_value(value, "local ipv6")); });
CMD_ANY ("network.proxy.global", [](auto, auto) { return torrent::runtime::proxy_manager()->proxy_url(); });
CMD_ANY_STRING_V("network.proxy.global.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_proxy_url(str); });
CMD_ANY ("network.proxy.http", [](auto, auto) { return torrent::runtime::proxy_manager()->http_proxy_url(); });
@@ -452,9 +437,6 @@ initialize_command_network() {
rpc::rpc.mark_safe("network.receive_buffer.size");
rpc::rpc.mark_safe("network.bind_address");
rpc::rpc.mark_safe("network.local_address");
rpc::rpc.mark_safe("network.local_port");
rpc::rpc.mark_safe("network.local_port.ipv4");
rpc::rpc.mark_safe("network.local_port.ipv6");
rpc::rpc.mark_safe("network.xmlrpc.size_limit");
rpc::rpc.mark_safe("network.open_sockets");
-6
View File
@@ -19,8 +19,6 @@
namespace {
constexpr int64_t max_string_pad_size = 1 << 14;
const std::string whitespace_characters = " \t\n\r\f\v";
// The byte offset of every utf-8 character in 'text', terminated by the offset
@@ -251,14 +249,10 @@ apply_string_pad(const char* name, const torrent::Object::list_type& args, bool
if (pad_size <= text_length || padding.empty())
return text;
if (pad_size - text_length > max_string_pad_size)
throw torrent::input_error(std::string(name) + ": padding is too large.");
auto padding_offsets = utf8_offsets(padding);
auto padding_length = static_cast<int64_t>(padding_offsets.size() - 1);
std::string result;
result.reserve(pad_size - text_length);
for (int64_t i = 0; i < pad_size - text_length; i++) {
auto index = static_cast<size_t>(i % padding_length);
-195
View File
@@ -1,195 +0,0 @@
#include "config.h"
#include <unistd.h>
#include <sys/stat.h>
#include <torrent/data/file_manager.h>
#include <torrent/runtime/client_config.h>
#include <torrent/runtime/memory_manager.h>
#include <torrent/runtime/socket_manager.h>
#include <torrent/runtime/runtime.h>
#include <torrent/utils/chrono.h>
#include <torrent/utils/option_strings.h>
#include "command_helpers.h"
#include "control.h"
#include "globals.h"
#include "core/manager.h"
#include "session/session_manager.h"
#include "utils/file_status_cache.h"
torrent::Object
system_env(const torrent::Object::string_type& arg) {
if (arg.empty())
throw torrent::input_error("system.env: Missing variable name.");
char* val = getenv(arg.c_str());
return std::string(val ? val : "");
}
torrent::Object
system_hostname() {
char buffer[1024];
if (gethostname(buffer, 1023) == -1)
throw torrent::input_error("Unable to read hostname.");
// if (shorten)
// *std::find(buffer, buffer + 1023, '.') = '\0';
return std::string(buffer);
}
torrent::Object
system_get_cwd() {
char* buffer = getcwd(NULL, 0);
if (buffer == NULL)
throw torrent::input_error("Unable to read cwd.");
torrent::Object result = torrent::Object(std::string(buffer));
free(buffer);
return result;
}
torrent::Object
system_set_cwd(const torrent::Object::string_type& rawArgs) {
if (::chdir(rawArgs.c_str()) != 0)
throw torrent::input_error("Could not change current working directory.");
return torrent::Object();
}
uint32_t
checked_socket_value(int64_t value, const char* label) {
if (value < 0 || value > std::numeric_limits<uint32_t>::max())
throw torrent::input_error(std::string("Invalid ") + label + " value.");
return static_cast<uint32_t>(value);
}
void
initialize_command_system() {
CMD_ANY ("system.hostname", std::bind(&system_hostname));
CMD_ANY ("system.pid", std::bind(&getpid));
CMD_VAR_C_STRING("system.api_version", (int64_t)API_VERSION);
CMD_VAR_C_STRING("system.client_version", PACKAGE_VERSION);
CMD_VAR_C_STRING("system.library_version", torrent::runtime::version());
CMD_ANY ("system.torrent_name.use_sanitized", [](auto, auto) { return torrent::runtime::client_config()->torrent_name_use_sanitized(); });
CMD_ANY_VALUE_V ("system.torrent_name.use_sanitized.set", [](auto, auto& value) { return torrent::runtime::client_config()->set_torrent_name_use_sanitized(value); });
CMD_VAR_VALUE ("system.file.allocate", 0);
CMD_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30);
CMD_VAR_VALUE ("system.file.split_size", -1);
CMD_VAR_STRING ("system.file.split_suffix", ".part");
CMD_ANY ("system.file_name.replace_slash", [](auto, auto) { return torrent::runtime::client_config()->file_name_replace_slash(); });
CMD_ANY_STRING_V("system.file_name.replace_slash.set", [](auto, auto& str) { return torrent::runtime::client_config()->set_file_name_replace_slash(str); });
CMD_ANY ("system.file_status_cache.size", [](auto, auto) { return control->core()->file_status_cache()->size(); });
CMD_ANY_V ("system.file_status_cache.prune", [](auto, auto) { return control->core()->file_status_cache()->prune(); });
CMD_VAR_BOOL ("file.prioritize_toc", 0);
CMD_VAR_LIST ("file.prioritize_toc.first");
CMD_VAR_LIST ("file.prioritize_toc.last");
CMD_ANY ("system.files.advise_random", [](auto, auto) { return torrent::file_manager()->advise_random(); });
CMD_ANY_VALUE_V ("system.files.advise_random.set", [](auto, auto& value) { return torrent::file_manager()->set_advise_random(value); });
CMD_ANY ("system.files.advise_random.hashing", [](auto, auto) { return torrent::file_manager()->advise_random_hashing(); });
CMD_ANY_VALUE_V ("system.files.advise_random.hashing.set", [](auto, auto& value) { return torrent::file_manager()->set_advise_random_hashing(value); });
CMD_ANY ("system.files.session.fdatasync", [](auto, auto) { return session_thread::manager()->use_fsyncdisk(); });
CMD_ANY_VALUE_V ("system.files.session.fdatasync.set", [](auto, auto& value) { return session_thread::manager()->set_use_fsyncdisk(value); });
CMD_ANY ("system.files.close_idle", [](auto, auto) { return torrent::file_manager()->close_idle_timeout().count(); });
CMD_ANY_VALUE_V ("system.files.close_idle.set", [](auto, auto& value) { return torrent::file_manager()->set_close_idle_timeout(value * 1s); });
CMD_ANY ("system.files.opened_counter", [](auto, auto) { return torrent::file_manager()->files_opened_counter(); });
CMD_ANY ("system.files.closed_counter", [](auto, auto) { return torrent::file_manager()->files_closed_counter(); });
CMD_ANY ("system.files.failed_counter", [](auto, auto) { return torrent::file_manager()->files_failed_counter(); });
CMD_ANY_STRING ("system.env", [](auto, auto& str) { return system_env(str); });
CMD_ANY ("system.time", [](auto, auto) { return torrent::this_thread::cached_seconds().count(); });
CMD_ANY ("system.time_seconds", [](auto, auto) { return torrent::utils::cast_seconds(torrent::utils::time_since_epoch()).count(); });
CMD_ANY ("system.time_usec", [](auto, auto) { return torrent::utils::time_since_epoch().count(); });
CMD_ANY_VALUE_V ("system.umask.set", [](auto, auto& value) { return ::umask(value); });
CMD_VAR_BOOL ("system.daemon", false);
CMD_ANY_V ("system.shutdown.normal", [](auto, auto) { control->receive_normal_shutdown(); });
CMD_ANY_V ("system.shutdown.quick", [](auto, auto) { control->receive_quick_shutdown(); });
CMD_REDIRECT_NO_EXPORT("system.shutdown", "system.shutdown.normal");
CMD_ANY ("system.cwd", [](auto, auto) { return system_get_cwd(); });
CMD_ANY_STRING ("system.cwd.set", [](auto, auto& str) { return system_set_cwd(str); });
CMD_ANY ("system.sockets.size", [](auto, auto) { return torrent::runtime::socket_manager()->size(); });
CMD_ANY ("system.sockets.max_size", [](auto, auto) { return torrent::runtime::socket_manager()->max_size(); });
CMD_ANY_VALUE_V ("system.sockets.max_size.set", [](auto, auto& value) {
return torrent::runtime::socket_manager()->set_max_size_and_adjust(checked_socket_value(value, "socket max size"));
});
CMD_ANY_V ("system.sockets.adjust_alloc", [](auto, auto) { torrent::runtime::socket_manager()->adjust_allocation(); });
CMD_ANY ("system.sockets.reserved_alloc", [](auto, auto) { return torrent::runtime::socket_manager()->reserved_allocation(); });
CMD_ANY ("system.sockets.available_alloc", [](auto, auto) { return torrent::runtime::socket_manager()->available_allocation(); });
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
auto category = static_cast<torrent::runtime::socket_manager_category_t>(i);
auto category_name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
CMD_ANY (category_name + ".size", [category](auto, auto) { return torrent::runtime::socket_manager()->category_managed_size(category); });
CMD_ANY (category_name + ".max_size", [category](auto, auto) { return torrent::runtime::socket_manager()->category_max_size(category); });
if (i == 0) {
CMD_ANY (category_name + ".min_alloc", [](auto, auto) { return torrent::runtime::socket_manager()->generic_min_allocation(); });
continue;
}
CMD_ANY (category_name + ".max_alloc.limit", [category](auto, auto) { return torrent::runtime::socket_manager()->category_alloc_limit(category); });
CMD_ANY (category_name + ".min_alloc.limit", [category](auto, auto) { return torrent::runtime::socket_manager()->category_alloc_minimum(category); });
CMD_ANY (category_name + ".min_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_min_allocation(category); });
CMD_ANY (category_name + ".max_alloc", [category](auto, auto) { return torrent::runtime::socket_manager()->category_max_allocation(category); });
CMD_ANY_VALUE_V(category_name + ".min_alloc.set", [category](auto, auto& value) {
torrent::runtime::socket_manager()->set_category_min_allocation(category, checked_socket_value(value, "socket min alloc"));
});
CMD_ANY_VALUE_V(category_name + ".max_alloc.set", [category](auto, auto& value) {
torrent::runtime::socket_manager()->set_category_max_allocation(category, checked_socket_value(value, "socket max alloc"));
});
}
rpc::rpc.mark_safe("system.api_version");
rpc::rpc.mark_safe("system.client_version");
rpc::rpc.mark_safe("system.library_version");
rpc::rpc.mark_safe("system.time");
rpc::rpc.mark_safe("system.time_seconds");
rpc::rpc.mark_safe("system.time_usec");
rpc::rpc.mark_safe("system.file.max_size");
rpc::rpc.mark_safe("system.file.split_size");
rpc::rpc.mark_safe("system.file.split_suffix");
rpc::rpc.mark_safe("system.sockets.size");
rpc::rpc.mark_safe("system.sockets.max_size");
rpc::rpc.mark_safe("system.sockets.reserved_alloc");
rpc::rpc.mark_safe("system.sockets.available_alloc");
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
auto category_name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
rpc::rpc.mark_safe(category_name + ".size");
rpc::rpc.mark_safe(category_name + ".max_size");
if (i == 0) {
rpc::rpc.mark_safe(category_name + ".min_alloc");
continue;
}
rpc::rpc.mark_safe(category_name + ".max_alloc.limit");
rpc::rpc.mark_safe(category_name + ".min_alloc.limit");
rpc::rpc.mark_safe(category_name + ".min_alloc");
rpc::rpc.mark_safe(category_name + ".max_alloc");
}
}
+2 -2
View File
@@ -68,11 +68,11 @@ apply_dht_add_node(const std::string& arg) {
torrent::Object
apply_enable_trackers(int64_t arg) {
if (arg == 0) {
for (const auto& download : *control->core()->download_list())
for (auto download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.disable(); });
} else {
for (const auto& download : *control->core()->download_list())
for (auto download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.enable(); });
}
+3 -11
View File
@@ -3,7 +3,6 @@
#include <sys/types.h>
#include <ctime>
#include <limits>
#include <regex>
#include <torrent/utils/log.h>
@@ -408,9 +407,8 @@ apply_to_time(const torrent::Object& rawArgs, int flags) {
torrent::Object
apply_to_elapsed_time(const torrent::Object& rawArgs) {
auto cached_seconds = torrent::this_thread::cached_seconds().count();
auto value = rawArgs.as_value();
uint64_t arg = value >= 0 && value <= cached_seconds ? cached_seconds - value : 0;
uint64_t arg = cached_seconds - rawArgs.as_value();
char buffer[48];
snprintf(buffer, 48, "%2d:%02d:%02d", (int)(arg / 3600), (int)((arg / 60) % 60), (int)(arg % 60));
@@ -676,13 +674,8 @@ apply_math_basic(const char* name, Comp op, const torrent::Object::list_type& ar
throw torrent::input_error(std::string(name) + ": Wrong argument type");
}
if (divides && itr != args.begin()) {
if (rhs == 0)
throw torrent::input_error(std::string(name) + ": Division by zero!");
if (val == std::numeric_limits<int64_t>::min() && rhs == -1)
throw torrent::input_error(std::string(name) + ": Division overflow!");
}
if (divides && !rhs && itr != args.begin())
throw torrent::input_error(std::string(name) + ": Division by zero!");
val = itr == args.begin() ? rhs : op(val, rhs);
@@ -923,7 +916,6 @@ initialize_command_ui() {
rpc::rpc.mark_safe("view.set_visible");
rpc::rpc.mark_safe("view.set_not_visible");
rpc::rpc.mark_safe("view.list");
rpc::rpc.mark_safe("cat");
rpc::rpc.mark_safe("if");
-2
View File
@@ -118,6 +118,4 @@ private:
std::atomic<bool> m_shutdown_quick{};
};
extern Control* control;
#endif
+3 -13
View File
@@ -101,18 +101,7 @@ Download::set_throttle_name(const std::string& name) {
}
void
Download::set_directory(const std::string& path) {
if (!m_download.file_list()->is_multi_file())
return set_base_directory(path);
if (path.empty() || *path.rbegin() == '/')
return set_base_directory(path + m_download.info()->name_sanitized());
set_base_directory(path + "/" + m_download.info()->name_sanitized());
}
void
Download::set_base_directory(const std::string& path) {
Download::set_root_directory(const std::string& path) {
// If the download is open, hashed and has completed chunks make
// sure to verify that the download files are still present.
//
@@ -131,12 +120,13 @@ Download::set_base_directory(const std::string& path) {
!file_stat.update(file_list->front()->frozen_path().str()))) {
set_message("Cannot change the directory of an open download after the files have been moved.");
rpc::call_command("d.state.set", (int64_t)0, rpc::make_target(this));
control->core()->download_list()->close_directly(this);
throw torrent::input_error("Cannot change the directory of an open download after the files have been moved.");
}
control->core()->download_list()->close_files(this);
control->core()->download_list()->close_directly(this);
file_list->set_root_dir(expand_path(path));
bencode()->get_key("rtorrent").insert_key("directory", path);
+1 -3
View File
@@ -1,7 +1,6 @@
#ifndef RTORRENT_CORE_DOWNLOAD_H
#define RTORRENT_CORE_DOWNLOAD_H
#include <memory>
#include <torrent/common.h>
#include <torrent/download.h>
#include <torrent/download_info.h>
@@ -79,8 +78,7 @@ public:
uint32_t resume_flags() { return m_resumeFlags; }
void set_resume_flags(uint32_t flags) { m_resumeFlags = flags; }
void set_directory(const std::string& path);
void set_base_directory(const std::string& path);
void set_root_directory(const std::string& path);
void set_throttle_name(const std::string& name);
+77 -210
View File
@@ -27,8 +27,6 @@
namespace core {
static constexpr const char* session_invalid_message = "Session data is invalid, ignoring it";
bool
is_network_uri(const std::string& uri) {
return
@@ -37,15 +35,9 @@ is_network_uri(const std::string& uri) {
std::strncmp(uri.c_str(), "ftp://", 6) == 0;
}
bool
is_magnet_uri(const std::string& uri) {
return
std::strncmp(uri.c_str(), "magnet:?", 8) == 0;
}
static constexpr const char* session_invalid_message = "Session data is invalid, ignoring it";
namespace {
std::unique_ptr<torrent::Object>
static std::unique_ptr<torrent::Object>
download_factory_load_stream(const char* filename, bool* is_invalid) {
std::fstream stream(filename, std::ios::in | std::ios::binary);
@@ -63,34 +55,17 @@ download_factory_load_stream(const char* filename, bool* is_invalid) {
return obj;
}
std::unique_ptr<torrent::Object>
create_untrusted_object(torrent::Object& obj) {
auto trusted_object = std::make_unique<torrent::Object>(torrent::Object::create_map());
if (obj.has_key("info"))
trusted_object->insert_key_move("info", obj.get_key("info"));
if (obj.has_key("announce"))
trusted_object->insert_key_move("announce", obj.get_key("announce"));
if (obj.has_key("announce-list"))
trusted_object->insert_key_move("announce-list", obj.get_key("announce-list"));
if (obj.has_key("creation date"))
trusted_object->insert_key_move("creation date", obj.get_key("creation date"));
if (obj.has_key("created by"))
trusted_object->insert_key_move("created by", obj.get_key("created by"));
return trusted_object;
bool
is_magnet_uri(const std::string& uri) {
return
std::strncmp(uri.c_str(), "magnet:?", 8) == 0;
}
} // namespace anonymous
DownloadFactory::DownloadFactory(Manager* m) :
m_manager(m) {
DownloadFactory::DownloadFactory(Manager* m, bool trusted)
: m_manager(m),
m_trusted(trusted) {
m_task_load.slot() = std::bind(&DownloadFactory::receive_load, this);
m_task_commit.slot() = std::bind(&DownloadFactory::receive_commit, this);
// m_variables["connection_leech"] = rpc::call_command("protocol.connection.leech");
// m_variables["connection_seed"] = rpc::call_command("protocol.connection.seed");
@@ -103,49 +78,21 @@ DownloadFactory::DownloadFactory(Manager* m, bool trusted)
DownloadFactory::~DownloadFactory() {
torrent::this_thread::scheduler()->erase(&m_task_load);
torrent::this_thread::scheduler()->erase(&m_task_commit);
delete m_object;
}
void
DownloadFactory::load_trusted(const std::string& uri) {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::load_trusted() called on an untrusted object");
DownloadFactory::load(const std::string& uri) {
m_uri = uri;
m_task_load.slot() = [this]() { receive_load_trusted(); };
torrent::this_thread::scheduler()->wait_for(&m_task_load, 0ms);
}
// This function must be called before DownloadFactory::commit().
void
DownloadFactory::load_untrusted(const std::string& uri) {
if (m_trusted)
throw torrent::internal_error("DownloadFactory::load_untrusted() called on a trusted object");
m_uri = uri;
m_task_load.slot() = [this]() { receive_load_untrusted(); };
torrent::this_thread::scheduler()->wait_for(&m_task_load, 0ms);
}
void
DownloadFactory::load_raw_data_trusted(const std::string& input) {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::load_raw_data_trusted() called on an untrusted object");
DownloadFactory::load_raw_data(const std::string& input) {
if (m_stream)
throw torrent::internal_error("DownloadFactory::load_raw_data_trusted() called on an object with m_stream != NULL");
m_stream.reset(new std::stringstream(input));
m_loaded = true;
}
void
DownloadFactory::load_raw_data_untrusted(const std::string& input) {
if (m_trusted)
throw torrent::internal_error("DownloadFactory::load_raw_data_untrusted() called on an trusted object");
if (m_stream)
throw torrent::internal_error("DownloadFactory::load_raw_data_untrusted() called on an object with m_stream != NULL");
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
m_stream.reset(new std::stringstream(input));
m_loaded = true;
@@ -153,91 +100,53 @@ DownloadFactory::load_raw_data_untrusted(const std::string& input) {
void
DownloadFactory::commit() {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::commit() called on an untrusted object");
m_task_commit.slot() = [this]() { receive_commit(); };
torrent::this_thread::scheduler()->wait_for(&m_task_commit, 0ms);
}
void
DownloadFactory::process_load_network_uri() {
m_stream.reset(new std::stringstream);
DownloadFactory::receive_load() {
if (m_stream)
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
// TODO: Add trusted flag.
if (is_network_uri(m_uri)) {
m_stream.reset(new std::stringstream);
auto done_fn = [this]() { receive_loaded(); };
auto failed_fn = [this](const std::string& error) { receive_failed(error); };
auto done_fn = [this]() { receive_loaded(); };
auto failed_fn = [this](const std::string& error) { receive_failed(error); };
m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn);
m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn);
m_variables["tied_to_file"] = (int64_t)false;
}
m_variables["tied_to_file"] = (int64_t)false;
return;
}
void
DownloadFactory::process_load_magnet_uri() {
m_stream.reset(new std::stringstream());
*m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e";
if (is_magnet_uri(m_uri)) {
// DEBUG: Use m_object.
m_stream.reset(new std::stringstream());
*m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e";
m_variables["tied_to_file"] = (int64_t)false;
m_variables["tied_to_file"] = (int64_t)false;
receive_loaded();
}
receive_loaded();
return;
}
void
DownloadFactory::process_load_file_uri() {
std::fstream stream(expand_path(m_uri).c_str(), std::ios::in | std::ios::binary);
if (!stream.is_open())
return receive_failed("Could not open file");
m_object = std::make_unique<torrent::Object>();
m_object = new torrent::Object;
stream >> *m_object;
if (!stream.good())
return receive_failed("Reading torrent file failed");
m_is_file = true;
m_isFile = true;
receive_loaded();
}
void
DownloadFactory::receive_load_trusted() {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::receive_load_trusted() called on an untrusted object");
if (m_stream)
throw torrent::internal_error("DownloadFactory::receive_load_trusted() called on an object with null m_stream");
if (is_network_uri(m_uri))
return process_load_network_uri();
if (is_magnet_uri(m_uri))
return process_load_magnet_uri();
process_load_file_uri();
}
void
DownloadFactory::receive_load_untrusted() {
if (m_trusted)
throw torrent::internal_error("DownloadFactory::receive_load_untrusted() called on a trusted object");
if (m_stream)
throw torrent::internal_error("DownloadFactory::load*() called on an object with null m_stream");
if (is_network_uri(m_uri))
return process_load_network_uri();
// TODO: Don't need to handle untrusted commands magnet URIs.
// if (is_magnet_uri(m_uri))
// return process_load_magnet_uri();
throw torrent::internal_error("DownloadFactory::receive_load_untrusted() called on a non-network/magnet URI");
}
void
DownloadFactory::receive_loaded() {
m_loaded = true;
@@ -256,40 +165,30 @@ DownloadFactory::receive_commit() {
void
DownloadFactory::receive_success() {
if (!m_trusted && m_session)
throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with m_session == true");
bool session_invalid = false;
if (m_session && !m_is_file)
throw torrent::internal_error("DownloadFactory::receive_success() called on a non-file object with m_session == true");
auto rtorrent_object = download_factory_load_stream((expand_path(m_uri) + ".rtorrent").c_str(), &session_invalid);
auto libtorrent_resume_object = download_factory_load_stream((expand_path(m_uri) + ".libtorrent_resume").c_str(), &session_invalid);
bool session_invalid = false;
uint32_t tracker_key = tracker_key = random() % (std::numeric_limits<uint32_t>::max() - 1) + 1;
if (session_invalid)
lt_log_print(torrent::LOG_ERROR, "%s: %s", session_invalid_message, m_uri.c_str());
std::unique_ptr<torrent::Object> rtorrent_object, libtorrent_resume_object;
uint32_t tracker_key;
if (m_session) {
rtorrent_object = download_factory_load_stream((expand_path(m_uri) + ".rtorrent").c_str(), &session_invalid);
libtorrent_resume_object = download_factory_load_stream((expand_path(m_uri) + ".libtorrent_resume").c_str(), &session_invalid);
if (rtorrent_object && rtorrent_object->has_key_value("key"))
tracker_key = rtorrent_object->get_key_value("key");
else
tracker_key = random() % (std::numeric_limits<uint32_t>::max() - 1) + 1;
if (session_invalid)
lt_log_print(torrent::LOG_ERROR, "%s: %s", session_invalid_message, m_uri.c_str());
Download* download = m_stream != nullptr ?
m_manager->download_list()->create(m_stream.get(), tracker_key, m_printLog) :
m_manager->download_list()->create(m_object, tracker_key, m_printLog);
if (rtorrent_object && rtorrent_object->has_key_value("key"))
tracker_key = rtorrent_object->get_key_value("key");
}
m_object = NULL;
// TODO: This adds the torrent, so untrusted can add brokent torrents.
if (m_stream != nullptr)
object_from_stream();
if (m_trusted)
m_object = create_untrusted_object(*m_object);
Download* download = m_manager->download_list()->create(std::move(m_object), tracker_key, m_print_log);
if (download == nullptr) {
// core::Manager should already have added the error message to the log.
if (download == NULL) {
// core::Manager should already have added the error message to
// the log.
m_slot_finished();
return;
}
@@ -298,49 +197,39 @@ DownloadFactory::receive_success() {
download->set_hash_failed(true);
download->set_message(session_invalid_message);
if (m_print_log)
if (m_printLog)
m_manager->push_log_std(std::string(session_invalid_message) + ": \"" + m_uri + "\"");
}
torrent::Object* root = download->bencode();
if (download->download()->info()->is_meta_download()) {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with a meta download");
torrent::Object& meta = root->insert_key("rtorrent_meta_download", torrent::Object::create_map());
meta.insert_key("start", m_start);
meta.insert_key("print_log", m_print_log);
meta.insert_key("print_log", m_printLog);
// TODO: ADD UNTRUSTED!!!
auto& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list();
torrent::Object::list_type& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list();
for (auto& m_command : m_commands)
commands.push_back(m_command);
}
if (m_session) {
if (!m_trusted)
throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with m_session == true");
if (rtorrent_object)
root->insert_key_move("rtorrent", *rtorrent_object);
if (libtorrent_resume_object)
root->insert_key_move("libtorrent_resume", *libtorrent_resume_object);
} else if (!m_trusted) {
if (root->has_key("rtorrent") || root->has_key("libtorrent_resume"))
throw torrent::internal_error("DownloadFactory::receive_success() called on an untrusted object with 'rtorrent' or 'libtorrent_resume' keys");
} else {
// We only allow session torrents to keep their 'rtorrent/libtorrent' sections. The
// "fast_resume" section should be safe to keep.
// We only allow session torrents to keep their
// 'rtorrent/libtorrent' sections. The "fast_resume" section
// should be safe to keep.
root->erase_key("rtorrent");
}
auto* rtorrent = &root->insert_preserve_copy("rtorrent", torrent::Object::create_map()).first->second;
auto& resumeObject = root->insert_preserve_copy("libtorrent_resume", torrent::Object::create_map()).first->second;
torrent::Object* rtorrent = &root->insert_preserve_copy("rtorrent", torrent::Object::create_map()).first->second;
torrent::Object& resumeObject = root->insert_preserve_copy("libtorrent_resume", torrent::Object::create_map()).first->second;
rtorrent->insert_key("key", download->tracker_controller().key());
@@ -370,7 +259,7 @@ DownloadFactory::receive_success() {
}
// Skip forcing trackers to scrape when rtorrent starts
if (m_init_load && rpc::call_command_value("trackers.delay_scrape"))
if (m_initLoad && rpc::call_command_value("trackers.delay_scrape"))
download->set_resume_flags(torrent::Download::start_skip_tracker);
// Check first if we already have these values set in the session
@@ -412,7 +301,7 @@ DownloadFactory::receive_success() {
lt_log_print(torrent::LOG_ERROR, "%s: %s", msg.c_str(), m_uri.c_str());
if (m_print_log)
if (m_printLog)
m_manager->push_log_std(msg + ": \"" + m_uri + "\"");
download->set_hash_failed(true);
@@ -436,13 +325,8 @@ DownloadFactory::receive_success() {
if (torrent::log_groups[torrent::LOG_TORRENT_DEBUG].valid())
log_created(download, rtorrent);
if (m_trusted) {
for (const auto& command : m_commands)
rpc::parse_command_multiple_std(command, rpc::make_target(download));
} else {
// TODO: CALL UNTRUSTED COMMANDS
}
for (const auto& command : m_commands)
rpc::parse_command_multiple_std(command, rpc::make_target(download));
if (m_manager->download_list()->find(infohash) == m_manager->download_list()->end())
throw torrent::input_error("The newly created download was removed.");
@@ -456,7 +340,7 @@ DownloadFactory::receive_success() {
} catch (torrent::input_error& e) {
std::string msg = "Command on torrent creation failed: " + std::string(e.what());
if (m_print_log)
if (m_printLog)
m_manager->push_log_std(msg);
if (m_manager->download_list()->find(infohash) != m_manager->download_list()->end()) {
@@ -470,18 +354,6 @@ DownloadFactory::receive_success() {
m_slot_finished();
}
void
DownloadFactory::receive_failed(const std::string& msg) {
if (m_print_log) {
if (m_trusted)
m_manager->push_log_std("Failed to load torrent: " + msg + ": \"" + m_uri + "\"");
else
m_manager->push_log_std("Failed to load untrusted torrent: " + msg);
}
m_slot_finished();
}
void
DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
std::stringstream dump;
@@ -508,6 +380,15 @@ DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
lt_log_print_dump(torrent::LOG_TORRENT_DEBUG, dump_str.c_str(), dump_str.size(), "Creating new download:");
}
void
DownloadFactory::receive_failed(const std::string& msg) {
// Add message to log.
if (m_printLog)
m_manager->push_log_std(msg + ": \"" + m_uri + "\"");
m_slot_finished();
}
void
DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorrent) {
auto cached_seconds = torrent::this_thread::cached_seconds().count();
@@ -531,7 +412,7 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre
rtorrent->insert_preserve_copy("timestamp.finished", (int64_t)0);
rtorrent->insert_preserve_copy("tied_to_file", "");
rtorrent->insert_key("loaded_file", m_is_file ? m_uri : std::string());
rtorrent->insert_key("loaded_file", m_isFile ? m_uri : std::string());
if (rtorrent->has_key_value("priority"))
rpc::call_command("d.priority.set", rtorrent->get_key_value("priority") % 4, rpc::make_target(download));
@@ -563,18 +444,4 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre
rtorrent->insert_preserve_copy("choke_heuristics.down.seed", std::string());
}
void
DownloadFactory::object_from_stream() {
m_object = std::make_unique<torrent::Object>();
*m_stream >> *m_object;
if (!m_stream->good() || !m_object->is_map()) {
if (m_print_log)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, stream is not a valid torrent.");
throw torrent::input_error("Invalid torrent data");
}
}
}
+14 -27
View File
@@ -24,18 +24,14 @@ public:
typedef std::vector<std::string> command_list_type;
// Do not destroy this object while it is in a HttpQueue.
DownloadFactory(Manager* m, bool trusted);
DownloadFactory(Manager* m);
~DownloadFactory();
// Calling of receive_load() is delayed so you can change whatever
// you want without fear of the slots being triggered as you call
// load() or commit().
void load_trusted(const std::string& uri);
void load_untrusted(const std::string& uri);
void load_raw_data_trusted(const std::string& input);
void load_raw_data_untrusted(const std::string& input);
void load(const std::string& uri);
void load_raw_data(const std::string& input);
void commit();
command_list_type& commands() { return m_commands; }
@@ -47,21 +43,16 @@ public:
bool get_start() const { return m_start; }
void set_start(bool v) { m_start = v; }
bool get_init_load() const { return m_init_load; }
void set_init_load(bool v) { m_init_load = v; }
bool get_init_load() const { return m_initLoad; }
void set_init_load(bool v) { m_initLoad = v; }
bool print_log() const { return m_print_log; }
void set_print_log(bool v) { m_print_log = v; }
bool print_log() const { return m_printLog; }
void set_print_log(bool v) { m_printLog = v; }
void slot_finished(slot_void s) { m_slot_finished = s; }
private:
void process_load_network_uri();
void process_load_magnet_uri();
void process_load_file_uri();
void receive_load_trusted();
void receive_load_untrusted();
void receive_load();
void receive_loaded();
void receive_commit();
void receive_success();
@@ -71,23 +62,19 @@ private:
void initialize_rtorrent(Download* download, torrent::Object* rtorrent);
void object_from_stream();
Manager* m_manager;
std::shared_ptr<std::iostream> m_stream;
torrent::Object* m_object{};
Manager* m_manager;
std::shared_ptr<std::iostream> m_stream;
std::unique_ptr<torrent::Object> m_object{};
bool m_trusted{};
bool m_commited{};
bool m_loaded{};
std::string m_uri;
bool m_session{};
bool m_start{};
bool m_print_log{true};
bool m_is_file{};
bool m_init_load{};
bool m_printLog{true};
bool m_isFile{};
bool m_initLoad{};
command_list_type m_commands;
torrent::Object::map_type m_variables;
+62 -60
View File
@@ -37,7 +37,7 @@ namespace core {
inline void
DownloadList::check_contains([[maybe_unused]] Download* d) {
#ifdef USE_EXTRA_DEBUG
if (std::find_if(begin(), end(), [d](const auto& entry) { return entry.get() == d; }) == end())
if (std::find(begin(), end(), d) == end())
throw torrent::internal_error("DownloadList::check_contains(...) failed.");
#endif
}
@@ -54,6 +54,7 @@ DownloadList::clear() {
base_type::pop_back();
torrent::download_remove(*download->download());
delete download;
} catch (torrent::internal_error& e) {
lt_log_print(torrent::LOG_ERROR, "DownloadList::clear() failed to close or remove download: %s", e.what());
@@ -69,7 +70,7 @@ DownloadList::clear() {
void
DownloadList::session_save() {
for (auto& download : *this)
session_thread::manager()->save_resume_download(download.get());
session_thread::manager()->save_resume_download(download);
control->dht_manager()->save_dht_cache();
control->ui()->save_input_history();
@@ -77,7 +78,7 @@ DownloadList::session_save() {
DownloadList::iterator
DownloadList::find(const torrent::HashString& hash) {
return std::find_if(begin(), end(), [hash](const auto& d) { return hash == d->info()->hash(); });
return std::find_if(begin(), end(), [hash](Download* d) { return hash == d->info()->hash(); });
}
DownloadList::iterator
@@ -90,28 +91,60 @@ DownloadList::find_hex(const char* hash) {
if (torrent::utils::transform_from_hex(hash, hash + 40, key) != key.end())
return end();
return std::find_if(begin(), end(), [key](const auto& d) { return key == d->info()->hash(); });
return std::find_if(begin(), end(), [key](Download* d) { return key == d->info()->hash(); });
}
Download*
DownloadList::find_hex_ptr(const char* hash) {
iterator itr = find_hex(hash);
return itr != end() ? itr->get() : NULL;
return itr != end() ? *itr : NULL;
}
Download*
DownloadList::create(std::unique_ptr<torrent::Object> obj, uint32_t tracker_key, bool printLog) {
DownloadList::create(torrent::Object* obj, uint32_t tracker_key, bool printLog) {
torrent::Download download;
auto obj_ptr = obj.get();
try {
download = torrent::download_add(obj.release(), tracker_key);
download = torrent::download_add(obj, tracker_key);
} catch (torrent::local_error& e) {
// TODO: Fix download_add so it takes the unique_ptr.
delete obj_ptr;
if (printLog)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what());
delete obj;
return NULL;
}
// There's no non-critical exceptions that should be throwable by
// the ctor, so don't catch.
return new Download(download);
}
Download*
DownloadList::create(std::istream* str, uint32_t tracker_key, bool printLog) {
torrent::Object* object = new torrent::Object;
torrent::Download download;
try {
*str >> *object;
// Don't throw input_error from here as gcc-3.3.5 produces bad
// code.
if (str->fail()) {
delete object;
if (printLog)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent.");
return NULL;
}
download = torrent::download_add(object, tracker_key);
} catch (torrent::local_error& e) {
delete object;
if (printLog)
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download: %s", e.what());
@@ -126,7 +159,7 @@ DownloadList::create(std::unique_ptr<torrent::Object> obj, uint32_t tracker_key,
DownloadList::iterator
DownloadList::insert(Download* download) {
iterator itr = base_type::insert(end(), std::shared_ptr<Download>(download));
iterator itr = base_type::insert(end(), download);
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Inserting download.");
@@ -137,7 +170,7 @@ DownloadList::insert(Download* download) {
// This needs to be separated into two different calls to ensure
// the download remains in the view.
for (auto v : *control->view_manager())
v->insert(*itr);
v->insert(download);
for (auto v : *control->view_manager())
v->filter_download(download);
@@ -154,7 +187,7 @@ DownloadList::insert(Download* download) {
void
DownloadList::erase_ptr(Download* download) {
erase(std::find_if(begin(), end(), [download](const auto& entry) { return entry.get() == download; }));
erase(std::find(begin(), end(), download));
}
DownloadList::iterator
@@ -168,14 +201,15 @@ DownloadList::erase(iterator itr) {
(*itr)->set_hash_failed(true);
close(*itr);
session_thread::manager()->remove_download(itr->get());
session_thread::manager()->remove_download(*itr);
DL_TRIGGER_EVENT(*itr, "event.download.erased");
for (auto v : *control->view_manager())
v->erase(itr->get());
v->erase(*itr);
torrent::download_remove(*(*itr)->download());
delete *itr;
return base_type::erase(itr);
}
@@ -222,11 +256,9 @@ DownloadList::close(Download* download) {
}
}
// Releases the files without changing the download's state, for callers that
// need the files closed and will keep using the download.
void
DownloadList::close_files(Download* download) {
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download files.");
DownloadList::close_directly(Download* download) {
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download directly.");
if (download->download()->info()->is_active()) {
download->download()->stop(torrent::Download::stop_skip_tracker);
@@ -239,44 +271,6 @@ DownloadList::close_files(Download* download) {
download->download()->close();
}
void
DownloadList::close_directly(Download* download) {
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download directly.");
bool was_active = download->download()->info()->is_active();
bool was_open = download->download()->info()->is_open();
close_files(download);
set_state_stopped(download);
if (was_active) {
DL_TRIGGER_EVENT(download, "event.download.paused");
update_paused_state(download);
}
if (was_open) {
DL_TRIGGER_EVENT(download, "event.download.hash_removed");
DL_TRIGGER_EVENT(download, "event.download.closed");
}
}
void
DownloadList::set_state_stopped(Download* download) {
control->view_manager()->find_ptr_throw("stopped")->set_visible(download);
rpc::call_command("d.state.set", (int64_t)0, rpc::make_target(download));
}
void
DownloadList::update_paused_state(Download* download) {
rpc::call_command("d.state_changed.set", torrent::this_thread::cached_seconds().count(), rpc::make_target(download));
rpc::call_command("d.state_counter.set", rpc::call_command_value("d.state_counter", rpc::make_target(download)), rpc::make_target(download));
// If initial seeding is complete, don't try it again when restarting.
if (download->is_done() &&
rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)).as_string() == "initial_seed")
rpc::call_command("d.connection_seed.set", rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)), rpc::make_target(download));
}
void
DownloadList::close_quick(Download* download) {
lt_log_print_info(torrent::LOG_TORRENT_INFO, download->info(), "download_list", "Closing download quickly.");
@@ -451,7 +445,15 @@ DownloadList::pause(Download* download, int flags) {
// view.
DL_TRIGGER_EVENT(download, "event.download.paused");
update_paused_state(download);
auto cached_seconds = torrent::this_thread::cached_seconds().count();
rpc::call_command("d.state_changed.set", cached_seconds, rpc::make_target(download));
rpc::call_command("d.state_counter.set", rpc::call_command_value("d.state_counter", rpc::make_target(download)), rpc::make_target(download));
// If initial seeding is complete, don't try it again when restarting.
if (download->is_done() &&
rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)).as_string() == "initial_seed")
rpc::call_command("d.connection_seed.set", rpc::call_command("d.connection_current", torrent::Object(), rpc::make_target(download)), rpc::make_target(download));
// Save the state after all the slots, etc have been called so we
// include the modifications they may make.
@@ -522,7 +524,7 @@ DownloadList::hash_done(Download* download) {
// If the download was previously completed but the files were
// f.ex deleted, then we clear the state and complete.
if (rpc::call_command_value("d.complete", rpc::make_target(download)) && !download->is_done()) {
set_state_stopped(download);
rpc::call_command("d.state.set", (int64_t)0, rpc::make_target(download));
download->set_message("Download registered as completed, but hash check returned unfinished chunks.");
}
+4 -16
View File
@@ -3,7 +3,6 @@
#include <iosfwd>
#include <list>
#include <memory>
#include <string>
namespace torrent {
@@ -21,9 +20,9 @@ class Download;
//
// Fix apply_on_ratio if the base_type is changed.
class DownloadList : private std::list<std::shared_ptr<Download>> {
class DownloadList : private std::list<Download*> {
public:
typedef std::list<std::shared_ptr<Download>> base_type;
typedef std::list<Download*> base_type;
using base_type::iterator;
using base_type::const_iterator;
@@ -52,7 +51,8 @@ public:
Download* find_hex_ptr(const char* hash);
// Might move this to DownloadFactory.
Download* create(std::unique_ptr<torrent::Object> obj, uint32_t tracker_key, bool printLog);
Download* create(std::istream* str, uint32_t tracker_key, bool printLog);
Download* create(torrent::Object* obj, uint32_t tracker_key, bool printLog);
iterator insert(Download* d);
@@ -64,17 +64,8 @@ public:
bool open(Download* d);
void open_throw(Download* d);
// Overloads for the list's own entries, so callers iterating it do not need
// to unwrap.
bool open(const value_type& d) { return open(d.get()); }
void close(const value_type& d) { close(d.get()); }
void close_quick(const value_type& d) { close_quick(d.get()); }
void pause(const value_type& d) { pause(d.get()); }
void resume(const value_type& d) { resume(d.get()); }
void close(Download* d);
void close_directly(Download* d);
void close_files(Download* d);
void close_quick(Download* d);
void close_throw(Download* d);
@@ -132,9 +123,6 @@ private:
void hash_done(Download* d);
void hash_queue(Download* d, int type);
void set_state_stopped(Download* d);
void update_paused_state(Download* d);
inline void check_contains(Download* d);
void received_finished(Download* d);
+36 -79
View File
@@ -37,8 +37,6 @@
namespace core {
void path_expand(std::vector<std::string>* paths, const std::string& pattern);
const int Manager::create_start;
const int Manager::create_tied;
const int Manager::create_quiet;
@@ -156,10 +154,10 @@ Manager::cleanup() {
void
Manager::shutdown(bool force) {
if (!force) {
for (const auto& d : *m_download_list)
m_download_list->pause_default(d.get());
for (auto d : *m_download_list)
m_download_list->pause_default(d);
} else {
for (const auto& d : *m_download_list)
for (auto d : *m_download_list)
m_download_list->close_quick(d);
}
}
@@ -197,7 +195,7 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
return;
// Adding download.
DownloadFactory* f = new DownloadFactory(this, true);
DownloadFactory* f = new DownloadFactory(this);
f->variables()["tied_to_file"] = (int64_t)(bool)(flags & create_tied);
f->commands().insert(f->commands().end(), commands.begin(), commands.end());
@@ -206,52 +204,29 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
f->set_print_log(!(flags & create_quiet));
f->slot_finished([f]() { delete f; });
if (flags & create_raw_data) {
f->load_raw_data_trusted(uri);
} else if (is_data_uri(uri)) {
if (is_data_uri(uri)) {
// Allow the use of data URIs, primarily for JSON-RPC which
// doesn't have a defined mechanism for binary data
f->load_raw_data_trusted(decode_data_uri(uri));
f->load_raw_data(decode_data_uri(uri));
f->variables()["tied_to_file"] = (int64_t)false;
} else if (flags & create_raw_data) {
f->load_raw_data(uri);
} else {
f->load_trusted(uri);
f->load(uri);
}
f->commit();
}
void
Manager::try_create_download_expand(const std::string& uri, int flags, command_list_type commands) {
if (flags & create_raw_data) {
try_create_download(uri, flags, commands);
return;
}
std::vector<std::string> paths;
paths.reserve(256);
path_expand(&paths, uri);
if (!paths.empty())
for (auto& path : paths)
try_create_download(path, flags, commands);
else
try_create_download(uri, flags, commands);
}
void
Manager::try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile) {
DownloadFactory* f = new DownloadFactory(this, true);
DownloadFactory* f = new DownloadFactory(this);
f->variables()["tied_to_file"] = (int64_t)true;
f->variables()["tied_file"] = metafile;
f->variables()["tied_file"] = metafile;
torrent::Object& meta = bencode->get_key("rtorrent_meta_download");
torrent::Object::list_type& commands = meta.get_key_list("commands");
for (const auto& command : commands)
f->commands().insert(f->commands().end(), command.as_string());
@@ -264,46 +239,13 @@ Manager::try_create_download_from_meta_download(torrent::Object* bencode, const
std::stringstream s;
s.imbue(std::locale::classic());
s << *bencode;
f->load_raw_data_trusted(s.str());
f->load_raw_data(s.str());
f->commit();
}
void
Manager::try_create_download_untrusted(const std::string& uri, int flags, const command_list_type& commands) {
// TODO: Need to check if we are allowed, also rate limit.
if (!(flags & create_raw_data) &&
!is_network_uri(uri) &&
!is_magnet_uri(uri) &&
!is_data_uri(uri)) {
push_log_std("URI type not allowed for untrusted loads.");
return;
}
DownloadFactory* f = new DownloadFactory(this, false);
f->commands().insert(f->commands().end(), commands.begin(), commands.end());
f->set_start(flags & create_start);
f->set_print_log(!(flags & create_quiet));
f->slot_finished([f]() { delete f; });
if (flags & create_raw_data) {
f->load_raw_data_untrusted(uri);
} else if (is_data_uri(uri)) {
// Allow the use of data URIs, primarily for JSON-RPC which
// doesn't have a defined mechanism for binary data
f->load_raw_data_untrusted(decode_data_uri(uri));
f->variables()["tied_to_file"] = (int64_t)false;
} else {
// f->load_untrusted(uri);
throw torrent::internal_error("Manager::try_create_download_untrusted() unimplemented.");
}
f->commit();
utils::Directory
path_expand_transform(std::string path, const utils::directory_entry& entry) {
return path + entry.s_name;
}
namespace {
@@ -362,11 +304,6 @@ split_iterator(const Sequence&) {
}
utils::Directory
path_expand_transform(std::string path, const utils::directory_entry& entry) {
return path + entry.s_name;
}
// Move this somewhere better.
void
path_expand(std::vector<std::string>* paths, const std::string& pattern) {
@@ -423,6 +360,26 @@ manager_equal_tied(const std::string& path, Download* download) {
return path == rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
}
void
Manager::try_create_download_expand(const std::string& uri, int flags, command_list_type commands) {
if (flags & create_raw_data) {
try_create_download(uri, flags, commands);
return;
}
std::vector<std::string> paths;
paths.reserve(256);
path_expand(&paths, uri);
if (!paths.empty())
for (auto& path : paths)
try_create_download(path, flags, commands);
else
try_create_download(uri, flags, commands);
}
// DownloadList's hashing related functions don't actually start the
// hashing, it only reacts to events. This functions checks the
// hashing view and starts hashing if nessesary.
@@ -448,7 +405,7 @@ Manager::receive_hashing_changed() {
continue;
try {
m_download_list->open_throw(itr->get());
m_download_list->open_throw(*itr);
// Since the bitfield is allocated on loading of resume load or
// hash start, and unallocated on close, we know that if it it
-2
View File
@@ -78,8 +78,6 @@ public:
void try_create_download_expand(const std::string& uri, int flags, command_list_type commands = command_list_type());
void try_create_download_from_meta_download(torrent::Object* bencode, const std::string& metafile);
void try_create_download_untrusted(const std::string& uri, int flags, const command_list_type& commands);
private:
void create_http(const std::string& uri);
void create_final(std::istream* s);
+16 -40
View File
@@ -16,20 +16,10 @@
namespace core {
// Also add focus thingie here?
// Matches the list entry that owns a given download.
inline auto
entry_is(Download* download) {
return [download](const std::shared_ptr<Download>& entry) { return entry.get() == download; };
}
struct view_downloads_compare {
view_downloads_compare(const torrent::Object& cmd) :
m_command(cmd) {}
bool operator()(const std::shared_ptr<Download>& d1, const std::shared_ptr<Download>& d2) const {
return (*this)(d1.get(), d2.get());
}
bool operator()(Download* d1, Download* d2) const {
try {
if (m_command.is_empty())
@@ -64,10 +54,6 @@ struct view_downloads_filter {
view_downloads_filter(const torrent::Object& cmd, const torrent::Object& cmd2) :
m_command(cmd), m_command2(cmd2) {}
bool operator()(const std::shared_ptr<Download>& d1) const {
return (*this)(d1.get());
}
bool operator()(Download* d1) const {
return this->evalCmd(m_command, d1) && this->evalCmd(m_command2, d1);
}
@@ -166,7 +152,7 @@ View::initialize(const std::string& name) {
void
View::erase(Download* download) {
iterator itr = std::find_if(base_type::begin(), base_type::end(), entry_is(download));
iterator itr = std::find(base_type::begin(), base_type::end(), download);
if (itr >= end_visible()) {
erase_internal(itr);
@@ -179,24 +165,22 @@ View::erase(Download* download) {
void
View::set_visible(Download* download) {
iterator itr = std::find_if(begin_filtered(), end_filtered(), entry_is(download));
iterator itr = std::find(begin_filtered(), end_filtered(), download);
if (itr == end_filtered())
return;
// Don't optimize erase since we want to keep the order of the
// non-visible elements.
auto entry = *itr;
base_type::erase(itr);
insert_visible(entry);
insert_visible(download);
rpc::call_object_nothrow(m_event_added, rpc::make_target(download));
}
void
View::set_not_visible(Download* download) {
iterator itr = std::find_if(begin_visible(), end_visible(), entry_is(download));
iterator itr = std::find(begin_visible(), end_visible(), download);
if (itr == end_visible())
return;
@@ -206,10 +190,8 @@ View::set_not_visible(Download* download) {
// Don't optimize erase since we want to keep the order of the
// non-visible elements.
auto entry = *itr;
base_type::erase(itr);
base_type::push_back(entry);
base_type::push_back(download);
rpc::call_object_nothrow(m_event_removed, rpc::make_target(download));
}
@@ -259,12 +241,12 @@ View::prev_focus(unsigned int i) {
void
View::sort() {
Download* curFocus = focus() != end_visible() ? focus()->get() : NULL;
Download* curFocus = focus() != end_visible() ? *focus() : NULL;
// Don't go randomly switching around equivalent elements.
std::stable_sort(begin(), end_visible(), view_downloads_compare(m_sortCurrent));
m_focus = position(std::find_if(begin(), end_visible(), entry_is(curFocus)));
m_focus = position(std::find(begin(), end_visible(), curFocus));
emit_changed();
}
@@ -298,10 +280,10 @@ View::filter() {
// set the elements to NULL as we trigger commands on them. Or
// perhaps always clear them, thus not throwing anything.
if (!m_event_removed.is_empty())
std::for_each(changed.begin(), splitChanged, [this](const auto& d) { rpc::call_object_d_nothrow(m_event_removed, d.get()); });
std::for_each(changed.begin(), splitChanged, std::bind(&rpc::call_object_d_nothrow, m_event_removed, std::placeholders::_1));
if (!m_event_added.is_empty())
std::for_each(changed.begin(), splitChanged, [this](const auto& d) { rpc::call_object_d_nothrow(m_event_added, d.get()); });
std::for_each(changed.begin(), splitChanged, std::bind(&rpc::call_object_d_nothrow, m_event_added, std::placeholders::_1));
emit_changed();
}
@@ -312,23 +294,21 @@ View::filter_by(const torrent::Object& condition, View::base_type& result) {
view_downloads_filter matches = view_downloads_filter(condition, m_temp_filter);
for (iterator itr = begin_visible(); itr != end_visible(); ++itr)
if (matches(itr->get()))
if (matches(*itr))
result.push_back(*itr);
}
void
View::filter_download(core::Download* download) {
iterator itr = std::find_if(base_type::begin(), base_type::end(), entry_is(download));
iterator itr = std::find(base_type::begin(), base_type::end(), download);
if (itr == base_type::end())
throw torrent::internal_error("View::filter_download(...) could not find download.");
if (view_downloads_filter(m_filter, m_temp_filter)(download)) {
if (itr >= end_visible()) {
auto entry = *itr;
erase_internal(itr);
insert_visible(entry);
insert_visible(download);
rpc::call_object_nothrow(m_event_added, rpc::make_target(download));
@@ -337,20 +317,16 @@ View::filter_download(core::Download* download) {
// already visible.
//
// Consider removing this.
auto entry = *itr;
erase_internal(itr);
insert_visible(entry);
insert_visible(download);
}
} else {
if (itr >= end_visible())
return;
auto entry = *itr;
erase_internal(itr);
base_type::push_back(entry);
base_type::push_back(download);
rpc::call_object_nothrow(m_event_removed, rpc::make_target(download));
}
@@ -369,8 +345,8 @@ View::clear_filter_on() {
}
inline void
View::insert_visible(const std::shared_ptr<Download>& d) {
auto itr = std::find_if(begin_visible(), end_visible(), [this, &d](const auto& d2) { return view_downloads_compare(m_sortNew)(d.get(), d2.get()); });
View::insert_visible(Download* d) {
auto itr = std::find_if(begin_visible(), end_visible(), [this, d](auto d2) { return view_downloads_compare(m_sortNew)(d, d2); });
m_size++;
m_focus += (m_focus >= position(itr));
+5 -6
View File
@@ -15,7 +15,6 @@
#include <functional>
#include <list>
#include <memory>
#include <string>
#include <vector>
#include <torrent/object.h>
@@ -27,9 +26,9 @@ namespace core {
class Download;
class View : private std::vector<std::shared_ptr<Download>> {
class View : private std::vector<Download*> {
public:
typedef std::vector<std::shared_ptr<Download>> base_type;
typedef std::vector<Download*> base_type;
typedef std::function<void()> slot_void;
typedef std::list<slot_void> signal_void;
@@ -73,7 +72,7 @@ public:
emit_changed();
}
void insert(const std::shared_ptr<Download>& download) { base_type::push_back(download); }
void insert(Download* download) { base_type::push_back(download); }
void erase(Download* download);
void set_visible(Download* download);
@@ -125,9 +124,9 @@ private:
View(const View&);
void operator=(const View&);
void push_back(const std::shared_ptr<Download>& d) { base_type::push_back(d); }
void push_back(Download* d) { base_type::push_back(d); }
inline void insert_visible(const std::shared_ptr<Download>& d);
inline void insert_visible(Download* d);
inline void erase_internal(iterator itr);
void emit_changed();
+5 -5
View File
@@ -37,7 +37,7 @@ WindowDownloadList::set_view(core::View* l) {
// Return a pair of ints, representing a) the ncurses attributes and b) the ncurses color pair ID to use
std::pair<int, int>
WindowDownloadList::get_attr_color(core::View::iterator selected) {
core::Download* item = selected->get();
core::Download* item = *selected;
unsigned long focus_attr = selected == m_view->focus() ? m_canvas->attr_map().at(RCOLOR_FOCUS) : 0;
int offset = (((selected - m_view->begin_visible()) & 1) + 1) * RCOLOR_MAX; // Determine the even/odd offset for the color pair
bool active = item->is_open() && item->is_active();
@@ -132,15 +132,15 @@ WindowDownloadList::redraw() {
ColorKind focus_color = is_focused ? RCOLOR_FOCUS : RCOLOR_LABEL;
auto attr_color = get_attr_color(range.first);
print_download_title(buffer.data(), last, range.first->get());
print_download_title(buffer.data(), last, *range.first);
m_canvas->print(0, pos, "%c %s", focus_char, buffer.data());
m_canvas->set_attr(2, pos++, -1, attr_color.first, attr_color.second);
print_download_info_full(buffer.data(), last, range.first->get());
print_download_info_full(buffer.data(), last, *range.first);
m_canvas->print(0, pos, "%c %s", focus_char, buffer.data());
m_canvas->set_attr(2, pos++, -1, focus_color);
print_download_status(buffer.data(), last, range.first->get());
print_download_status(buffer.data(), last, *range.first);
m_canvas->print(0, pos, "%c %s", focus_char, buffer.data());
m_canvas->set_attr(2, pos++, -1, focus_color);
@@ -152,7 +152,7 @@ WindowDownloadList::redraw() {
char focus_char = range.first == m_view->focus() ? '*' : ' ';
auto attr_color = get_attr_color(range.first);
print_download_info_compact(buffer.data(), last, range.first->get());
print_download_info_compact(buffer.data(), last, *range.first);
m_canvas->print(0, pos, "%c %s", focus_char, buffer.data());
m_canvas->set_attr(2, pos++, -1, attr_color.first, attr_color.second);
+1 -2
View File
@@ -11,8 +11,7 @@ namespace input {
void
InputEvent::insert() {
torrent::this_thread::poll()->open(this);
torrent::this_thread::poll()->insert_read(this);
torrent::this_thread::poll()->open_and_insert_read(this);
}
void
+9 -14
View File
@@ -112,8 +112,9 @@ main(int argc, char** argv) {
torrent::log_initialize();
// TODO: Create a fake thread object for initializing other processes and enabling logging.
torrent::initialize_main_thread();
torrent::runtime::initialize_worker_process_and_main_thread([argc, argv]() {
parse_config_file(argc, argv, [](auto& path) { parse_config_file_comments("worker", path); });
});
// Block SIGCHLD until all threads are created, then unblock on main-thread, to avoid SIGCHLD
// interrupting other threads.
@@ -136,12 +137,10 @@ main(int argc, char** argv) {
// # do:log.open_file=system,/usr/rakshasa/system.log
// # do:log.add_output=system,system
//
parse_config_file(argc, argv, [](auto& path) {
if (path.empty())
return;
parse_config_file_comments(path);
});
// # 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); });
control = new Control;
@@ -164,6 +163,8 @@ main(int argc, char** argv) {
torrent::initialize();
torrent::main_thread::set_client_callback(&client_perform);
torrent::runtime::initialize_worker_process();
scgi::ThreadScgi::create_thread();
session::ThreadSession::create_thread();
@@ -379,12 +380,6 @@ main(int argc, char** argv) {
lt_log_print(torrent::LOG_WARN, "network.max_open_files.set is deprecated, use system.sockets.files.min_alloc.set instead.");
});
// TODO: Keep d.directory_base for a while as it is widely used.
CMD_REDIRECT("d.directory_base", "d.directory");
CMD_REDIRECT("d.directory_base.set", "d.directory.base.set");
rpc::rpc.mark_safe("d.directory_base");
// if (rpc::call_command_value("method.use_intermediate") == 1) {
// } else if (rpc::call_command_value("method.use_intermediate") == 2) {
+1 -1
View File
@@ -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);
}
+1 -9
View File
@@ -1,7 +1,5 @@
#include "config.h"
#include <limits>
#include "core/download.h"
#include "parse.h"
@@ -43,13 +41,7 @@ command_base_call_value_base(command_base* command_raw, target_type target, cons
return command_base::_call<typename command_value_function<T>::type, T>(command_raw, target, val);
}
auto value = arg.as_value();
if (value > std::numeric_limits<int64_t>::max() / unit ||
value < std::numeric_limits<int64_t>::min() / unit)
throw torrent::input_error("Value out of range.");
return command_base::_call<typename command_value_function<T>::type, T>(command_raw, target, unit * value);
return command_base::_call<typename command_value_function<T>::type, T>(command_raw, target, unit * arg.as_value());
}
template <typename T> const torrent::Object
-5
View File
@@ -1,7 +1,6 @@
#ifndef RTORRENT_RPC_COMMAND_MAP_H
#define RTORRENT_RPC_COMMAND_MAP_H
#include <memory>
#include <map>
#include <string>
#include <cstring>
@@ -105,10 +104,6 @@ inline target_type make_target(T target) {
return target_type((int)target_type_id<T>::value, target);
}
inline target_type make_target(const std::shared_ptr<core::Download>& target) {
return make_target(target.get());
}
template <typename T>
inline target_type make_target_pair(T target1, T target2) {
return target_type((int)target_type_id<T, T>::value, target1, target2);
+9 -14
View File
@@ -26,12 +26,10 @@ constexpr int JSONRPC_METHOD_NOT_FOUND_ERROR = -32601;
constexpr int JSONRPC_INVALID_PARAMS_ERROR = -32602;
constexpr int JSONRPC_INTERNAL_ERROR = -32000;
constexpr uint32_t max_json_depth = 1024;
using json = nlohmann::json;
torrent::Object
json_to_object(const json& value, uint32_t depth = 0) {
json_to_object(const json& value) {
switch (value.type()) {
case json::value_t::number_unsigned:
case json::value_t::number_integer:
@@ -44,26 +42,20 @@ json_to_object(const json& value, uint32_t depth = 0) {
return torrent::Object(value.get<std::string>());
case json::value_t::array: {
if (++depth >= max_json_depth)
throw torrent::input_error("invalid parameters: max depth reached");
auto array_raw = torrent::Object::create_list();
auto& array = array_raw.as_list();
for (const auto& entry : value)
array.push_back(json_to_object(entry, depth));
array.push_back(json_to_object(entry));
return array_raw;
}
case json::value_t::object: {
if (++depth >= max_json_depth)
throw torrent::input_error("invalid parameters: max depth reached");
auto map_raw = torrent::Object::create_map();
auto& map = map_raw.as_map();
for (const auto& entry : value.items())
map[entry.key()] = json_to_object(entry.value(), depth);
map[entry.key()] = json_to_object(entry.value());
return map_raw;
}
@@ -146,7 +138,7 @@ jsonrpc_call_command(const std::string& method, const json& params) {
CommandMap::iterator itr = commands.find(method.c_str());
if (itr == commands.end() || !(itr->second.m_flags & CommandMap::flag_public_rpc)) {
if (itr == commands.end()) {
throw rpc_error(JSONRPC_METHOD_NOT_FOUND_ERROR, "method not found: " + method);
}
@@ -266,8 +258,11 @@ JsonRpc::process(const char* in_buffer, uint32_t length, slot_write callback) {
return callback(response_str.c_str(), response_str.size());
} catch (json::exception& e) {
// Exception strings may contain invalid UTF-8, hence the ::replace
} catch (json::parse_error& e) {
auto err_str = json_error(JSONRPC_PARSE_ERROR, e.what(), nullptr).dump(-1, ' ', false, json::error_handler_t::replace);
return callback(err_str.c_str(), err_str.size());
} catch (json::type_error& e) {
// Type errors may be caused by invalid UTF-8 strings in exception strings, hence the ::replace
auto err_str = json_error(JSONRPC_PARSE_ERROR, e.what(), nullptr).dump(-1, ' ', false, json::error_handler_t::replace);
return callback(err_str.c_str(), err_str.size());
}
+19 -37
View File
@@ -2,7 +2,6 @@
#include <cstring>
#include <cstdio>
#include <limits>
#include <locale>
#include <torrent/exceptions.h>
@@ -11,8 +10,6 @@
namespace rpc {
constexpr uint32_t max_parse_depth = 1024;
const char*
parse_skip_wspace(const char* first, const char* last) {
while (first != last && parse_is_space(*first))
@@ -102,12 +99,6 @@ parse_whole_value_nothrow(const char* src, int64_t* value, int base, int unit) {
return true;
}
static bool
value_fits_shifted(int64_t value, int shift) {
return value <= (std::numeric_limits<int64_t>::max() >> shift) &&
value >= (std::numeric_limits<int64_t>::min() >> shift);
}
const char*
parse_value_nothrow(const char* src, int64_t* value, int base, int unit) {
if (unit <= 0)
@@ -130,26 +121,20 @@ parse_value_nothrow(const char* src, int64_t* value, int base, int unit) {
case 'B': ++last; break;
case 'k':
case 'K':
if (!value_fits_shifted(*value, 10)) return src; // overflow guard
if (*value > (int64_t)0x1FFFFFFFFFFFFF) return src; // overflow guard
*value = *value << 10; ++last; break;
case 'm':
case 'M':
if (!value_fits_shifted(*value, 20)) return src; // overflow guard
if (*value > (int64_t)0x7FFFFFFFFFF) return src; // overflow guard
*value = *value << 20; ++last; break;
case 'g':
case 'G':
if (!value_fits_shifted(*value, 30)) return src; // overflow guard
if (*value > (int64_t)0x1FFFFFFFF) return src; // overflow guard
*value = *value << 30; ++last; break;
// case ' ':
// case '\0': *value = *value * unit; break;
// default: throw torrent::input_error("Could not parse value.");
default:
if (*value > std::numeric_limits<int64_t>::max() / unit ||
*value < std::numeric_limits<int64_t>::min() / unit)
return src; // overflow guard
*value = *value * unit;
break;
default: *value = *value * unit; break;
}
return last;
@@ -157,13 +142,10 @@ parse_value_nothrow(const char* src, int64_t* value, int base, int unit) {
// Somewhat ugly...
const char*
parse_object(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char), uint32_t depth) {
if (++depth >= max_parse_depth)
throw torrent::input_error("Max parse depth reached.");
parse_object(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char)) {
if (*first == '{') {
*dest = torrent::Object::create_list();
first = parse_list(first + 1, last, dest, &parse_is_delim_block, depth);
first = parse_list(first + 1, last, dest, &parse_is_delim_block);
first = parse_skip_wspace(first, last);
if (first == last || *first != '}')
@@ -172,18 +154,18 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
return ++first;
} else if (*first == '(') {
int32_t parentheses = 1;
int32_t depth = 1;
while (first + 1 != last && *(first + 1) == '(') {
first++;
parentheses++;
depth++;
}
if (parentheses > 3)
if (depth > 3)
throw torrent::input_error("Max 3 parentheses per object allowed.");
*dest = torrent::Object::create_dict_key();
dest->set_flags(torrent::Object::flag_function << (parentheses - 1));
dest->set_flags(torrent::Object::flag_function << (depth - 1));
first = parse_string(first + 1, last, &dest->as_dict_key(), &parse_is_delim_func);
first = parse_skip_wspace(first, last);
@@ -194,16 +176,16 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
if (*first == ',') {
// This will always create a list even for single argument functions...
dest->as_dict_obj() = torrent::Object::create_list();
first = parse_list(first + 1, last, &dest->as_dict_obj(), &parse_is_delim_func, depth);
first = parse_list(first + 1, last, &dest->as_dict_obj(), &parse_is_delim_func);
first = parse_skip_wspace(first, last);
}
while (parentheses != 0 && first != last && *first == ')') {
while (depth != 0 && first != last && *first == ')') {
first++;
parentheses--;
depth--;
}
if (parentheses != 0)
if (depth != 0)
throw torrent::input_error("Parentheses mismatch.");
return first;
@@ -216,7 +198,7 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
}
const char*
parse_list(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char), uint32_t depth) {
parse_list(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char)) {
if (!dest->is_list())
throw torrent::internal_error("parse_list(...) !dest->is_list().");
@@ -224,7 +206,7 @@ parse_list(const char* first, const char* last, torrent::Object* dest, bool (*de
torrent::Object tmp;
first = parse_skip_wspace(first, last);
first = parse_object(first, last, &tmp, delim, depth);
first = parse_object(first, last, &tmp, delim);
first = parse_skip_wspace(first, last);
dest->as_list().push_back(tmp);
@@ -239,9 +221,9 @@ parse_list(const char* first, const char* last, torrent::Object* dest, bool (*de
}
const char*
parse_whole_list(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char), uint32_t depth) {
parse_whole_list(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char)) {
first = parse_skip_wspace(first, last);
first = parse_object(first, last, dest, delim, depth);
first = parse_object(first, last, dest, delim);
first = parse_skip_wspace(first, last);
if (first != last && parse_is_seperator(*first)) {
@@ -249,7 +231,7 @@ parse_whole_list(const char* first, const char* last, torrent::Object* dest, boo
tmp.swap(*dest);
dest->as_list().push_back(tmp);
first = parse_list(++first, last, dest, delim, depth);
first = parse_list(++first, last, dest, delim);
}
return first;
+3 -3
View File
@@ -77,9 +77,9 @@ const char* parse_value_nothrow(const char* first, const char* last, int64_t* va
void parse_whole_value(const char* src, int64_t* value, int base = 0, int unit = 1);
bool parse_whole_value_nothrow(const char* src, int64_t* value, int base = 0, int unit = 1);
const char* parse_object (const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char) = &parse_is_delim_default, uint32_t depth = 0);
const char* parse_list (const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char) = &parse_is_delim_default, uint32_t depth = 0);
const char* parse_whole_list(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char) = &parse_is_delim_default, uint32_t depth = 0);
const char* parse_object (const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char) = &parse_is_delim_default);
const char* parse_list (const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char) = &parse_is_delim_default);
const char* parse_whole_list(const char* first, const char* last, torrent::Object* dest, bool (*delim)(const char) = &parse_is_delim_default);
std::string convert_to_string(const torrent::Object& src);
-8
View File
@@ -167,14 +167,6 @@ RpcManager::cleanup() {
m_jsonrpc.cleanup();
}
void
RpcManager::set_size_limit(uint64_t size) {
if (size > SCgiTask::max_content_size)
throw torrent::input_error("XMLRPC size limit cannot exceed the SCGI content size limit.");
m_xmlrpc.set_size_limit(size);
}
void
RpcManager::insert_command(const char* name, const char* parm, const char* doc) {
m_xmlrpc.insert_command(name, parm, doc);
+1 -1
View File
@@ -62,7 +62,7 @@ public:
void cleanup();
int64_t size_limit() { return m_xmlrpc.size_limit(); };
void set_size_limit(uint64_t size);
void set_size_limit(uint64_t size) { m_xmlrpc.set_size_limit(size); };
int dialect() { return m_xmlrpc.dialect(); }
void set_dialect(int dialect) { m_xmlrpc.set_dialect(dialect); }
+1 -2
View File
@@ -109,8 +109,7 @@ void
SCgi::activate() {
assert(torrent::this_thread::thread() == scgi_thread::thread());
torrent::this_thread::poll()->open(this);
torrent::this_thread::poll()->insert_read(this);
torrent::this_thread::poll()->open_and_insert_read(this);
}
// TODO: This should close the fd to avoid reuse.
+2 -18
View File
@@ -14,7 +14,6 @@
#include <torrent/runtime/socket_manager.h>
#include <torrent/system/callbacks.h>
#include <torrent/system/poll.h>
#include <torrent/system/scheduler.h>
#include <torrent/utils/log.h>
#include "control.h"
@@ -28,8 +27,6 @@ namespace rpc {
SCgiTask::SCgiTask()
: m_callback_id(torrent::system::make_callback_id()) {
m_task_timeout.slot() = [this]() { close(); };
reset_file_descriptor();
}
@@ -50,10 +47,7 @@ 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(this);
torrent::this_thread::poll()->insert_read(this);
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&m_task_timeout, timeout_request);
torrent::this_thread::poll()->open_and_insert_read(this);
auto lock = std::lock_guard<std::mutex>(m_result_mutex);
@@ -66,8 +60,6 @@ SCgiTask::cancel_open() {
if (!is_open())
return;
torrent::this_thread::scheduler()->erase(&m_task_timeout);
torrent::this_thread::poll()->remove_and_close(this);
torrent::fd_close(file_descriptor());
@@ -79,8 +71,6 @@ SCgiTask::close() {
if (!is_open())
return;
torrent::this_thread::scheduler()->erase(&m_task_timeout);
torrent::system::cancel_callback_and_wait(m_callback_id, scgi_thread::thread(), torrent::main_thread::thread());
torrent::runtime::socket_manager()->close_event_or_throw(this, [this]() {
@@ -103,12 +93,8 @@ SCgiTask::event_read() {
if (m_content_length == 0)
read_length--;
if (read_length <= 0) {
if (m_content_length == 0)
return close();
if (read_length <= 0)
throw torrent::internal_error("SCgiTask::event_read() no space in buffer for event_read.");
}
int bytes = ::recv(file_descriptor(), m_buffer.data() + m_position, read_length, 0);
@@ -167,8 +153,6 @@ SCgiTask::event_read() {
torrent::this_thread::poll()->remove_read(this);
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&m_task_timeout, timeout_request);
if (m_parent->log_fd() >= 0) {
[[maybe_unused]] int result;
+2 -7
View File
@@ -1,12 +1,10 @@
#ifndef RTORRENT_RPC_SCGI_TASK_H
#define RTORRENT_RPC_SCGI_TASK_H
#include <chrono>
#include <memory>
#include <mutex>
#include <vector>
#include <torrent/system/event.h>
#include <torrent/system/scheduler.h>
namespace rpc {
@@ -18,8 +16,6 @@ public:
static constexpr int max_header_size = 2000;
static constexpr int max_content_size = (2 << 23);
static constexpr auto timeout_request = std::chrono::seconds(60);
enum ContentType { XML, JSON };
SCgiTask();
@@ -58,9 +54,8 @@ private:
void plaintext_response(const char* buffer, uint32_t content_length);
void gzip_response(const char* buffer, uint32_t content_length);
SCgi* m_parent{};
torrent::system::callback_id m_callback_id;
torrent::system::SchedulerEntry m_task_timeout;
SCgi* m_parent{};
torrent::system::callback_id m_callback_id;
std::mutex m_result_mutex;
+3
View File
@@ -529,6 +529,9 @@ XmlRpc::size_limit() {
void
XmlRpc::set_size_limit(uint64_t size) {
if (size >= (64 << 20))
throw torrent::input_error("Invalid XMLRPC limit size.");
xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, size);
}
+5 -26
View File
@@ -49,23 +49,13 @@ element_access(const tinyxml2::XMLElement* elem, std::initializer_list<std::stri
return result;
}
const char*
element_text_value(const tinyxml2::XMLNode* node) {
auto text = node->ToText();
if (text == nullptr)
throw rpc_error(XMLRPC_TYPE_ERROR, "expected a text value");
return text->Value();
}
long long
element_to_int(const tinyxml2::XMLNode* elem) {
char* pos;
if (elem->FirstChild() == nullptr) {
throw rpc_error(XMLRPC_TYPE_ERROR, "unable to parse empty integer");
}
auto str = element_text_value(elem->FirstChild());
auto str = elem->FirstChild()->ToText()->Value();
auto result = std::strtoll(str, &pos, 10);
if (pos == str || *pos != '\0')
throw rpc_error(XMLRPC_TYPE_ERROR, "unable to parse integer value");
@@ -95,7 +85,7 @@ xml_value_to_object(const tinyxml2::XMLNode* elem) {
if (child_element == nullptr)
return torrent::Object("");
return torrent::Object(element_text_value(child_element));
return torrent::Object(child_element->ToText()->Value());
} else if (std::strncmp(root_type, "int", sizeof("int")) == 0 ||
std::strncmp(root_type, "i4", sizeof("i4")) == 0 ||
@@ -108,7 +98,7 @@ xml_value_to_object(const tinyxml2::XMLNode* elem) {
if (child_element == nullptr)
throw rpc_error(XMLRPC_TYPE_ERROR, "empty boolean element");
auto boolean_text = std::string(element_text_value(child_element));
auto boolean_text = std::string(child_element->ToText()->Value());
if (boolean_text == "1")
return torrent::Object((int64_t)1);
@@ -139,12 +129,7 @@ xml_value_to_object(const tinyxml2::XMLNode* elem) {
if (name_element == nullptr)
throw rpc_error(XMLRPC_PARSE_ERROR, "struct member missing name element");
auto name_text = name_element->GetText();
if (name_text == nullptr)
throw rpc_error(XMLRPC_PARSE_ERROR, "struct member has an empty name element");
map[name_text] = std::move(xml_value_to_object(child->FirstChildElement("value")));
map[name_element->GetText()] = std::move(xml_value_to_object(child->FirstChildElement("value")));
}
return map_raw;
@@ -155,7 +140,7 @@ xml_value_to_object(const tinyxml2::XMLNode* elem) {
if (child_element == nullptr)
return torrent::Object("");
return torrent::Object(utils::decode_base64(utils::remove_newlines(element_text_value(child_element))));
return torrent::Object(utils::decode_base64(utils::remove_newlines(child_element->ToText()->Value())));
} else {
throw rpc_error(XMLRPC_INTERNAL_ERROR, "received unsupported value type: " + std::string(root_type));
@@ -315,9 +300,6 @@ process_document(const tinyxml2::XMLDocument* doc, tinyxml2::XMLPrinter* printer
if (doc->FirstChildElement("methodCall")->FirstChildElement("methodName") == nullptr)
throw rpc_error(XMLRPC_PARSE_ERROR, "methodName element not found");
auto method_name = doc->FirstChildElement("methodCall")->FirstChildElement("methodName")->GetText();
if (method_name == nullptr)
throw rpc_error(XMLRPC_PARSE_ERROR, "methodName element is empty");
torrent::Object result;
// Add a shim here for system.multicall to allow better code reuse, and
@@ -328,9 +310,6 @@ process_document(const tinyxml2::XMLDocument* doc, tinyxml2::XMLPrinter* printer
auto parent_elements = element_access(doc->RootElement(), {"params", "param", "value", "array", "data"});
for (auto child = parent_elements->FirstChildElement("value"); child; child = child->NextSiblingElement("value")) {
auto sub_method_name = element_access(child, {"struct", "member", "value", "string"})->GetText();
if (sub_method_name == nullptr)
throw rpc_error(XMLRPC_PARSE_ERROR, "multicall methodName element is empty");
// If sub_params ends up a nullptr at the end of this if-chian,
// execute_command will turn it into an empty list
auto sub_params = element_access(child, {"struct", "member"});
+1 -1
View File
@@ -126,7 +126,7 @@ private:
inline bool SessionManager::is_used() const { return !m_path.empty(); }
inline std::string SessionManager::path() const { return m_path; }
inline bool SessionManager::use_fsyncdisk() const { return m_use_fsyncdisk; }
inline bool SessionManager::use_fsyncdisk() const { return true; }
inline bool SessionManager::use_lock() const { return m_use_lock; }
inline void SessionManager::flush_all_pending_builds() { process_pending_builds(true); }
+12 -8
View File
@@ -37,7 +37,7 @@ parse_main_options(int argc, char** argv) {
optionParser.insert_option('b', [](auto& arg) { rpc::call_command_set_string("network.bind_address.set", arg); });
optionParser.insert_option('d', [](auto& arg) { rpc::call_command_set_string("directory.default.set", arg); });
optionParser.insert_option('i', [](auto& arg) { rpc::call_command_set_string("network.local_address.set", arg); });
optionParser.insert_option('i', [](auto& arg) { rpc::call_command_set_string("ip", arg); });
optionParser.insert_option('p', [](auto& arg) { rpc::call_command_set_string("network.listen.port.range.set", arg); });
optionParser.insert_option('s', [](auto& arg) { rpc::call_command_set_string("session", arg); });
@@ -108,18 +108,22 @@ 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" in the config file.
// Call special commands in the format "# do:command=args" or "# do-<category>:command=args" in the config file.
void
parse_config_file_comments(const std::string& path) {
parse_config_file_comments(const std::string& category, const std::string& path) {
if (path.empty())
return;
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() <= 5 || line.compare(0, 5, "# do:") != 0)
if (line.size() <= prefix.size() || line.compare(0, prefix.size(), prefix) != 0)
continue;
auto equal_pos = line.find('=');
@@ -157,12 +161,12 @@ load_session_torrents(const std::string& path) {
if (!entry.is_file())
continue;
auto* f = new core::DownloadFactory(control->core(), true);
auto* f = new core::DownloadFactory(control->core());
f->set_session(true);
f->set_init_load(true);
f->slot_finished([f](){ delete f; });
f->load_trusted(entries.path() + entry.s_name);
f->load(entries.path() + entry.s_name);
f->commit();
}
}
@@ -170,12 +174,12 @@ load_session_torrents(const std::string& path) {
void
load_arg_torrents(char** first, char** last) {
for (; first != last; ++first) {
auto* f = new core::DownloadFactory(control->core(), true);
auto* f = new core::DownloadFactory(control->core());
f->set_start(true);
f->set_init_load(true);
f->slot_finished([f](){ delete f; });
f->load_trusted(*first);
f->load(*first);
f->commit();
}
}
+1 -1
View File
@@ -6,7 +6,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& path);
void parse_config_file_comments(const std::string& category, const std::string& path);
void load_session_torrents(const std::string& path);
void load_arg_torrents(char** first, char** last);
+2 -5
View File
@@ -1,4 +1,3 @@
#include <memory>
#include "config.h"
#include <cassert>
@@ -31,10 +30,8 @@
namespace ui {
Download::Download(const std::shared_ptr<core::Download>& download)
: m_download(download.get()) {
auto* d = download.get();
Download::Download(core::Download* d)
: m_download(d) {
m_windowDownloadStatus = std::make_unique<WDownloadStatus>(d);
m_windowDownloadStatus->set_bottom(true);
+1 -2
View File
@@ -2,7 +2,6 @@
#define RTORRENT_UI_DOWNLOAD_H
#include <list>
#include <memory>
#include <torrent/peer/peer.h>
#include "display/manager.h"
@@ -37,7 +36,7 @@ public:
DISPLAY_MAX_SIZE
} Display;
Download(const std::shared_ptr<core::Download>& d);
Download(core::Download* d);
~Download();
void activate(display::Frame* frame, bool focus = true);
+1 -1
View File
@@ -89,7 +89,7 @@ DownloadList::unfocus_download(core::Download* d) {
if (m_state == DISPLAY_DOWNLOAD && d == static_cast<Download*>(m_uiArray[DISPLAY_DOWNLOAD])->download())
activate_display(DISPLAY_DOWNLOAD_LIST);
if (current_view()->focus() < current_view()->end_visible() && current_view()->focus()->get() == d)
if (*current_view()->focus() == d && current_view()->focus() < current_view()->end_visible())
current_view()->next_focus();
}
+1 -1
View File
@@ -196,7 +196,7 @@ ElementDownloadList::receive_cycle_throttle() {
if (m_view->focus() == m_view->end_visible())
return;
core::Download* download = m_view->focus()->get();
core::Download* download = *m_view->focus();
if (download->is_active()) {
lt_log_print(torrent::LOG_TORRENT_WARN, "Cannot change throttle on active download.");
return;
+2 -4
View File
@@ -35,8 +35,6 @@ rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
rpc/test_command.h \
rpc/test_command_map.cc \
rpc/test_command_map.h \
rpc/test_command_scheduler.cc \
rpc/test_command_scheduler.h \
rpc/test_jsonrpc.cc \
rpc/test_jsonrpc.h \
rpc/test_xmlrpc.cc \
@@ -51,8 +49,8 @@ rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
src/test_command_dynamic.cc \
src/test_command_dynamic.h \
src/test_command_system.cc \
src/test_command_system.h \
src/test_command_local.cc \
src/test_command_local.h \
src/test_command_path.cc \
src/test_command_path.h \
src/test_command_string.cc \
-65
View File
@@ -1,65 +0,0 @@
#include "config.h"
#include "test/rpc/test_command_scheduler.h"
#include <chrono>
#include "rpc/command_scheduler.h"
#include "rpc/command_scheduler_item.h"
#include "torrent/object.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandScheduler);
namespace {
const torrent::Object test_command = torrent::Object(std::string("print=scheduled"));
std::chrono::microseconds
time_scheduled(rpc::CommandScheduler& scheduler, const std::string& key) {
auto itr = scheduler.find(key);
CPPUNIT_ASSERT(itr != scheduler.end());
return (*itr)->time_scheduled();
}
}
void
TestCommandScheduler::setUp() {
TestFixtureWithMainThread::setUp();
m_main_thread->test_set_cached_time(std::chrono::seconds(0));
}
void
TestCommandScheduler::tearDown() {
TestFixtureWithMainThread::tearDown();
}
void
TestCommandScheduler::test_parse_rearms_existing_key() {
rpc::CommandScheduler scheduler;
scheduler.parse("key", "3600", "3600", test_command);
auto first = time_scheduled(scheduler, "key");
m_main_thread->test_add_cached_time(std::chrono::seconds(600));
scheduler.parse("key", "3600", "3600", test_command);
CPPUNIT_ASSERT_EQUAL(size_t{1}, scheduler.size());
CPPUNIT_ASSERT(time_scheduled(scheduler, "key") == first + std::chrono::seconds(600));
}
void
TestCommandScheduler::test_find_locates_a_scheduled_key() {
rpc::CommandScheduler scheduler;
CPPUNIT_ASSERT(scheduler.find("key") == scheduler.end());
scheduler.parse("key", "3600", "3600", test_command);
CPPUNIT_ASSERT(scheduler.find("key") != scheduler.end());
CPPUNIT_ASSERT(scheduler.find("other") == scheduler.end());
}
-17
View File
@@ -1,17 +0,0 @@
#include "test/helpers/test_main_thread.h"
class TestCommandScheduler : public TestFixtureWithMainThread {
CPPUNIT_TEST_SUITE(TestCommandScheduler);
CPPUNIT_TEST(test_parse_rearms_existing_key);
CPPUNIT_TEST(test_find_locates_a_scheduled_key);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void test_parse_rearms_existing_key();
void test_find_locates_a_scheduled_key();
};
@@ -1,6 +1,6 @@
#include "config.h"
#include "test/src/test_command_system.h"
#include "test/src/test_command_local.h"
#include <torrent/torrent.h>
#include <torrent/runtime/socket_manager.h>
@@ -10,12 +10,12 @@
#include "globals.h"
#include "rpc/parse_commands.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandSystem);
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandLocal);
void initialize_command_system();
void initialize_command_local();
void
TestCommandSystem::setUp() {
TestCommandLocal::setUp() {
torrent::initialize_main_thread();
torrent::initialize();
@@ -23,16 +23,16 @@ TestCommandSystem::setUp() {
control = new Control;
if (!rpc::commands.has("system.sockets.size"))
initialize_command_system();
initialize_command_local();
}
void
TestCommandSystem::tearDown() {
TestCommandLocal::tearDown() {
torrent::cleanup();
}
void
TestCommandSystem::test_socket_category_commands() {
TestCommandLocal::test_socket_category_commands() {
for (uint32_t i = 0; i < torrent::runtime::SocketManager::category_count; ++i) {
auto category = static_cast<torrent::runtime::socket_manager_category_t>(i);
auto name = "system.sockets." + torrent::option_to_str_or_throw(torrent::OPTION_SOCKET_CATEGORY, i);
@@ -1,7 +1,7 @@
#include "test/helpers/test_fixture.h"
class TestCommandSystem : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommandSystem);
class TestCommandLocal : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommandLocal);
CPPUNIT_TEST(test_socket_category_commands);