Compare commits

..

8 Commits

Author SHA1 Message Date
Jari Sundell d8664e6b4c Changing listen/dht port changes the listening/dht ports. 2026-07-12 17:39:26 +02:00
Jari Sundell 7e907616a2 Moved ChunkManager out of public header directory. 2026-07-12 17:36:27 +02:00
Jari Sundell dcf13ab21a Moved all sync/diskspace related methods to MemoryManager. 2026-07-12 17:36:27 +02:00
Jari Sundell 03c4467a33 Added runtime::MemoryManager to split out unrelated features from ChunkManager. 2026-07-12 17:36:27 +02:00
Jari Sundell fc5ce92c46 Fixed command_base t_pod align static asserts. 2026-07-12 17:36:27 +02:00
Jari Sundell f1b22023a0 Reordered http queue slots to avoid race conditions. 2026-07-12 17:36:27 +02:00
Jari Sundell 928f3e58a8 Removed unused add/remove error-event code. 2026-07-12 17:36:27 +02:00
Jesse Miller 743363b405 Add handshake/stream encryption RPC commands
Replace protocol.encryption.set bitmask flags with
protocol.encryption.handshake.set and protocol.encryption.stream.set.
Add encryption_config to map commands to libtorrent EncryptionPolicy.
Startup default matches the old preset (allow_incoming, enable_retry,
prefer_plaintext → handshake=allow, stream=allow).

Update docs and examples. Peer list distinguishes RC4 (R/L),
handshake-only (H/h), and plain (r/l). Fix ui encrypted column
conditional. Add encryption config tests; remove OPTION_ENCRYPTION
parse tests. Drop the encryption command redirect.
2026-07-08 10:23:16 -06:00
35 changed files with 430 additions and 418 deletions
-65
View File
@@ -1,65 +0,0 @@
name: "Lint Commit Message Size"
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
check-commit-bounds:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate Line Count, Width, and Spacing
run: |
# Fetch commit hashes unique to this PR branch
COMMITS=$(git log --no-merges --pretty=format:"%H" origin/${{ github.base_ref }}..HEAD)
MAX_LINES=3
MAX_CHARS=90
FAILED=0
for commit in $COMMITS; do
SUBJECT=$(git log --format="%s" -n 1 $commit)
# Extract clean commit message, trimming trailing blank lines
RAW_MSG=$(git log --format="%B" -n 1 $commit)
CLEAN_MSG=$(echo "$RAW_MSG" | awk '{msg[NR]=$0} END {while(NR>0 && msg[NR]=="") NR--; for(i=1;i<=NR;i++) print msg[i]}')
# 1. Check total line count
LINE_COUNT=$(echo "$CLEAN_MSG" | wc -l)
if [ "$LINE_COUNT" -gt "$MAX_LINES" ]; then
echo "❌ Error: Commit message has too many lines ($LINE_COUNT/$MAX_LINES)."
echo " Commit: '$SUBJECT'"
FAILED=1
fi
# 2. Check for multiple consecutive blank lines
# This regex looks for 2 or more empty lines anywhere in the message
if echo "$CLEAN_MSG" | grep -pz '(\r?\n){3,}'; then
echo "❌ Error: Commit message contains multiple consecutive line breaks."
echo " Commit: '$SUBJECT'"
FAILED=1
fi
# 3. Check maximum width of any individual line
while IFS= read -r line; do
LINE_LENGTH=${#line}
if [ "$LINE_LENGTH" -gt "$MAX_CHARS" ]; then
echo "❌ Error: Line length exceeds limit ($LINE_LENGTH / $MAX_CHARS chars)."
echo " Offending line: '$line'"
FAILED=1
fi
done <<< "$CLEAN_MSG"
done
# Fail the job if any check failed
if [ "$FAILED" -ne 0 ]; then
exit 1
fi
echo "✅ All commit messages passed style rules!"
+3 -3
View File
@@ -1,6 +1,6 @@
m4_pattern_allow([PKG_CHECK_EXISTS])
AC_INIT([rtorrent],[0.16.19],[sundell.software@gmail.com])
AC_INIT([rtorrent],[0.16.17],[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], [24], [api version])
AC_DEFINE([API_VERSION], [23], [api version])
RAK_CHECK_CFLAGS
RAK_CHECK_CXXFLAGS
@@ -47,7 +47,7 @@ fi
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
PKG_CHECK_MODULES([ZLIB], [zlib])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.19])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.17])
AC_LANG_PUSH(C++)
TORRENT_WITH_XMLRPC_C
+9 -15
View File
@@ -214,21 +214,15 @@ Add a preferred filename encoding to the list. The encodings are
attempted in the order they are inserted, if none match the torrent
default is used.
.TP
\fBencryption = \fIoption\fB,\fI\&...\fB\fR
Set how rtorrent should deal with encrypted Bittorrent connections. By
default, encryption is disabled, equivalent to specifying the option
\fBnone\fR\&. Alternatively, any number of the following
options may be specified:
\fBallow_incoming\fR (allow incoming encrypted connections),
\fBtry_outgoing\fR (use encryption for outgoing connections),
\fBrequire\fR (disable unencrypted handshakes),
\fBrequire_RC4\fR (also disable plaintext transmission after the
initial encrypted handshake),
\fBenable_retry\fR (if the initial outgoing connection fails, retry
with encryption turned on if it was off or off if it was on),
\fBprefer_plaintext\fR (choose plaintext when peer offers a choice
between plaintext transmission and RC4 encryption, otherwise RC4 will be used).
\fBprotocol.encryption.handshake.set\fR (deny, allow, prefer, require)
and \fBprotocol.encryption.stream.set\fR (deny, allow, prefer,
require) control how rtorrent deals with encrypted Bittorrent
connections. Handshake \fBallow\fR accepts plain or PE inbound and
tries plain first outbound with one PE retry on failure.
\fBprefer\fR tries PE first with one plain retry. Stream \fBallow\fR
and \fBprefer\fR offer both handshake-only and RC4 on outgoing PE
connections. The default is handshake=allow, stream=allow. Use
\fBprotocol.encryption\fR to inspect the effective policy.
.TP
\fBpeer_exchange = \fIyes | no\fB\fR
Enable/disable peer exchange for torrents that aren't marked private. Disabled by default.
+11 -17
View File
@@ -484,25 +484,19 @@ default is used.
</varlistentry>
<varlistentry>
<term>encryption = <replaceable>option</replaceable>,<replaceable>...</replaceable></term>
<term>protocol.encryption.handshake.set = <replaceable>policy</replaceable></term>
<listitem><para>
Set how rtorrent should deal with encrypted Bittorrent connections. By
default, encryption is disabled, equivalent to specifying the option
<emphasis>none</emphasis>. Alternatively, any number of the following
options may be specified:
</para><para>
<emphasis>allow_incoming</emphasis> (allow incoming encrypted connections),
<emphasis>try_outgoing</emphasis> (use encryption for outgoing connections),
<emphasis>require</emphasis> (disable unencrypted handshakes),
<emphasis>require_RC4</emphasis> (also disable plaintext transmission after the
initial encrypted handshake),
<emphasis>enable_retry</emphasis> (if the initial outgoing connection fails, retry
with encryption turned on if it was off or off if it was on),
<emphasis>prefer_plaintext</emphasis> (choose plaintext when peer offers a choice
between plaintext transmission and RC4 encryption, otherwise RC4 will be used).
Control how rtorrent deals with encrypted Bittorrent connections.
<emphasis>protocol.encryption.handshake.set</emphasis> (deny, allow, prefer,
require) and <emphasis>protocol.encryption.stream.set</emphasis> (deny, allow,
prefer, require). Handshake <emphasis>allow</emphasis> accepts plain or PE
inbound and tries plain first outbound with one PE retry on failure.
<emphasis>prefer</emphasis> tries PE first with one plain retry. Stream
<emphasis>allow</emphasis> and <emphasis>prefer</emphasis> offer both
handshake-only and RC4 on outgoing PE connections. The default is
handshake=allow, stream=allow. Use <emphasis>protocol.encryption</emphasis> to
inspect the effective policy.
</para></listitem>
</varlistentry>
+32 -6
View File
@@ -95,14 +95,40 @@
#schedule2 = ip_tick,0,1800,ip=rakshasa
#schedule2 = bind_tick,0,1800,bind=rakshasa
# Encryption options, set to none (default) or any combination of the following:
# allow_incoming, try_outgoing, require, require_RC4, enable_retry, prefer_plaintext
# --- Protocol encryption (PE handshake / optional RC4 stream) ---
# Default at startup: handshake=allow stream=allow
#
# The example value allows incoming encrypted connections, starts unencrypted
# outgoing connections but retries with encryption if they fail, preferring
# plain-text to RC4 encryption after the encrypted handshake.
# Handshake (PE handshake; incoming accepts plain or PE for allow/prefer):
# deny - plain BT handshake only both ways; no retry
# allow - accept plain or PE inbound; plain first outbound with one PE retry
# prefer - accept plain or PE inbound; PE first outbound with one plain retry
# require - PE handshake required both ways; no retry
#
# protocol.encryption.set = allow_incoming,enable_retry,prefer_plaintext
# protocol.encryption.handshake.set = allow
#
# Stream (cipher negotiation after PE handshake succeeds):
# deny - offer handshake-only; require handshake-only (no RC4)
# allow - incoming: prefer handshake-only if offered, else RC4
# outgoing: offer both handshake-only and RC4
# prefer - incoming: pick RC4 if offered, else handshake-only
# outgoing: offer both handshake-only and RC4
# require - offer RC4 only; require RC4
#
# Outgoing retry summary with handshake=allow (plain first):
# stream=allow/prefer -> plain BT -> PE (both)
# stream=deny -> plain BT -> PE (handshake-only)
# stream=require -> plain BT -> PE (RC4-only)
#
# Outgoing retry summary with handshake=prefer (PE first):
# stream=allow/prefer -> PE (both) -> plain BT
# stream=deny -> PE (handshake-only) -> plain BT
# stream=require -> PE (RC4-only) -> plain BT
#
# Negotiated stream cipher is logged at connection_handshake level.
#
# protocol.encryption.stream.set = allow
#
# Use protocol.encryption to inspect the effective policy.
# Enable DHT support for trackerless torrents or when all trackers are down.
# May be set to "disable" (completely disable DHT), "off" (do not start DHT),
+2 -1
View File
@@ -42,7 +42,8 @@ throttle.min_peers.seed.set = 30
throttle.max_peers.seed.set = 80
trackers.numwant.set = 80
protocol.encryption.set = allow_incoming,try_outgoing,enable_retry
protocol.encryption.handshake.set = allow
protocol.encryption.stream.set = prefer
# Limits for file handle resources, this is optimized for
# an `ulimit` of 1024 (a common default). You MUST leave
+2 -1
View File
@@ -72,7 +72,8 @@ rc.throttle.min_peers.seed = 30
rc.throttle.max_peers.seed = 80
rc.trackers.numwant = 80
rc.protocol.encryption.set('allow_incoming', 'try_outgoing', 'enable_retry')
rc.protocol.encryption.handshake.set('allow')
rc.protocol.encryption.stream.set('prefer')
-- Limits for file handle resources, this is optimized for
-- an `ulimit` of 1024 (a common default). You MUST leave
+1 -1
View File
@@ -12,7 +12,7 @@ echo "Client version: " `xmlrpc2scgi.py -p scgi://127.0.0.1:${PORT_NUMBER} syste
echo
echo "Generated by 'rtorrent/doc/scripts/print_option_string.sh' on `date -u`."
for i in strings.choke_heuristics strings.choke_heuristics.upload strings.choke_heuristics.download strings.connection_type strings.encryption strings.ip_filter strings.ip_tos strings.log_group strings.tracker_event strings.tracker_mode; do
for i in strings.choke_heuristics strings.choke_heuristics.upload strings.choke_heuristics.download strings.connection_type strings.encryption.handshake strings.encryption.stream strings.ip_filter strings.ip_tos strings.log_group strings.tracker_event strings.tracker_mode; do
echo
echo $i
echo `echo $i | tr 'a-z_.' '-'`
+2
View File
@@ -188,6 +188,8 @@ libsub_root_a_SOURCES = \
command_local.cc \
command_logging.cc \
command_network.cc \
encryption_config.cc \
encryption_config.h \
command_peer.cc \
command_throttle.cc \
command_tracker.cc \
-1
View File
@@ -974,7 +974,6 @@ initialize_command_download() {
rpc::rpc.mark_safe("d.size_pex");
rpc::rpc.mark_safe("d.completed_bytes");
rpc::rpc.mark_safe("d.complete");
rpc::rpc.mark_safe("d.timestamp.started");
rpc::rpc.mark_safe("d.timestamp.finished");
rpc::rpc.mark_safe("d.bytes_done");
rpc::rpc.mark_safe("d.peers_accounted");
+13 -17
View File
@@ -444,20 +444,17 @@ initialize_command_dynamic() {
CMD2_ANY ("catch", std::bind(&cmd_catch, std::placeholders::_1, std::placeholders::_2));
CMD2_ANY_STRING ("enum.log_group", [](auto, const auto& str) { return torrent::option_find_string_str(torrent::OPTION_LOG_GROUP, str); });
CMD2_ANY ("strings.choke_heuristics", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CHOKE_HEURISTICS); });
CMD2_ANY ("strings.choke_heuristics.upload", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CHOKE_HEURISTICS_UPLOAD); });
CMD2_ANY ("strings.choke_heuristics.download", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD); });
CMD2_ANY ("strings.connection_type", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_CONNECTION_TYPE); });
CMD2_ANY ("strings.encryption", [](auto, auto) { return torrent::Object::create_list(); });
CMD2_ANY ("strings.encryption.handshake", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_ENCRYPTION_HANDSHAKE); });
CMD2_ANY ("strings.encryption.stream", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_ENCRYPTION_STREAM); });
CMD2_ANY ("strings.ip_filter", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_IP_FILTER); });
CMD2_ANY ("strings.ip_tos", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_IP_TOS); });
CMD2_ANY ("strings.log_group", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_LOG_GROUP); });
CMD2_ANY ("strings.tracker_event", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_TRACKER_EVENT); });
CMD2_ANY ("strings.tracker_mode", [](auto, auto) { return torrent::option_list_strings(torrent::OPTION_TRACKER_MODE); });
CMD2_ANY ("strings.choke_heuristics", std::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS));
CMD2_ANY ("strings.choke_heuristics.upload", std::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_UPLOAD));
CMD2_ANY ("strings.choke_heuristics.download", std::bind(&torrent::option_list_strings, torrent::OPTION_CHOKE_HEURISTICS_DOWNLOAD));
CMD2_ANY ("strings.connection_type", std::bind(&torrent::option_list_strings, torrent::OPTION_CONNECTION_TYPE));
CMD2_ANY ("strings.encryption.handshake", std::bind(&torrent::option_list_strings, torrent::OPTION_ENCRYPTION_MODE));
CMD2_ANY ("strings.encryption.stream", std::bind(&torrent::option_list_strings, torrent::OPTION_ENCRYPTION_MODE));
CMD2_ANY ("strings.ip_filter", std::bind(&torrent::option_list_strings, torrent::OPTION_IP_FILTER));
CMD2_ANY ("strings.ip_tos", std::bind(&torrent::option_list_strings, torrent::OPTION_IP_TOS));
CMD2_ANY ("strings.log_group", std::bind(&torrent::option_list_strings, torrent::OPTION_LOG_GROUP));
CMD2_ANY ("strings.tracker_event", std::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_EVENT));
CMD2_ANY ("strings.tracker_mode", std::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_MODE));
// clang-format on
#ifdef HAVE_XMLRPC_TINYXML2
@@ -472,13 +469,12 @@ initialize_command_dynamic() {
rpc::rpc.mark_safe("method.rlookup");
rpc::rpc.mark_safe("catch");
rpc::rpc.mark_safe("enum.log_group");
rpc::rpc.mark_safe("strings.choke_heuristics");
rpc::rpc.mark_safe("strings.choke_heuristics.upload");
rpc::rpc.mark_safe("strings.choke_heuristics.download");
rpc::rpc.mark_safe("strings.connection_type");
rpc::rpc.mark_safe("strings.encryption");
rpc::rpc.mark_safe("strings.encryption.handshake");
rpc::rpc.mark_safe("strings.encryption.stream");
rpc::rpc.mark_safe("strings.ip_filter");
rpc::rpc.mark_safe("strings.ip_tos");
rpc::rpc.mark_safe("strings.log_group");
+7 -7
View File
@@ -117,7 +117,7 @@ group_insert(const torrent::Object::list_type& args) {
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.enable", "simple",
"schedule=group." + name + ".ratio,5,60,on_ratio=" + name));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.disable", "simple",
"schedule.remove=group." + name + ".ratio"));
"schedule_remove=group." + name + ".ratio"));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.command", "simple",
"d.try_close= ;d.ignore_commands.set=1"));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".view", "string", view));
@@ -190,6 +190,10 @@ initialize_command_local() {
core::DownloadList* dList = control->core()->download_list();
torrent::FileManager* fileManager = torrent::file_manager();
if (rpc::call_command_value("method.use_deprecated") == 1) {
CMD_ANY_LIST ("file.append", std::bind(&cmd_file_append, std::placeholders::_2));
}
CMD_ANY ("system.hostname", std::bind(&system_hostname));
CMD_ANY ("system.pid", std::bind(&getpid));
@@ -250,12 +254,12 @@ initialize_command_local() {
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); });
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); });
if (i == 0)
continue;
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); });
}
@@ -354,10 +358,6 @@ initialize_command_local() {
rpc::rpc.mark_safe(category_name + ".size");
rpc::rpc.mark_safe(category_name + ".max_size");
if (i == 0)
continue;
rpc::rpc.mark_safe(category_name + ".min_alloc");
rpc::rpc.mark_safe(category_name + ".max_alloc");
}
-29
View File
@@ -1,7 +1,6 @@
#include "config.h"
#include <fcntl.h>
#include <iterator>
#include <stdio.h>
#include <unistd.h>
#include <torrent/data/chunk_utils.h>
@@ -16,7 +15,6 @@
#include "core/download.h"
#include "core/download_list.h"
#include "core/manager.h"
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
torrent::Object
@@ -40,32 +38,6 @@ apply_log_add_output(const torrent::Object::list_type& args) {
return torrent::Object();
}
torrent::Object
apply_log_print(const torrent::Object::list_type& args) {
if (args.size() < 2)
throw torrent::input_error("Invalid number of arguments.");
torrent::Object::value_type group;
if (args.front().is_value())
group = args.front().as_value();
else if (args.front().is_string())
group = torrent::option_find_string_str(torrent::OPTION_LOG_GROUP, args.front().as_string());
else
throw torrent::input_error("Invalid log group.");
if (group < 0 || group >= torrent::LOG_GROUP_MAX_SIZE)
throw torrent::input_error("Invalid log group.");
std::string message;
for (auto itr = std::next(args.begin()); itr != args.end(); ++itr)
rpc::print_object_std(&message, &*itr, 0);
torrent::log_groups[group].internal_print(message);
return torrent::Object();
}
// TODO: Deprecated.
torrent::Object
apply_log(const torrent::Object::string_type& arg, int logType) {
@@ -140,7 +112,6 @@ initialize_command_logging() {
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
CMD2_ANY_LIST ("log.print", std::bind(&apply_log_print, std::placeholders::_2));
CMD2_ANY_STRING ("log.execute", std::bind(&apply_log, std::placeholders::_2, 0));
CMD2_ANY_STRING ("log.vmmap.dump", std::bind(&log_vmmap_dump, std::placeholders::_2));
+5 -122
View File
@@ -19,6 +19,7 @@
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "encryption_config.h"
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
@@ -34,118 +35,6 @@
#include <systemd/sd-daemon.h>
#endif
torrent::Object
listen_port_range() {
auto port_range = torrent::runtime::client_config()->listen_port_range();
return std::to_string(port_range.first) + "-" + std::to_string(port_range.second);
}
void
set_listen_port_range(const std::string& arg) {
unsigned int port_first{}, port_last{};
if (std::sscanf(arg.c_str(), "%i-%i", &port_first, &port_last) != 2)
throw torrent::input_error("Invalid port_range argument.");
if (port_first >= (1 << 16) || port_last >= (1 << 16))
throw torrent::input_error("Port range out-of-bounds.");
torrent::runtime::client_config()->set_listen_port_range(port_first, port_last);
}
torrent::Object
get_encryption() {
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_HANDSHAKE, encryption_modes.first) + "," +
torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_STREAM, encryption_modes.second);
}
torrent::Object
get_handshake_encryption() {
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_MODE, encryption_modes.first);
}
torrent::Object
get_stream_encryption() {
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_MODE, encryption_modes.second);
}
torrent::Object
apply_obsolete_encryption(const torrent::Object::list_type& args) {
torrent::encryption_mode handshake_mode{torrent::ENCRYPTION_MODE_ALLOW};
torrent::encryption_mode stream_mode{torrent::ENCRYPTION_MODE_ALLOW};
for (auto& itr : args) {
auto arg = itr.as_string();
if (arg == "none") {
handshake_mode = torrent::ENCRYPTION_MODE_DENY;
stream_mode = torrent::ENCRYPTION_MODE_DENY;
break;
} else if (arg == "allow_incoming") {
} else if (arg == "try_outgoing") {
} else if (arg == "require") {
handshake_mode = torrent::ENCRYPTION_MODE_REQUIRE;
} else if (arg == "require_RC4" || arg == "require_rc4") {
handshake_mode = torrent::ENCRYPTION_MODE_REQUIRE;
stream_mode = torrent::ENCRYPTION_MODE_REQUIRE;
break;
} else if (arg == "enable_retry") {
} else if (arg == "prefer_plaintext") {
} else {
throw torrent::input_error("Invalid encryption option: '" + arg + "'");
}
}
lt_log_print(torrent::LOG_WARN, "Obsolete encryption options used, use 'handshake_{deny,allow,prefer,require}, stream_{deny,allow,prefer,require}' instead.");
torrent::runtime::network_config()->set_encryption_modes(handshake_mode, stream_mode);
return {};
}
torrent::Object
apply_encryption(const torrent::Object::list_type& args) {
if (args.empty())
throw torrent::input_error("No encryption options specified.");
torrent::encryption_mode encryption_mode, handshake_mode, stream_mode;
if (args.size() == 1) {
try {
encryption_mode = static_cast<torrent::encryption_mode>(torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_MODE, args.front().as_string()));
} catch (torrent::input_error& e) {
return apply_obsolete_encryption(args);
}
torrent::runtime::network_config()->set_encryption_modes(encryption_mode, encryption_mode);
return {};
}
if (args.size() != 2)
return apply_obsolete_encryption(args);
try {
handshake_mode = static_cast<torrent::encryption_mode>(torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_HANDSHAKE, args.front().as_string()));
stream_mode = static_cast<torrent::encryption_mode>(torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_STREAM, args.back().as_string()));
} catch (torrent::input_error& e) {
return apply_obsolete_encryption(args);
}
torrent::runtime::network_config()->set_encryption_modes(handshake_mode, stream_mode);
return {};
}
torrent::Object
apply_tos(const torrent::Object::string_type& arg) {
rpc::command_base::value_type value;
@@ -325,13 +214,9 @@ initialize_command_network() {
CMD_ANY ("network.listen.backlog", [](auto, auto) { return torrent::runtime::network_config()->listen_backlog(); });
CMD_ANY_VALUE_V ("network.listen.backlog.set", [](auto, auto& value) { return torrent::runtime::network_config()->set_listen_backlog(value); });
CMD_ANY ("protocol.pex", [](auto, auto) { return torrent::runtime::client_config()->is_pex_enabled(); });
CMD_ANY_VALUE_V ("protocol.pex.set", [](auto, auto& value) { return torrent::runtime::client_config()->set_pex_enabled(value); });
CMD_VAR_BOOL ("protocol.pex", true);
CMD_ANY_LIST ("protocol.encryption", [](auto, auto) { return get_encryption(); });
CMD_ANY_LIST ("protocol.encryption.set", [](auto, auto& args) { return apply_encryption(args); });
CMD_ANY_LIST ("protocol.encryption.handshake", [](auto, auto) { return get_handshake_encryption(); });
CMD_ANY_LIST ("protocol.encryption.stream", [](auto, auto) { return get_stream_encryption(); });
encryption_config::initialize_commands();
CMD_VAR_STRING ("protocol.connection.leech", "leech");
CMD_VAR_STRING ("protocol.connection.seed", "seed");
@@ -402,10 +287,8 @@ initialize_command_network() {
CMD_ANY ("network.xmlrpc.size_limit", [](auto, auto) { return rpc::rpc.size_limit(); });
CMD_ANY_VALUE_V ("network.xmlrpc.size_limit.set", [](auto, auto& arg) { return rpc::rpc.set_size_limit(arg); });
CMD_ANY ("network.rpc.use_xmlrpc", [](auto, auto) { return rpc::rpc.use_xmlrpc(); });
CMD_ANY_VALUE_V ("network.rpc.use_xmlrpc.set", [](auto, auto& arg) { return rpc::rpc.set_use_xmlrpc(arg); });
CMD_ANY ("network.rpc.use_jsonrpc", [](auto, auto) { return rpc::rpc.use_jsonrpc(); });
CMD_ANY_VALUE_V ("network.rpc.use_jsonrpc.set", [](auto, auto& arg) { return rpc::rpc.set_use_jsonrpc(arg); });
CMD_VAR_BOOL ("network.rpc.use_xmlrpc", true);
CMD_VAR_BOOL ("network.rpc.use_jsonrpc", true);
CMD_ANY ("network.block.ipv4", [nw_config](auto, auto) { return nw_config->is_block_ipv4(); });
CMD_ANY_VALUE_V ("network.block.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4(value); });
+1 -2
View File
@@ -15,7 +15,6 @@
#include <torrent/rate.h>
#include <torrent/data/file_utils.h>
#include <torrent/net/http_stack.h>
#include <torrent/runtime/client_config.h>
#include <torrent/utils/string_manip.h>
#include "control.h"
@@ -272,7 +271,7 @@ DownloadFactory::receive_success() {
if (!m_session && m_variables["tied_to_file"].as_value())
rpc::call_command("d.tied_to_file.set", m_uri.empty() ? m_variables["tied_file"] : m_uri, rpc::make_target(download));
rpc::call_command("d.peer_exchange.set", torrent::runtime::client_config()->is_pex_enabled(), rpc::make_target(download));
rpc::call_command("d.peer_exchange.set", rpc::call_command_value("protocol.pex"), rpc::make_target(download));
torrent::resume_load_addresses(*download->download(), resumeObject);
torrent::resume_load_file_priorities(*download->download(), resumeObject);
+17 -1
View File
@@ -16,6 +16,21 @@
namespace display {
namespace {
char
connection_type_char(const torrent::Peer* p) {
if (p->is_encrypted())
return p->is_incoming() ? 'R' : 'L';
if (p->is_obfuscated())
return p->is_incoming() ? 'H' : 'h';
return p->is_incoming() ? 'r' : 'l';
}
} // namespace
WindowPeerList::WindowPeerList(core::Download* d, PList* l, PList::iterator* f) :
Window(new Canvas, 0, 0, 0, extent_full, extent_full),
m_download(d),
@@ -35,6 +50,7 @@ WindowPeerList::redraw() {
m_canvas->print(x, y, "UP"); x += 7;
m_canvas->print(x, y, "DOWN"); x += 7;
m_canvas->print(x, y, "PEER"); x += 7;
// CT: R/H/r or L/h/l (RC4 / handshake-only / plain) + peer type (u/p/ )
m_canvas->print(x, y, "CT/RE/LO"); x += 10;
m_canvas->print(x, y, "QS"); x += 6;
m_canvas->print(x, y, "DONE"); x += 6;
@@ -95,7 +111,7 @@ WindowPeerList::redraw() {
peerType = ' ';
m_canvas->print(x, y, "%c%c/%c%c/%c%c",
p->is_encrypted() ? (p->is_incoming() ? 'R' : 'L') : (p->is_incoming() ? 'r' : 'l'),
connection_type_char(p),
peerType,
p->is_down_choked() ? std::tolower(remoteChoked) : remoteChoked,
+88
View File
@@ -0,0 +1,88 @@
#include "config.h"
#include "encryption_config.h"
#include <torrent/runtime/network_config.h>
#include <torrent/runtime/runtime.h>
#include <torrent/utils/option_strings.h>
#include "command_helpers.h"
#include "globals.h"
namespace encryption_config {
namespace {
Policy
current_policy() {
return torrent::runtime::network_config()->encryption_policy();
}
} // namespace
Policy
default_policy() {
Policy policy;
policy.handshake = Policy::Mode::allow;
policy.stream = Policy::Mode::allow;
return policy;
}
std::string
mode_to_string(Policy::Mode value) {
return torrent::option_to_str_or_throw(torrent::OPTION_ENCRYPTION_MODE,
static_cast<unsigned int>(value));
}
void
apply_mode_value(Policy& policy, Policy::Mode Policy::*field, const std::string& value) {
policy.*field = static_cast<Policy::Mode>(
torrent::option_find_string_str(torrent::OPTION_ENCRYPTION_MODE, value));
}
std::string
summary_string(const Policy& policy) {
return "handshake=" + mode_to_string(policy.handshake)
+ " stream=" + mode_to_string(policy.stream);
}
void
apply_policy(const Policy& policy) {
torrent::runtime::network_config()->set_encryption_policy(policy);
}
torrent::Object
apply_handshake_set(const std::string& value) {
Policy policy = current_policy();
apply_mode_value(policy, &Policy::handshake, value);
apply_policy(policy);
return torrent::Object();
}
torrent::Object
apply_stream_set(const std::string& value) {
Policy policy = current_policy();
apply_mode_value(policy, &Policy::stream, value);
apply_policy(policy);
return torrent::Object();
}
void
initialize_commands() {
apply_policy(default_policy());
CMD2_ANY("protocol.encryption", [](auto, auto) { return summary_string(current_policy()); });
CMD2_ANY("protocol.encryption.handshake", [](auto, auto) { return mode_to_string(current_policy().handshake); });
CMD2_ANY_STRING_V("protocol.encryption.handshake.set", [](auto, auto& str) { return apply_handshake_set(str); });
CMD2_ANY("protocol.encryption.stream", [](auto, auto) { return mode_to_string(current_policy().stream); });
CMD2_ANY_STRING_V("protocol.encryption.stream.set", [](auto, auto& str) { return apply_stream_set(str); });
rpc::rpc.mark_safe("protocol.encryption");
rpc::rpc.mark_safe("protocol.encryption.handshake");
rpc::rpc.mark_safe("protocol.encryption.handshake.set");
rpc::rpc.mark_safe("protocol.encryption.stream");
rpc::rpc.mark_safe("protocol.encryption.stream.set");
}
} // namespace encryption_config
+29
View File
@@ -0,0 +1,29 @@
#ifndef RTORRENT_ENCRYPTION_CONFIG_H
#define RTORRENT_ENCRYPTION_CONFIG_H
#include <cstdint>
#include <string>
#include <torrent/runtime/encryption_policy.h>
#include <torrent/object.h>
namespace encryption_config {
using Policy = torrent::EncryptionPolicy;
Policy default_policy();
std::string mode_to_string(Policy::Mode value);
void apply_mode_value(Policy& policy, Policy::Mode Policy::*field, const std::string& value);
std::string summary_string(const Policy& policy);
void apply_policy(const Policy& policy);
torrent::Object apply_handshake_set(const std::string& value);
torrent::Object apply_stream_set(const std::string& value);
void initialize_commands();
} // namespace encryption_config
#endif
+3 -2
View File
@@ -2,11 +2,12 @@
#define RTORRENT_INPUT_INPUT_EVENT_H
#include <functional>
#include <torrent/system/event.h>
#include <torrent/event.h>
namespace input {
class InputEvent : public torrent::system::Event {
class InputEvent : public torrent::Event {
public:
typedef std::function<void (int)> slot_int;
+7 -5
View File
@@ -301,6 +301,9 @@ main(int argc, char** argv) {
"schedule = low_diskspace,5,60,((close_low_diskspace,500M))\n"
"schedule = prune_file_status,3600,86400,((system.file_status_cache.prune))\n"
"protocol.encryption.handshake.set=allow\n"
"protocol.encryption.stream.set=allow\n"
"ui.color.focus.set=reverse\n"
);
@@ -319,8 +322,6 @@ main(int argc, char** argv) {
CMD_REDIRECT("ratio.max.set", "group.seeding.ratio.max.set");
CMD_REDIRECT("ratio.upload.set", "group.seeding.ratio.upload.set");
CMD_REDIRECT("encryption", "protocol.encryption.set");
CMD_REDIRECT("check_hash", "pieces.hash.on_completion.set");
CMD_REDIRECT("connection_leech", "protocol.connection.leech.set");
@@ -344,9 +345,8 @@ main(int argc, char** argv) {
CMD_REDIRECT("directory", "directory.default.set");
CMD_REDIRECT("session", "session.path.set");
CMD_REDIRECT_NO_EXPORT("port_range", "network.listen.port.range.set");
CMD_REDIRECT_NO_EXPORT("scgi_port", "network.scgi.open_port");
CMD_REDIRECT_NO_EXPORT("scgi_local", "network.scgi.open_local");
CMD_REDIRECT("scgi_port", "network.scgi.open_port");
CMD_REDIRECT("scgi_local", "network.scgi.open_local");
CMD_REDIRECT("to_gm_time", "convert.gm_time");
CMD_REDIRECT("to_gm_date", "convert.gm_date");
@@ -390,6 +390,8 @@ main(int argc, char** argv) {
CMD_REDIRECT("schedule2", "schedule");
CMD_REDIRECT("schedule_remove2", "schedule.remove");
// TODO: Remove file.append when cleaning these up.
CMD_REDIRECT("bind", "network.bind_address.set");
CMD_REDIRECT("ip", "network.local_address.set");
CMD_REDIRECT("port_range", "network.port_range.set");
+37 -6
View File
@@ -113,20 +113,25 @@ bool
RpcManager::process(RPCType type, const char* in_buffer, uint32_t length, slot_response_callback callback) {
switch (type) {
case RPCType::XML:
if (!m_xmlrpc.is_valid() || !m_use_xmlrpc) {
// TODO: 'network.rpc.use_xmlrpc' should be a bool in RpcManager, not a command variable.
if (m_xmlrpc.is_valid() && rpc::call_command_value("network.rpc.use_xmlrpc")) {
return m_xmlrpc.process(in_buffer, length, callback);
} else {
const std::string response = "<?xml version=\"1.0\"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><i8>-501</i8></value></member><member><name>faultString</name><value><string>XML-RPC not supported</string></value></member></struct></value></fault></methodResponse>";
return callback(response.c_str(), response.size());
}
return m_xmlrpc.process(in_buffer, length, callback);
break;
case RPCType::JSON:
if (!m_use_jsonrpc) {
if (rpc::call_command_value("network.rpc.use_jsonrpc")) {
return m_jsonrpc.process(in_buffer, length, callback);
} else {
const std::string response = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32601,\"message\":\"JSON-RPC not supported\"},\"id\":null}";
return callback(response.c_str(), response.size());
}
return m_jsonrpc.process(in_buffer, length, callback);
break;
default:
throw torrent::input_error("invalid parameters: unknown RPC type");
@@ -167,6 +172,32 @@ RpcManager::cleanup() {
m_jsonrpc.cleanup();
}
bool
RpcManager::is_type_enabled(RPCType type) const {
switch (type) {
case RPCType::XML:
return m_is_xmlrpc_enabled;
case RPCType::JSON:
return m_is_jsonrpc_enabled;
default:
throw torrent::input_error("invalid parameters: unknown RPC type");
}
}
void
RpcManager::set_type_enabled(RPCType type, bool enabled) {
switch (type) {
case RPCType::XML:
m_is_xmlrpc_enabled = enabled;
break;
case RPCType::JSON:
m_is_jsonrpc_enabled = enabled;
break;
default:
throw torrent::input_error("invalid parameters: unknown RPC type");
}
}
void
RpcManager::insert_command(const char* name, const char* parm, const char* doc) {
m_xmlrpc.insert_command(name, parm, doc);
+4 -13
View File
@@ -67,11 +67,8 @@ public:
int dialect() { return m_xmlrpc.dialect(); }
void set_dialect(int dialect) { m_xmlrpc.set_dialect(dialect); }
bool use_xmlrpc() const;
void set_use_xmlrpc(bool v);
bool use_jsonrpc() const;
void set_use_jsonrpc(bool v);
bool is_type_enabled(RPCType type) const;
void set_type_enabled(RPCType type, bool enabled);
bool process(RPCType type, const char* in_buffer, uint32_t length, slot_response_callback callback);
bool process_untrusted(RPCType type, const char* in_buffer, uint32_t length, slot_response_callback callback);
@@ -105,9 +102,8 @@ private:
JsonRpc m_jsonrpc;
bool m_handlers_initialized{};
bool m_use_jsonrpc{true};
bool m_use_xmlrpc{true};
bool m_is_jsonrpc_enabled{true};
bool m_is_xmlrpc_enabled{true};
std::atomic<bool> m_scgi_allow_compression{true};
std::atomic<unsigned int> m_scgi_min_compress_size{1000};
@@ -120,11 +116,6 @@ private:
extern RpcManager rpc;
inline bool RpcManager::use_xmlrpc() const { return m_use_xmlrpc; }
inline void RpcManager::set_use_xmlrpc(bool v) { m_use_xmlrpc = v; }
inline bool RpcManager::use_jsonrpc() const { return m_use_jsonrpc; }
inline void RpcManager::set_use_jsonrpc(bool v) { m_use_jsonrpc = v; }
} // namespace rpc
#endif
+2 -2
View File
@@ -3,13 +3,13 @@
#include <array>
#include <memory>
#include <torrent/system/event.h>
#include <torrent/event.h>
#include "rpc/scgi_task.h"
namespace rpc {
class SCgi : public torrent::system::Event {
class SCgi : public torrent::Event {
public:
static const int max_tasks = 100;
+2 -2
View File
@@ -4,13 +4,13 @@
#include <memory>
#include <mutex>
#include <vector>
#include <torrent/system/event.h>
#include <torrent/event.h>
namespace rpc {
class SCgi;
class SCgiTask : public torrent::system::Event {
class SCgiTask : public torrent::Event {
public:
static constexpr int default_buffer_size = 8191;
static constexpr int max_header_size = 2000;
+1 -1
View File
@@ -38,7 +38,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("ip", arg); });
optionParser.insert_option('p', [](auto& arg) { rpc::call_command_set_string("network.listen.port.range.set", arg); });
optionParser.insert_option('p', [](auto& arg) { rpc::call_command_set_string("network.port_range.set", arg); });
optionParser.insert_option('s', [](auto& arg) { rpc::call_command_set_string("session", arg); });
optionParser.insert_option('O', [](auto& arg) { rpc::parse_command_single_std(arg); });
+1 -1
View File
@@ -111,7 +111,7 @@ ElementPeerList::create_info() {
element->push_column("Client:", te_command("p.client_version="));
element->push_column("Options:", te_command("p.options_str="));
element->push_column("Connected:", te_command("if=$p.is_incoming=,incoming,outgoing"));
element->push_column("Encrypted:", te_command("if=$p.is_encrypted=,yes,$p.is_obfuscated=,handshake,no"));
element->push_column("Encrypted:", te_command("if=$p.is_encrypted=,yes,$if=$p.is_obfuscated=\\,handshake\\,no"));
element->push_back("");
element->push_column("Snubbed:", te_command("if=$p.is_snubbed=,yes,no"));
+2 -2
View File
@@ -49,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_local.cc \
src/test_command_local.h \
src/test_encryption_config.cc \
src/test_encryption_config.h \
src/test_watch_ready_queue.cc \
src/test_watch_ready_queue.h
+8 -22
View File
@@ -2,10 +2,9 @@
#define LIBTORRENT_HELPERS_MOCK_COMPARE_H
#include <algorithm>
#include <map>
#include <type_traits>
#include <torrent/event.h>
#include <torrent/net/socket_address.h>
#include <torrent/system/event.h>
// Compare arguments to mock functions with what is expected. The lhs
// are the expected arguments, rhs are the ones called with.
@@ -14,13 +13,13 @@ template <typename Arg>
inline bool mock_compare_arg(Arg lhs, Arg rhs) { return lhs == rhs; }
template <int I, typename A, typename... Args>
std::enable_if_t<I == 1, int>
typename std::enable_if<I == 1, int>::type
mock_compare_tuple(const std::tuple<A, Args...>& lhs, const std::tuple<Args...>& rhs) {
return mock_compare_arg(std::get<I>(lhs), std::get<I - 1>(rhs)) ? 0 : 1;
}
template <int I, typename A, typename... Args>
std::enable_if_t<1 < I, int>
typename std::enable_if<1 < I, int>::type
mock_compare_tuple(const std::tuple<A, Args...>& lhs, const std::tuple<Args...>& rhs) {
auto res = mock_compare_tuple<I - 1>(lhs, rhs);
@@ -71,37 +70,24 @@ void mock_compare_add(T* v) {
// Specialize:
//
constexpr int mock_compare_gt_two_int = -0xFD30;
template <>
inline bool mock_compare_arg<int>(int lhs, int rhs) {
if (lhs == mock_compare_gt_two_int)
return rhs > 2;
if (rhs == mock_compare_gt_two_int)
return lhs > 2;
return lhs == rhs;
}
template <>
inline bool mock_compare_arg<sockaddr*>(sockaddr* lhs, sockaddr* rhs) {
return lhs != nullptr && rhs != nullptr && torrent::sa_equal(lhs, rhs);
}
template <>
inline bool mock_compare_arg<const sockaddr*>(const sockaddr* lhs, const sockaddr* rhs) {
return lhs != nullptr && rhs != nullptr && torrent::sa_equal(lhs, rhs);
}
template <>
inline bool mock_compare_arg<torrent::system::Event*>(torrent::system::Event* lhs, torrent::system::Event* rhs) {
if (mock_compare_map<torrent::system::Event>::is_key(lhs)) {
if (!mock_compare_map<torrent::system::Event>::has_value(rhs)) {
mock_compare_map<torrent::system::Event>::values[lhs] = rhs;
inline bool mock_compare_arg<torrent::Event*>(torrent::Event* lhs, torrent::Event* rhs) {
if (mock_compare_map<torrent::Event>::is_key(lhs)) {
if (!mock_compare_map<torrent::Event>::has_value(rhs)) {
mock_compare_map<torrent::Event>::values[lhs] = rhs;
return true;
}
return mock_compare_map<torrent::system::Event>::has_key(lhs) && mock_compare_map<torrent::system::Event>::get(lhs) == rhs;
return mock_compare_map<torrent::Event>::has_key(lhs) && mock_compare_map<torrent::Event>::get(lhs) == rhs;
}
return lhs == rhs;
+66 -5
View File
@@ -6,9 +6,9 @@
#include <iostream>
#include <unistd.h>
#include "torrent/event.h"
#include "torrent/net/socket_address.h"
#include "torrent/net/fd.h"
#include "torrent/system/event.h"
#include "torrent/utils/log.h"
#include "torrent/utils/random.h"
@@ -32,7 +32,7 @@ mock_clear(bool ignore_assert) {
MOCK_CLEANUP_MAP(torrent::random_uniform_uint16);
MOCK_CLEANUP_MAP(torrent::random_uniform_uint32);
mock_compare_map<torrent::system::Event>::values.clear();
mock_compare_map<torrent::Event>::values.clear();
}
} // namespace
@@ -55,9 +55,7 @@ mock_redirect_defaults([[maybe_unused]] mock_redirect_flags flags) {
mock_redirect(torrent::fd__close, std::function<int(int fildes)>([](int fildes) { return ::close(fildes); }));
mock_redirect(torrent::fd__fcntl_int, std::function<int(int fildes, int cmd, int arg)>([](int fildes, int cmd, int arg) { return ::fcntl(fildes, cmd, arg); }));
mock_redirect(torrent::fd__setsockopt_int, std::function<int(int socket, int level, int option_name, int option_value)>([](int socket, int level, int option_name, int option_value) {
return ::setsockopt(socket, level, option_name, &option_value, sizeof(int));
}));
mock_redirect(torrent::fd__setsockopt_int, std::function<int(int socket, int level, int option_name, int option_value)>([](int socket, int level, int option_name, int option_value) { return ::setsockopt(socket, level, option_name, &option_value, sizeof(int)); }));
mock_redirect(torrent::fd__socket, std::function<int(int domain, int type, int protocol)>([](int domain, int type, int protocol) { return ::socket(domain, type, protocol); }));
}
@@ -114,6 +112,69 @@ int fd__socket(int domain, int type, int protocol) {
return mock_call<int>(__func__, &torrent::fd__socket, domain, type, protocol);
}
//
// Mock functions for 'torrent/common.h':
//
namespace this_thread {
void event_open(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_open, event);
}
void event_open_and_count(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_open_and_count, event);
}
void event_close_and_count(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_close_and_count, event);
}
void event_closed_and_count(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_closed_and_count, event);
}
void event_insert_read(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_insert_read, event);
}
void event_insert_write(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_insert_write, event);
}
void event_insert_error(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_insert_error, event);
}
void event_remove_read(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_remove_read, event);
}
void event_remove_write(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_remove_write, event);
}
void event_remove_error(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_remove_error, event);
}
void event_remove_and_close(Event* event) {
MOCK_LOG("fd:%i type_name:%s", event->file_descriptor(), event->type_name());
return mock_call<void>(__func__, &torrent::this_thread::event_remove_and_close, event);
}
}
//
// Mock functions for 'torrent/utils/random.h':
//
+16
View File
@@ -169,3 +169,19 @@ TestParseOptions::test_flag_libtorrent() {
FLAG_LT_LOG_ASSERT_ERROR("resume_data|rpc_dump");
}
#define FLAGS_LT_IP_TOS_ASSERT(flags, result) \
CPPUNIT_ASSERT(rpc::parse_option_flags(flags, std::bind(&torrent::option_find_string_str, torrent::OPTION_IP_TOS, std::placeholders::_1)) == (result))
#define FLAGS_LT_IP_TOS_ASSERT_ERROR(flags) \
ASSERT_CATCH_INPUT_ERROR(rpc::parse_option_flags(flags, std::bind(&torrent::option_find_string_str, torrent::OPTION_IP_TOS, std::placeholders::_1)))
void
TestParseOptions::test_flags_libtorrent() {
FLAGS_LT_IP_TOS_ASSERT("throughput", torrent::option_find_string(torrent::OPTION_IP_TOS, "throughput"));
FLAGS_LT_IP_TOS_ASSERT("lowdelay | throughput",
torrent::option_find_string(torrent::OPTION_IP_TOS, "lowdelay")
| torrent::option_find_string(torrent::OPTION_IP_TOS, "throughput"));
FLAGS_LT_IP_TOS_ASSERT_ERROR("throughput_");
}
+2
View File
@@ -14,6 +14,7 @@ class TestParseOptions : public test_fixture {
CPPUNIT_TEST(test_flags_print_flags);
CPPUNIT_TEST(test_flag_libtorrent);
CPPUNIT_TEST(test_flags_libtorrent);
CPPUNIT_TEST_SUITE_END();
@@ -29,4 +30,5 @@ public:
void test_flags_print_flags();
void test_flag_libtorrent();
void test_flags_libtorrent();
};
-54
View File
@@ -1,54 +0,0 @@
#include "config.h"
#include "test/src/test_command_local.h"
#include <torrent/torrent.h>
#include <torrent/runtime/socket_manager.h>
#include <torrent/utils/option_strings.h>
#include "control.h"
#include "globals.h"
#include "rpc/parse_commands.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandLocal);
void initialize_command_local();
void
TestCommandLocal::setUp() {
torrent::initialize_main_thread();
torrent::initialize();
if (control == nullptr)
control = new Control;
if (!rpc::commands.has("system.sockets.size"))
initialize_command_local();
}
void
TestCommandLocal::tearDown() {
torrent::cleanup();
}
void
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);
for (const auto suffix : {".size", ".max_size", ".min_alloc", ".max_alloc"})
if (rpc::commands.has(name + suffix))
CPPUNIT_ASSERT_NO_THROW(rpc::commands.call(name + suffix));
const bool has_allocation = category != torrent::runtime::category_generic;
CPPUNIT_ASSERT(rpc::commands.has(name + ".size"));
CPPUNIT_ASSERT(rpc::commands.has(name + ".max_size"));
CPPUNIT_ASSERT_EQUAL(has_allocation, rpc::commands.has(name + ".min_alloc"));
CPPUNIT_ASSERT_EQUAL(has_allocation, rpc::commands.has(name + ".max_alloc"));
CPPUNIT_ASSERT_EQUAL(has_allocation, rpc::commands.has(name + ".min_alloc.set"));
CPPUNIT_ASSERT_EQUAL(has_allocation, rpc::commands.has(name + ".max_alloc.set"));
}
}
-15
View File
@@ -1,15 +0,0 @@
#include "test/helpers/test_fixture.h"
class TestCommandLocal : public test_fixture {
CPPUNIT_TEST_SUITE(TestCommandLocal);
CPPUNIT_TEST(test_socket_category_commands);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void test_socket_category_commands();
};
+45
View File
@@ -0,0 +1,45 @@
#include "config.h"
#include "test/src/test_encryption_config.h"
#include <torrent/runtime/encryption_policy.h>
#include "encryption_config.h"
CPPUNIT_TEST_SUITE_REGISTRATION(TestEncryptionConfig);
void
TestEncryptionConfig::test_default_policy() {
const auto policy = encryption_config::default_policy();
CPPUNIT_ASSERT(policy.handshake == encryption_config::Policy::Mode::allow);
CPPUNIT_ASSERT(policy.stream == encryption_config::Policy::Mode::allow);
CPPUNIT_ASSERT_EQUAL(std::string("handshake=allow stream=allow"),
encryption_config::summary_string(policy));
}
void
TestEncryptionConfig::test_granular_round_trip() {
auto round_trip_handshake = [](const std::string& value) {
encryption_config::Policy policy;
encryption_config::apply_mode_value(policy, &encryption_config::Policy::handshake, value);
return encryption_config::mode_to_string(policy.handshake);
};
CPPUNIT_ASSERT_EQUAL(std::string("deny"), round_trip_handshake("deny"));
CPPUNIT_ASSERT_EQUAL(std::string("allow"), round_trip_handshake("allow"));
CPPUNIT_ASSERT_EQUAL(std::string("prefer"), round_trip_handshake("prefer"));
CPPUNIT_ASSERT_EQUAL(std::string("require"), round_trip_handshake("require"));
auto round_trip_stream = [](const std::string& value) {
encryption_config::Policy policy;
encryption_config::apply_mode_value(policy, &encryption_config::Policy::stream, value);
return encryption_config::mode_to_string(policy.stream);
};
CPPUNIT_ASSERT_EQUAL(std::string("deny"), round_trip_stream("deny"));
CPPUNIT_ASSERT_EQUAL(std::string("allow"), round_trip_stream("allow"));
CPPUNIT_ASSERT_EQUAL(std::string("prefer"), round_trip_stream("prefer"));
CPPUNIT_ASSERT_EQUAL(std::string("require"), round_trip_stream("require"));
}
+12
View File
@@ -0,0 +1,12 @@
#include "test/helpers/test_fixture.h"
class TestEncryptionConfig : public test_fixture {
CPPUNIT_TEST_SUITE(TestEncryptionConfig);
CPPUNIT_TEST(test_default_policy);
CPPUNIT_TEST(test_granular_round_trip);
CPPUNIT_TEST_SUITE_END();
public:
void test_default_policy();
void test_granular_round_trip();
};