mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-06 18:22:32 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d8664e6b4c | |||
| 7e907616a2 | |||
| dcf13ab21a | |||
| 03c4467a33 | |||
| fc5ce92c46 | |||
| f1b22023a0 | |||
| 928f3e58a8 | |||
| 743363b405 | |||
| fa351c017d | |||
| 1e1bdd551a | |||
| a07f57a703 | |||
| 0494ce70c8 | |||
| cfad36bf12 | |||
| 123c327a8f | |||
| 9884c9dd9b | |||
| d99cd5eb73 | |||
| 786f1234d2 | |||
| 23921cc97c | |||
| 6558f0ad42 | |||
| 9431dd5acc | |||
| 8598873627 | |||
| ce4cd27697 | |||
| 59fe93515e | |||
| 8249070ff1 | |||
| 517454b413 | |||
| a79aaad9ab | |||
| c6de871a77 | |||
| acb02379b8 | |||
| bf74686c29 | |||
| dbe7997131 | |||
| d595ebf7d8 | |||
| 08828045f5 | |||
| 662d67e861 | |||
| d08d7de20d |
@@ -37,6 +37,9 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: ubuntu-base
|
||||
steps:
|
||||
- name: Update Packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get install -y \
|
||||
@@ -75,6 +78,9 @@ jobs:
|
||||
matrix:
|
||||
config_flag: ["--with-xmlrpc-c", "--with-xmlrpc-tinyxml2"]
|
||||
steps:
|
||||
- name: Update Packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get install -y \
|
||||
|
||||
@@ -7,7 +7,6 @@ nobase_dist_pkgdata_DATA = \
|
||||
lua/rtorrent.lua
|
||||
|
||||
EXTRA_DIST= \
|
||||
rak/regex.h \
|
||||
scripts/checks.m4 \
|
||||
scripts/common.m4 \
|
||||
scripts/attributes.m4
|
||||
|
||||
+4
-3
@@ -1,6 +1,6 @@
|
||||
m4_pattern_allow([PKG_CHECK_EXISTS])
|
||||
|
||||
AC_INIT([rtorrent],[0.16.14],[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], [22], [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.14])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.17])
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
TORRENT_WITH_XMLRPC_C
|
||||
@@ -73,6 +73,7 @@ CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS $ZLIB_CFLAGS $DEPENDENCIES_CFLAGS
|
||||
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS $ZLIB_CFLAGS $DEPENDENCIES_CFLAGS"
|
||||
|
||||
TORRENT_CHECK_CACHELINE
|
||||
TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
|
||||
+9
-15
@@ -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
@@ -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
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_.' '-'`
|
||||
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
// rak - Rakshasa's toolbox
|
||||
// Copyright (C) 2005-2007, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
// This is a hacked up whole string pattern matching. Replace with
|
||||
// TR1's regex when that becomes widely available. It is intended for
|
||||
// small strings.
|
||||
|
||||
#ifndef RAK_REGEX_H
|
||||
#define RAK_REGEX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace rak {
|
||||
|
||||
class regex {
|
||||
public:
|
||||
regex() {}
|
||||
regex(const std::string& p) : m_pattern(p) {}
|
||||
|
||||
const std::string& pattern() const { return m_pattern; }
|
||||
|
||||
bool operator () (const std::string& p) const;
|
||||
|
||||
private:
|
||||
std::string m_pattern;
|
||||
};
|
||||
|
||||
// This isn't optimized, or very clean. A simple hack that should work.
|
||||
inline bool
|
||||
regex::operator () (const std::string& text) const {
|
||||
if (m_pattern.empty() ||
|
||||
text.empty() ||
|
||||
(m_pattern[0] != '*' && m_pattern[0] != text[0]))
|
||||
return false;
|
||||
|
||||
// Replace with unordered_vector?
|
||||
std::list<unsigned int> paths;
|
||||
paths.push_front(0);
|
||||
|
||||
for (std::string::const_iterator itrText = ++text.begin(), lastText = text.end(); itrText != lastText; ++itrText) {
|
||||
|
||||
for (std::list<unsigned int>::iterator itrPaths = paths.begin(), lastPaths = paths.end(); itrPaths != lastPaths; ) {
|
||||
|
||||
unsigned int next = *itrPaths + 1;
|
||||
|
||||
if (m_pattern[*itrPaths] != '*')
|
||||
itrPaths = paths.erase(itrPaths);
|
||||
else
|
||||
itrPaths++;
|
||||
|
||||
// When we reach the end of 'm_pattern', we don't have a whole
|
||||
// match of 'text'.
|
||||
if (next == m_pattern.size())
|
||||
continue;
|
||||
|
||||
// Push to the back so that '*' will match zero length strings.
|
||||
if (m_pattern[next] == '*')
|
||||
paths.push_back(next);
|
||||
|
||||
if (m_pattern[next] == *itrText)
|
||||
paths.push_front(next);
|
||||
}
|
||||
|
||||
if (paths.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::find(paths.begin(), paths.end(), m_pattern.size() - 1) != paths.end();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -298,6 +298,24 @@ AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_CHECK_POSIX_SPAWN_ADDCLOSEFROM_NP], [
|
||||
AC_MSG_CHECKING(for posix_spawn_file_actions_addclosefrom_np)
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#define _GNU_SOURCE
|
||||
#include <spawn.h>
|
||||
]], [[
|
||||
posix_spawn_file_actions_t actions;
|
||||
posix_spawn_file_actions_addclosefrom_np(&actions, 3);
|
||||
]])],[
|
||||
AC_DEFINE(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP, 1, [Define if posix_spawn_file_actions_addclosefrom_np is available.])
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([TORRENT_WITH_SYSTEMD], [
|
||||
AC_ARG_WITH(systemd,
|
||||
AS_HELP_STRING([--with-systemd],[enable systemd socket activation support [[default=no]]]),
|
||||
|
||||
@@ -118,6 +118,14 @@ AC_DEFUN([TORRENT_CHECK_CACHELINE], [
|
||||
AC_MSG_RESULT([linux fallback enterprise 128 bytes])
|
||||
AC_DEFINE([LT_SMP_CACHE_BYTES], 128, [Fallback 128-byte alignment for Linux enterprise hardware.])
|
||||
;;
|
||||
riscv32*|riscv64*)
|
||||
AC_MSG_RESULT([linux fallback RISC-V 64 bytes])
|
||||
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Fallback 64-byte alignment for Linux RISC-V hardware.])
|
||||
;;
|
||||
loongarch32*|loongarch64*)
|
||||
AC_MSG_RESULT([linux fallback LoongArch 64 bytes])
|
||||
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Fallback 64-byte alignment for Linux LoongArch hardware.])
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([unrecognized CPU arch on Linux header fallback])
|
||||
AC_MSG_FAILURE([Unrecognized CPU architecture ($host_cpu) on Linux fallback path. Aborting build.])
|
||||
|
||||
@@ -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 \
|
||||
|
||||
+19
-16
@@ -5,7 +5,7 @@
|
||||
#include <functional>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <rak/regex.h>
|
||||
#include <fnmatch.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/tracker/tracker.h>
|
||||
@@ -340,7 +340,7 @@ f_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
// parsing and searching command map for every single call.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
std::vector<rak::regex> regex_list;
|
||||
std::vector<std::string> regex_list;
|
||||
|
||||
bool use_regex = true;
|
||||
|
||||
@@ -354,7 +354,7 @@ f_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
|
||||
for (const auto& file : *download->file_list()) {
|
||||
if (use_regex &&
|
||||
std::none_of(regex_list.begin(), regex_list.end(), [&file](const auto& r) { return r(file->path()->as_string()); }))
|
||||
std::none_of(regex_list.begin(), regex_list.end(), [&file](const auto& pattern) { return fnmatch(pattern.c_str(), file->path()->as_string().c_str(), 0) == 0; }))
|
||||
continue;
|
||||
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
@@ -378,18 +378,19 @@ t_multicall(core::Download* download, 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.
|
||||
torrent::Object result_raw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = result_raw.as_list();
|
||||
|
||||
auto result_raw = torrent::Object::create_list();
|
||||
auto& result = result_raw.as_list();
|
||||
|
||||
for (uint32_t idx = 0, last = download->tracker_list_size(); idx < last; idx++) {
|
||||
auto& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
auto& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
auto tracker = download->tracker_controller().at(idx);
|
||||
|
||||
if (!tracker.is_valid())
|
||||
continue;
|
||||
|
||||
for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
for (auto cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
auto& cmd = cItr->as_string();
|
||||
|
||||
row.push_back(rpc::parse_command(rpc::make_target(&tracker), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
}
|
||||
@@ -408,13 +409,13 @@ p_multicall(core::Download* download, 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.
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
auto resultRaw = torrent::Object::create_list();
|
||||
auto& result = resultRaw.as_list();
|
||||
|
||||
for (const auto& connection : *download->connection_list()) {
|
||||
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++) {
|
||||
for (auto cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
|
||||
row.push_back(rpc::parse_command(rpc::make_target(connection), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
@@ -780,15 +781,15 @@ initialize_command_download() {
|
||||
CMD2_DL_TIMESTAMP("d.timestamp.started", "rtorrent", "timestamp.started");
|
||||
CMD2_DL_TIMESTAMP("d.timestamp.finished", "rtorrent", "timestamp.finished");
|
||||
|
||||
CMD2_DL ("d.connection_current", std::bind(&torrent::option_as_string, torrent::OPTION_CONNECTION_TYPE, CMD2_ON_DL(connection_type)));
|
||||
CMD2_DL_STRING("d.connection_current.set", std::bind(&apply_d_connection_type, std::placeholders::_1, std::placeholders::_2));
|
||||
CMD2_DL ("d.connection_current", [](auto* d, auto) { return torrent::option_to_c_str_or_throw(torrent::OPTION_CONNECTION_TYPE, d->download()->connection_type()); });
|
||||
CMD2_DL_STRING_V("d.connection_current.set", [](auto* d, auto arg) { apply_d_connection_type(d, arg); });
|
||||
|
||||
CMD2_DL_VAR_STRING("d.connection_leech", "rtorrent", "connection_leech");
|
||||
CMD2_DL_VAR_STRING("d.connection_seed", "rtorrent", "connection_seed");
|
||||
|
||||
CMD2_DL ("d.up.choke_heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(upload_choke_heuristic)));
|
||||
CMD2_DL ("d.up.choke_heuristics", [](auto* d, auto) { return torrent::option_to_c_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, d->download()->upload_choke_heuristic()); });
|
||||
CMD2_DL_STRING("d.up.choke_heuristics.set", std::bind(&apply_d_choke_heuristics, std::placeholders::_1, std::placeholders::_2, false));
|
||||
CMD2_DL ("d.down.choke_heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS, CMD2_ON_DL(download_choke_heuristic)));
|
||||
CMD2_DL ("d.down.choke_heuristics", [](auto* d, auto) { return torrent::option_to_c_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, d->download()->download_choke_heuristic()); });
|
||||
CMD2_DL_STRING("d.down.choke_heuristics.set", std::bind(&apply_d_choke_heuristics, std::placeholders::_1, std::placeholders::_2, true));
|
||||
|
||||
CMD2_DL_VAR_STRING("d.up.choke_heuristics.leech", "rtorrent", "choke_heuristics.up.leech");
|
||||
@@ -843,7 +844,7 @@ initialize_command_download() {
|
||||
CMD2_DL ("d.bytes_done", CMD2_ON_DL(bytes_done));
|
||||
CMD2_DL ("d.ratio", std::bind(&retrieve_d_ratio, std::placeholders::_1));
|
||||
CMD2_DL ("d.chunks_hashed", CMD2_ON_DL(chunks_hashed));
|
||||
CMD2_DL ("d.free_diskspace", CMD2_ON_FL(free_diskspace));
|
||||
CMD2_DL ("d.free_diskspace", [](auto* download, auto) { return download->file_list()->free_diskspace_no_cache(); });
|
||||
|
||||
CMD2_DL ("d.size_files", CMD2_ON_FL(size_files));
|
||||
CMD2_DL ("d.size_bytes", CMD2_ON_FL(size_bytes));
|
||||
@@ -972,6 +973,8 @@ initialize_command_download() {
|
||||
rpc::rpc.mark_safe("d.size_chunks");
|
||||
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.finished");
|
||||
rpc::rpc.mark_safe("d.bytes_done");
|
||||
rpc::rpc.mark_safe("d.peers_accounted");
|
||||
rpc::rpc.mark_safe("d.chunks_hashed");
|
||||
|
||||
@@ -448,7 +448,8 @@ initialize_command_dynamic() {
|
||||
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", std::bind(&torrent::option_list_strings, torrent::OPTION_ENCRYPTION));
|
||||
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));
|
||||
@@ -472,7 +473,8 @@ initialize_command_dynamic() {
|
||||
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");
|
||||
|
||||
+10
-8
@@ -168,12 +168,14 @@ torrent::Object
|
||||
apply_close_low_diskspace(int64_t arg, uint32_t skip_priority) {
|
||||
bool closed = false;
|
||||
|
||||
torrent::FileList::cache_list cache;
|
||||
|
||||
for (auto download : *control->core()->download_list()) {
|
||||
if (!download->is_downloading())
|
||||
continue;
|
||||
if (download->priority() >= skip_priority)
|
||||
continue;
|
||||
if (download->file_list()->free_diskspace() >= (uint64_t)arg)
|
||||
if (download->file_list()->free_diskspace(cache) >= (uint64_t)arg)
|
||||
continue;
|
||||
|
||||
control->core()->download_list()->close(download);
|
||||
@@ -256,11 +258,12 @@ torrent::Object
|
||||
d_multicall_filtered(const torrent::Object::list_type& args) {
|
||||
if (args.size() < 2)
|
||||
throw torrent::input_error("d.multicall.filtered requires at least 2 arguments.");
|
||||
torrent::Object::list_const_iterator arg = args.begin();
|
||||
|
||||
auto arg = args.begin();
|
||||
|
||||
// Find the given view
|
||||
core::ViewManager* viewManager = control->view_manager();
|
||||
core::ViewManager::iterator view_itr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string());
|
||||
auto* viewManager = control->view_manager();
|
||||
auto view_itr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string());
|
||||
|
||||
if (view_itr == viewManager->end())
|
||||
throw torrent::input_error("Could not find view '" + arg->as_string() + "'.");
|
||||
@@ -270,8 +273,9 @@ d_multicall_filtered(const torrent::Object::list_type& args) {
|
||||
(*view_itr)->filter_by(*++arg, dlist);
|
||||
|
||||
// Generate result by iterating over all items
|
||||
torrent::Object resultRaw = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = resultRaw.as_list();
|
||||
auto resultRaw = torrent::Object::create_list();
|
||||
auto& result = resultRaw.as_list();
|
||||
|
||||
++arg; // skip to first command
|
||||
|
||||
for (const auto& item : dlist) {
|
||||
@@ -358,7 +362,6 @@ initialize_command_events() {
|
||||
|
||||
// TODO: Deprecate d.multicall2. (6/2026)
|
||||
CMD2_ANY_LIST ("d.multicall", [](auto, auto& args) { return d_multicall(args); });
|
||||
CMD2_ANY_LIST ("d.multicall2", [](auto, auto& args) { return d_multicall(args); });
|
||||
CMD2_ANY_LIST ("d.multicall.filtered", [](auto, auto& args) { return d_multicall_filtered(args); });
|
||||
|
||||
CMD2_ANY_LIST ("directory.watch.added", [](auto, auto& args) { return directory_watch_added(args); });
|
||||
@@ -373,6 +376,5 @@ initialize_command_events() {
|
||||
rpc::rpc.mark_safe("close_low_diskspace.normal");
|
||||
rpc::rpc.mark_safe("download_list");
|
||||
rpc::rpc.mark_safe("d.multicall");
|
||||
rpc::rpc.mark_safe("d.multicall2");
|
||||
rpc::rpc.mark_safe("d.multicall.filtered");
|
||||
}
|
||||
|
||||
+29
-32
@@ -337,54 +337,51 @@ options.
|
||||
|
||||
void
|
||||
initialize_command_groups() {
|
||||
CMD2_ANY ("choke_group.list", std::bind(&apply_cg_list));
|
||||
CMD2_ANY_STRING ("choke_group.insert", std::bind(&apply_cg_insert, std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.list", std::bind(&apply_cg_list));
|
||||
CMD_ANY_STRING ("choke_group.insert", std::bind(&apply_cg_insert, std::placeholders::_2));
|
||||
|
||||
#if USE_CHOKE_GROUP
|
||||
CMD2_ANY ("choke_group.size", std::bind(&torrent::ResourceManager::group_size, torrent::resource_manager()));
|
||||
CMD2_ANY_STRING ("choke_group.index_of", std::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.size", std::bind(&torrent::ResourceManager::group_size, torrent::resource_manager()));
|
||||
CMD_ANY_STRING ("choke_group.index_of", std::bind(&torrent::ResourceManager::group_index_of, torrent::resource_manager(), std::placeholders::_2));
|
||||
#else
|
||||
apply_cg_insert("default");
|
||||
|
||||
CMD2_ANY ("choke_group.size", std::bind(&std::vector<torrent::choke_group*>::size, cg_list_hack));
|
||||
CMD2_ANY_STRING ("choke_group.index_of", std::bind(&apply_cg_index_of, std::placeholders::_2));
|
||||
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
|
||||
|
||||
// Commands specific for a group. Supports as the first argument the
|
||||
// name, the index or a negative index.
|
||||
CMD2_ANY ("choke_group.general.size", std::bind(&torrent::choke_group::size, CG_GROUP_AT()));
|
||||
CMD_ANY ("choke_group.general.size", std::bind(&torrent::choke_group::size, CG_GROUP_AT()));
|
||||
|
||||
CMD2_ANY ("choke_group.tracker.mode", std::bind(&torrent::option_as_string, torrent::OPTION_TRACKER_MODE,
|
||||
std::bind(&torrent::choke_group::tracker_mode, CG_GROUP_AT())));
|
||||
CMD2_ANY_LIST ("choke_group.tracker.mode.set", std::bind(&apply_cg_tracker_mode_set, std::placeholders::_2));
|
||||
CMD_ANY ("choke_group.tracker.mode", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_TRACKER_MODE, cg_get_group(arg)->tracker_mode()); });
|
||||
CMD_ANY_LIST ("choke_group.tracker.mode.set", [](auto, auto arg) { return apply_cg_tracker_mode_set(arg); });
|
||||
|
||||
CMD2_ANY ("choke_group.all.up.update_balance", std::bind(&apply_cg_all_update_balance, true));
|
||||
CMD2_ANY ("choke_group.all.down.update_balance", std::bind(&apply_cg_all_update_balance, false));
|
||||
CMD_ANY ("choke_group.all.up.update_balance", std::bind(&apply_cg_all_update_balance, true));
|
||||
CMD_ANY ("choke_group.all.down.update_balance", std::bind(&apply_cg_all_update_balance, false));
|
||||
|
||||
CMD2_ANY ("choke_group.up.rate", std::bind(&torrent::choke_group::up_rate, CG_GROUP_AT()));
|
||||
CMD2_ANY ("choke_group.down.rate", std::bind(&torrent::choke_group::down_rate, CG_GROUP_AT()));
|
||||
CMD_ANY ("choke_group.up.rate", std::bind(&torrent::choke_group::up_rate, CG_GROUP_AT()));
|
||||
CMD_ANY ("choke_group.down.rate", std::bind(&torrent::choke_group::down_rate, CG_GROUP_AT()));
|
||||
|
||||
CMD2_ANY ("choke_group.up.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY_LIST ("choke_group.up.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, true));
|
||||
CMD_ANY ("choke_group.up.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY_LIST ("choke_group.up.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, true));
|
||||
|
||||
CMD2_ANY ("choke_group.up.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD2_ANY ("choke_group.up.heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
|
||||
std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::up_queue))));
|
||||
CMD2_ANY_LIST ("choke_group.up.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, true));
|
||||
CMD_ANY ("choke_group.up.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::up_queue)));
|
||||
CMD_ANY ("choke_group.up.heuristics", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->up_queue()->heuristics()); });
|
||||
CMD_ANY_LIST ("choke_group.up.heuristics.set", [](auto, auto arg) { return apply_cg_heuristics_set(arg, true); });
|
||||
|
||||
CMD2_ANY ("choke_group.down.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY_LIST ("choke_group.down.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, false));
|
||||
CMD_ANY ("choke_group.down.max.unlimited", std::bind(&torrent::choke_queue::is_unlimited, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.max", std::bind(&torrent::choke_queue::max_unchoked_signed, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY_LIST ("choke_group.down.max.set", std::bind(&apply_cg_max_set, std::placeholders::_2, false));
|
||||
|
||||
CMD2_ANY ("choke_group.down.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD2_ANY ("choke_group.down.heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
|
||||
std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::down_queue))));
|
||||
CMD2_ANY_LIST ("choke_group.down.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, false));
|
||||
CMD_ANY ("choke_group.down.total", std::bind(&torrent::choke_queue::size_total, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.queued", std::bind(&torrent::choke_queue::size_queued, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.unchoked", std::bind(&torrent::choke_queue::size_unchoked, CHOKE_GROUP(&torrent::choke_group::down_queue)));
|
||||
CMD_ANY ("choke_group.down.heuristics", [](auto, auto arg) { return torrent::option_to_str_or_throw(torrent::OPTION_CHOKE_HEURISTICS, cg_get_group(arg)->down_queue()->heuristics()); });
|
||||
CMD_ANY_LIST ("choke_group.down.heuristics.set", [](auto, auto arg) { return apply_cg_heuristics_set(arg, false); });
|
||||
|
||||
rpc::rpc.mark_safe("choke_group.list");
|
||||
rpc::rpc.mark_safe("choke_group.size");
|
||||
|
||||
+19
-1
@@ -7,6 +7,25 @@
|
||||
|
||||
void initialize_commands();
|
||||
|
||||
//
|
||||
// Aliases with CMD_* for the below
|
||||
//
|
||||
|
||||
#define CMD_ANY(key, slot) CMD2_ANY(key, slot)
|
||||
#define CMD_ANY_P(key, slot) CMD2_ANY_P(key, slot)
|
||||
#define CMD_REDIRECT(key, slot) CMD2_REDIRECT(key, slot)
|
||||
#define CMD_REDIRECT_NO_EXPORT(key, slot) CMD2_REDIRECT_NO_EXPORT(key, slot)
|
||||
#define CMD_ANY_STRING(key, slot) CMD2_ANY_STRING(key, slot)
|
||||
#define CMD_ANY_STRING_V(key, slot) CMD2_ANY_STRING_V(key, slot)
|
||||
#define CMD_ANY_LIST(key, slot) CMD2_ANY_LIST(key, slot)
|
||||
#define CMD_VAR_VALUE(key, value) CMD2_VAR_VALUE(key, value)
|
||||
#define CMD_VAR_BOOL(key, value) CMD2_VAR_BOOL(key, value)
|
||||
#define CMD_VAR_STRING(key, value) CMD2_VAR_STRING(key, value)
|
||||
#define CMD_VAR_C_STRING(key, value) CMD2_VAR_C_STRING(key, value)
|
||||
#define CMD_VAR_LIST(key) CMD2_VAR_LIST(key)
|
||||
#define CMD_ANY_V(key, slot) CMD2_ANY_V(key, slot)
|
||||
#define CMD_ANY_VALUE_V(key, slot) CMD2_ANY_VALUE_V(key, slot)
|
||||
|
||||
//
|
||||
// New std::function based command_base helper functions:
|
||||
//
|
||||
@@ -115,7 +134,6 @@ void initialize_commands();
|
||||
#define CMD2_REDIRECT_TRACKER(from_key, to_key) \
|
||||
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_tracker_target | rpc::CommandMap::flag_dont_delete);
|
||||
|
||||
|
||||
//
|
||||
// Conversion of return types:
|
||||
//
|
||||
|
||||
+1
-1
@@ -353,7 +353,7 @@ apply_ipv4_filter_dump() {
|
||||
inet_ntop(AF_INET, &net_start, start_str, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &net_end, end_str, INET_ADDRSTRLEN);
|
||||
|
||||
snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_as_string(torrent::OPTION_IP_FILTER, value));
|
||||
snprintf(buffer, 64, "%s-%s %s", start_str, end_str, torrent::option_to_c_str_or_throw(torrent::OPTION_IP_FILTER, value));
|
||||
|
||||
result.push_back((std::string)buffer);
|
||||
|
||||
|
||||
+127
-97
@@ -8,10 +8,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/chunk_manager.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/runtime/socket_manager.h>
|
||||
#include <torrent/utils/chrono.h>
|
||||
#include <torrent/utils/option_strings.h>
|
||||
|
||||
@@ -187,143 +188,160 @@ cmd_file_append(const torrent::Object::list_type& args) {
|
||||
void
|
||||
initialize_command_local() {
|
||||
core::DownloadList* dList = control->core()->download_list();
|
||||
torrent::ChunkManager* chunkManager = torrent::chunk_manager();
|
||||
torrent::FileManager* fileManager = torrent::file_manager();
|
||||
|
||||
if (rpc::call_command_value("method.use_deprecated") == 1) {
|
||||
CMD2_ANY_LIST ("file.append", std::bind(&cmd_file_append, std::placeholders::_2));
|
||||
CMD_ANY_LIST ("file.append", std::bind(&cmd_file_append, std::placeholders::_2));
|
||||
}
|
||||
|
||||
CMD2_ANY ("system.hostname", std::bind(&system_hostname));
|
||||
CMD2_ANY ("system.pid", std::bind(&getpid));
|
||||
CMD_ANY ("system.hostname", std::bind(&system_hostname));
|
||||
CMD_ANY ("system.pid", std::bind(&getpid));
|
||||
|
||||
CMD2_VAR_C_STRING("system.api_version", (int64_t)API_VERSION);
|
||||
CMD2_VAR_C_STRING("system.client_version", PACKAGE_VERSION);
|
||||
CMD2_VAR_C_STRING("system.library_version", torrent::runtime::version());
|
||||
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());
|
||||
|
||||
CMD2_VAR_VALUE ("system.file.allocate", 0);
|
||||
CMD2_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30);
|
||||
CMD2_VAR_VALUE ("system.file.split_size", -1);
|
||||
CMD2_VAR_STRING ("system.file.split_suffix", ".part");
|
||||
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");
|
||||
|
||||
CMD2_ANY ("system.file_status_cache.size", std::bind(&utils::FileStatusCache::size,
|
||||
CMD_ANY ("system.file_status_cache.size", std::bind(&utils::FileStatusCache::size,
|
||||
(utils::FileStatusCache::base_type*)control->core()->file_status_cache()));
|
||||
CMD2_ANY_V ("system.file_status_cache.prune", std::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
|
||||
CMD_ANY_V ("system.file_status_cache.prune", std::bind(&utils::FileStatusCache::prune, control->core()->file_status_cache()));
|
||||
|
||||
CMD2_VAR_BOOL ("file.prioritize_toc", 0);
|
||||
CMD2_VAR_LIST ("file.prioritize_toc.first");
|
||||
CMD2_VAR_LIST ("file.prioritize_toc.last");
|
||||
CMD_VAR_BOOL ("file.prioritize_toc", 0);
|
||||
CMD_VAR_LIST ("file.prioritize_toc.first");
|
||||
CMD_VAR_LIST ("file.prioritize_toc.last");
|
||||
|
||||
CMD2_ANY ("system.files.advise_random", std::bind(&FM_t::advise_random, fileManager));
|
||||
CMD2_ANY_VALUE_V ("system.files.advise_random.set", std::bind(&FM_t::set_advise_random, fileManager, std::placeholders::_2));
|
||||
CMD2_ANY ("system.files.advise_random.hashing", std::bind(&FM_t::advise_random_hashing, fileManager));
|
||||
CMD2_ANY_VALUE_V ("system.files.advise_random.hashing.set", std::bind(&FM_t::set_advise_random_hashing, fileManager, std::placeholders::_2));
|
||||
CMD2_ANY ("system.files.session.fdatasync", [](auto, auto) { return session_thread::manager()->use_fsyncdisk(); });
|
||||
CMD2_ANY_VALUE_V ("system.files.session.fdatasync.set", [](auto, auto& value) { return session_thread::manager()->set_use_fsyncdisk(value); });
|
||||
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); });
|
||||
|
||||
CMD2_ANY ("system.files.opened_counter", std::bind(&FM_t::files_opened_counter, fileManager));
|
||||
CMD2_ANY ("system.files.closed_counter", std::bind(&FM_t::files_closed_counter, fileManager));
|
||||
CMD2_ANY ("system.files.failed_counter", std::bind(&FM_t::files_failed_counter, fileManager));
|
||||
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));
|
||||
|
||||
CMD2_ANY_STRING ("system.env", std::bind(&system_env, std::placeholders::_2));
|
||||
CMD_ANY_STRING ("system.env", [](auto, auto& str) { return system_env(str); });
|
||||
|
||||
CMD2_ANY ("system.time", []([[maybe_unused]] auto t, [[maybe_unused]] auto o) -> torrent::Object {
|
||||
return torrent::this_thread::cached_seconds().count();
|
||||
});
|
||||
CMD2_ANY ("system.time_seconds", []([[maybe_unused]] auto t, [[maybe_unused]] auto o) -> torrent::Object {
|
||||
return torrent::utils::cast_seconds(torrent::utils::time_since_epoch()).count();
|
||||
});
|
||||
CMD2_ANY ("system.time_usec", []([[maybe_unused]] auto t, [[maybe_unused]] auto o) -> torrent::Object {
|
||||
return torrent::utils::time_since_epoch().count();
|
||||
});
|
||||
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(); });
|
||||
|
||||
CMD2_ANY_VALUE_V ("system.umask.set", std::bind(&umask, std::placeholders::_2));
|
||||
CMD_ANY_VALUE_V ("system.umask.set", [](auto, auto& value) { return ::umask(value); });
|
||||
|
||||
CMD2_VAR_BOOL ("system.daemon", false);
|
||||
CMD_VAR_BOOL ("system.daemon", false);
|
||||
|
||||
CMD2_ANY_V ("system.shutdown.normal", std::bind(&Control::receive_normal_shutdown, control));
|
||||
CMD2_ANY_V ("system.shutdown.quick", std::bind(&Control::receive_quick_shutdown, control));
|
||||
CMD2_REDIRECT_NO_EXPORT("system.shutdown", "system.shutdown.normal");
|
||||
CMD_ANY_V ("system.shutdown.normal", [](auto, auto) { control->receive_normal_shutdown(); });
|
||||
CMD_ANY_V ("system.shutdown.quick", [](auto, auto) { control->receive_quick_shutdown(); });
|
||||
|
||||
CMD2_ANY ("system.cwd", std::bind(&system_get_cwd));
|
||||
CMD2_ANY_STRING ("system.cwd.set", std::bind(&system_set_cwd, std::placeholders::_2));
|
||||
CMD_REDIRECT_NO_EXPORT("system.shutdown", "system.shutdown.normal");
|
||||
|
||||
CMD2_ANY ("pieces.sync.always_safe", std::bind(&CM_t::safe_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.always_safe.set", std::bind(&CM_t::set_safe_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.safe_free_diskspace", std::bind(&CM_t::safe_free_diskspace, chunkManager));
|
||||
CMD2_ANY ("pieces.sync.timeout", std::bind(&CM_t::timeout_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.timeout.set", std::bind(&CM_t::set_timeout_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.timeout_safe", std::bind(&CM_t::timeout_safe_sync, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.sync.timeout_safe.set", std::bind(&CM_t::set_timeout_safe_sync, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.sync.queue_size", std::bind(&CM_t::sync_queue_size, chunkManager));
|
||||
CMD_ANY ("system.cwd", [](auto, auto) { return system_get_cwd(); });
|
||||
CMD_ANY_STRING ("system.cwd.set", [](auto, auto& str) { return system_set_cwd(str); });
|
||||
|
||||
CMD2_ANY ("pieces.preload.type", std::bind(&CM_t::preload_type, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.type.set", std::bind(&CM_t::set_preload_type, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.preload.min_size", std::bind(&CM_t::preload_min_size, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.min_size.set", std::bind(&CM_t::set_preload_min_size, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.preload.min_rate", std::bind(&CM_t::preload_required_rate, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.preload.min_rate.set", std::bind(&CM_t::set_preload_required_rate, chunkManager, std::placeholders::_2));
|
||||
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(); });
|
||||
|
||||
CMD2_ANY ("pieces.memory.current", std::bind(&CM_t::memory_usage, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.sync_queue", std::bind(&CM_t::sync_queue_memory_usage, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.block_count", std::bind(&CM_t::memory_block_count, chunkManager));
|
||||
CMD2_ANY ("pieces.memory.max", std::bind(&CM_t::max_memory_usage, chunkManager));
|
||||
CMD2_ANY_VALUE_V ("pieces.memory.max.set", std::bind(&CM_t::set_max_memory_usage, chunkManager, std::placeholders::_2));
|
||||
CMD2_ANY ("pieces.stats_preloaded", std::bind(&CM_t::stats_preloaded, chunkManager));
|
||||
CMD2_ANY ("pieces.stats_not_preloaded", std::bind(&CM_t::stats_not_preloaded, chunkManager));
|
||||
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);
|
||||
|
||||
CMD2_ANY ("pieces.stats.total_size", std::bind(&apply_pieces_stats_total_size));
|
||||
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); });
|
||||
|
||||
CMD2_ANY ("pieces.hash.queue_size", std::bind(&torrent::main_thread::hash_queue_size));
|
||||
CMD2_VAR_BOOL ("pieces.hash.on_completion", true);
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
CMD2_VAR_STRING ("directory.default", "./");
|
||||
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); });
|
||||
}
|
||||
|
||||
CMD2_VAR_STRING ("session.name", "");
|
||||
CMD2_ANY ("session.path", [](auto, auto) { return session_thread::manager()->path(); });
|
||||
CMD2_ANY_STRING_V("session.path.set", [](auto, auto& str) { return session_thread::manager()->set_path(str); });
|
||||
CMD2_ANY ("session.use_lock", [](auto, auto) { return session_thread::manager()->use_lock(); });
|
||||
CMD2_ANY_VALUE_V ("session.use_lock.set", [](auto, auto& value) { return session_thread::manager()->set_use_lock(value); });
|
||||
CMD2_VAR_BOOL ("session.on_completion", true);
|
||||
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) { });
|
||||
CMD_ANY ("pieces.sync.queue_size", [](auto, auto) { return torrent::runtime::memory_manager()->sync_queue_block_count(); });
|
||||
|
||||
CMD2_ANY_V ("session.save", [dList](auto, auto) { return dList->session_save(); });
|
||||
CMD_ANY ("pieces.preload.type", [](auto, auto) { return torrent::runtime::memory_manager()->preload_type(); });
|
||||
CMD_ANY_VALUE_V ("pieces.preload.type.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_preload_type(value); });
|
||||
CMD_ANY ("pieces.preload.min_size", [](auto, auto) { return torrent::runtime::memory_manager()->preload_min_size(); });
|
||||
CMD_ANY_VALUE_V ("pieces.preload.min_size.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_preload_min_size(value); });
|
||||
CMD_ANY ("pieces.preload.min_rate", [](auto, auto) { return torrent::runtime::memory_manager()->preload_required_rate(); });
|
||||
CMD_ANY_VALUE_V ("pieces.preload.min_rate.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_preload_required_rate(value); });
|
||||
|
||||
CMD2_ANY ("magnet.path", [](auto, auto) { return control->core()->magnet_path(); });
|
||||
CMD2_ANY_STRING_V("magnet.path.set", [](auto, auto& str) { return control->core()->set_magnet_path(str); });
|
||||
CMD_ANY ("pieces.stats_preloaded", [](auto, auto) { return torrent::runtime::memory_manager()->stats_preloaded(); });
|
||||
CMD_ANY ("pieces.stats_not_preloaded", [](auto, auto) { return torrent::runtime::memory_manager()->stats_not_preloaded(); });
|
||||
CMD_ANY ("pieces.stats.total_size", std::bind(&apply_pieces_stats_total_size));
|
||||
|
||||
CMD_ANY ("pieces.memory.current", [](auto, auto) { return torrent::runtime::memory_manager()->memory_usage(); });
|
||||
CMD_ANY ("pieces.memory.sync_queue", [](auto, auto) { return torrent::runtime::memory_manager()->sync_queue_memory_usage(); });
|
||||
CMD_ANY ("pieces.memory.block_count", [](auto, auto) { return torrent::runtime::memory_manager()->memory_block_count(); });
|
||||
CMD_ANY ("pieces.memory.max", [](auto, auto) { return torrent::runtime::memory_manager()->max_memory_usage(); });
|
||||
CMD_ANY_VALUE_V ("pieces.memory.max.set", [](auto, auto& value) { return torrent::runtime::memory_manager()->set_max_memory_usage(value); });
|
||||
|
||||
CMD_ANY ("pieces.hash.queue_size", std::bind(&torrent::main_thread::hash_queue_size));
|
||||
CMD_VAR_BOOL ("pieces.hash.on_completion", true);
|
||||
|
||||
CMD_VAR_STRING ("directory.default", "./");
|
||||
|
||||
CMD_VAR_STRING ("session.name", "");
|
||||
CMD_ANY ("session.path", [](auto, auto) { return session_thread::manager()->path(); });
|
||||
CMD_ANY_STRING_V("session.path.set", [](auto, auto& str) { return session_thread::manager()->set_path(str); });
|
||||
CMD_ANY ("session.use_lock", [](auto, auto) { return session_thread::manager()->use_lock(); });
|
||||
CMD_ANY_VALUE_V ("session.use_lock.set", [](auto, auto& value) { return session_thread::manager()->set_use_lock(value); });
|
||||
CMD_VAR_BOOL ("session.on_completion", true);
|
||||
|
||||
CMD_ANY_V ("session.save", [dList](auto, auto) { return dList->session_save(); });
|
||||
|
||||
CMD_ANY ("magnet.path", [](auto, auto) { return control->core()->magnet_path(); });
|
||||
CMD_ANY_STRING_V("magnet.path.set", [](auto, auto& str) { return control->core()->set_magnet_path(str); });
|
||||
|
||||
#ifdef HAVE_LUA
|
||||
rpc::LuaEngine* lua_engine = control->lua_engine();
|
||||
|
||||
CMD2_ANY ("lua.execute", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD2_ANY ("lua.execute.str", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, rpc::LuaEngine::flag_string));
|
||||
CMD_ANY ("lua.execute", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, 0));
|
||||
CMD_ANY ("lua.execute.str", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, rpc::LuaEngine::flag_string));
|
||||
#endif
|
||||
|
||||
#define CMD2_EXECUTE(key, flags) \
|
||||
CMD2_ANY(key, std::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::placeholders::_2, flags));
|
||||
#define CMD_EXECUTE(key, flags) \
|
||||
CMD_ANY(key, std::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::placeholders::_2, flags));
|
||||
|
||||
CMD2_EXECUTE ("execute", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute.throw", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute.throw.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.nothrow", rpc::ExecFile::flag_expand_tilde);
|
||||
CMD2_EXECUTE ("execute.nothrow.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.raw", rpc::ExecFile::flag_throw);
|
||||
CMD2_EXECUTE ("execute.raw.bg", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.raw_nothrow", 0);
|
||||
CMD2_EXECUTE ("execute.raw_nothrow.bg", rpc::ExecFile::flag_background);
|
||||
CMD2_EXECUTE ("execute.capture", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
CMD2_EXECUTE ("execute.capture_nothrow", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
CMD_EXECUTE ("execute", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD_EXECUTE ("execute.throw", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw);
|
||||
CMD_EXECUTE ("execute.throw.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD_EXECUTE ("execute.nothrow", rpc::ExecFile::flag_expand_tilde);
|
||||
CMD_EXECUTE ("execute.nothrow.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_background);
|
||||
CMD_EXECUTE ("execute.raw", rpc::ExecFile::flag_throw);
|
||||
CMD_EXECUTE ("execute.raw.bg", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background);
|
||||
CMD_EXECUTE ("execute.raw_nothrow", 0);
|
||||
CMD_EXECUTE ("execute.raw_nothrow.bg", rpc::ExecFile::flag_background);
|
||||
CMD_EXECUTE ("execute.capture", rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
CMD_EXECUTE ("execute.capture_nothrow", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture);
|
||||
|
||||
// TODO: Convert to new command types:
|
||||
*rpc::command_base::argument(0) = "placeholder.0";
|
||||
*rpc::command_base::argument(1) = "placeholder.1";
|
||||
*rpc::command_base::argument(2) = "placeholder.2";
|
||||
*rpc::command_base::argument(3) = "placeholder.3";
|
||||
CMD2_ANY_P("argument.0", std::bind(&rpc::command_base::argument_ref, 0));
|
||||
CMD2_ANY_P("argument.1", std::bind(&rpc::command_base::argument_ref, 1));
|
||||
CMD2_ANY_P("argument.2", std::bind(&rpc::command_base::argument_ref, 2));
|
||||
CMD2_ANY_P("argument.3", std::bind(&rpc::command_base::argument_ref, 3));
|
||||
CMD_ANY_P("argument.0", std::bind(&rpc::command_base::argument_ref, 0));
|
||||
CMD_ANY_P("argument.1", std::bind(&rpc::command_base::argument_ref, 1));
|
||||
CMD_ANY_P("argument.2", std::bind(&rpc::command_base::argument_ref, 2));
|
||||
CMD_ANY_P("argument.3", std::bind(&rpc::command_base::argument_ref, 3));
|
||||
|
||||
CMD2_ANY_LIST ("group.insert", std::bind(&group_insert, std::placeholders::_2));
|
||||
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");
|
||||
@@ -332,6 +350,18 @@ initialize_command_local() {
|
||||
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");
|
||||
|
||||
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");
|
||||
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.use_lock");
|
||||
|
||||
+89
-105
@@ -9,13 +9,17 @@
|
||||
#include <torrent/download/resource_manager.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/net/socket_address.h>
|
||||
#include <torrent/runtime/client_config.h>
|
||||
#include <torrent/runtime/network_config.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/runtime/proxy_manager.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/runtime/socket_manager.h>
|
||||
#include <torrent/tracker/tracker.h>
|
||||
#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"
|
||||
@@ -31,24 +35,6 @@
|
||||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
torrent::Object
|
||||
apply_encryption(const torrent::Object::list_type& args) {
|
||||
uint32_t options_mask = torrent::runtime::NetworkConfig::encryption_none;
|
||||
|
||||
for (const auto& arg : args) {
|
||||
uint32_t opt = torrent::option_find_string(torrent::OPTION_ENCRYPTION, arg.as_string().c_str());
|
||||
|
||||
if (opt == torrent::runtime::NetworkConfig::encryption_none)
|
||||
options_mask = torrent::runtime::NetworkConfig::encryption_none;
|
||||
else
|
||||
options_mask |= opt;
|
||||
}
|
||||
|
||||
torrent::runtime::network_config()->set_encryption_options(options_mask);
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_tos(const torrent::Object::string_type& arg) {
|
||||
rpc::command_base::value_type value;
|
||||
@@ -219,104 +205,101 @@ initialize_command_network() {
|
||||
auto http_stack = torrent::net_thread::http_stack();
|
||||
auto nw_config = torrent::runtime::network_config();
|
||||
|
||||
// Isn't port_open used?
|
||||
CMD2_VAR_BOOL ("network.port_open", true);
|
||||
CMD2_VAR_BOOL ("network.port_random", true);
|
||||
CMD2_VAR_STRING ("network.port_range", "6881-6999");
|
||||
CMD_ANY ("network.listen.port", [](auto, auto) { return torrent::runtime::network_manager()->listen_port(); });
|
||||
CMD_ANY_VALUE_V ("network.listen.port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_listen_port(value); });
|
||||
CMD_ANY ("network.listen.port.random", [](auto, auto) { return torrent::runtime::client_config()->listen_port_random(); });
|
||||
CMD_ANY_VALUE_V ("network.listen.port.random.set", [](auto, auto& value) { return torrent::runtime::client_config()->set_listen_port_random(value); });
|
||||
CMD_ANY ("network.listen.port.range", [](auto, auto) { return listen_port_range(); });
|
||||
CMD_ANY_STRING_V("network.listen.port.range.set", [](auto, auto& value) { return set_listen_port_range(value); });
|
||||
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); });
|
||||
|
||||
CMD2_ANY ("network.listen.port", [](auto, auto) { return torrent::runtime::listen_port(); });
|
||||
CMD2_ANY ("network.listen.backlog", [nw_config](auto, auto) { return nw_config->listen_backlog(); });
|
||||
CMD2_ANY_VALUE_V ("network.listen.backlog.set", [nw_config](auto, auto& value) { return nw_config->set_listen_backlog(value); });
|
||||
CMD_VAR_BOOL ("protocol.pex", true);
|
||||
|
||||
CMD2_VAR_BOOL ("protocol.pex", true);
|
||||
CMD2_ANY_LIST ("protocol.encryption.set", [](auto, auto& args) { return apply_encryption(args); });
|
||||
encryption_config::initialize_commands();
|
||||
|
||||
CMD2_VAR_STRING ("protocol.connection.leech", "leech");
|
||||
CMD2_VAR_STRING ("protocol.connection.seed", "seed");
|
||||
CMD_VAR_STRING ("protocol.connection.leech", "leech");
|
||||
CMD_VAR_STRING ("protocol.connection.seed", "seed");
|
||||
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech");
|
||||
CMD2_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech");
|
||||
CMD_VAR_STRING ("protocol.choke_heuristics.up.leech", "upload_leech");
|
||||
CMD_VAR_STRING ("protocol.choke_heuristics.up.seed", "upload_leech");
|
||||
CMD_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech");
|
||||
CMD_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech");
|
||||
|
||||
CMD2_ANY ("network.http.cacert", [http_stack](auto, auto) { return http_stack->http_cacert(); });
|
||||
CMD2_ANY_STRING_V("network.http.cacert.set", [http_stack](auto, auto& str) { return http_stack->set_http_cacert(str); });
|
||||
CMD2_ANY ("network.http.capath", [http_stack](auto, auto) { return http_stack->http_capath(); });
|
||||
CMD2_ANY_STRING_V("network.http.capath.set", [http_stack](auto, auto& str) { return http_stack->set_http_capath(str); });
|
||||
CMD2_ANY ("network.http.dns_cache_timeout", [http_stack](auto, auto) { return http_stack->dns_timeout(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", [http_stack](auto, auto& value) { return http_stack->set_dns_timeout(value); });
|
||||
CMD2_ANY ("network.http.current_open", [http_stack](auto, auto) { return http_stack->size(); });
|
||||
CMD2_ANY ("network.http.max_cache_connections", [http_stack](auto, auto) { return http_stack->max_cache_connections(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.max_cache_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_cache_connections(value); });
|
||||
CMD2_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); });
|
||||
CMD2_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.max_total_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_total_connections(value); });
|
||||
CMD2_ANY ("network.http.proxy_address", [http_stack](auto, auto) { return http_stack->http_proxy(); });
|
||||
CMD2_ANY_STRING_V("network.http.proxy_address.set", [http_stack](auto, auto& str) { return http_stack->set_http_proxy(str); });
|
||||
CMD2_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_host.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_host(value); });
|
||||
CMD2_ANY ("network.http.ssl_verify_peer", [http_stack](auto, auto) { return http_stack->ssl_verify_peer(); });
|
||||
CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_peer(value); });
|
||||
CMD_ANY ("network.http.cacert", [http_stack](auto, auto) { return http_stack->http_cacert(); });
|
||||
CMD_ANY_STRING_V("network.http.cacert.set", [http_stack](auto, auto& str) { return http_stack->set_http_cacert(str); });
|
||||
CMD_ANY ("network.http.capath", [http_stack](auto, auto) { return http_stack->http_capath(); });
|
||||
CMD_ANY_STRING_V("network.http.capath.set", [http_stack](auto, auto& str) { return http_stack->set_http_capath(str); });
|
||||
CMD_ANY ("network.http.dns_cache_timeout", [http_stack](auto, auto) { return http_stack->dns_timeout(); });
|
||||
CMD_ANY_VALUE_V ("network.http.dns_cache_timeout.set", [http_stack](auto, auto& value) { return http_stack->set_dns_timeout(value); });
|
||||
CMD_ANY ("network.http.current_open", [http_stack](auto, auto) { return http_stack->size(); });
|
||||
CMD_ANY ("network.http.max_cache_connections", [http_stack](auto, auto) { return http_stack->max_cache_connections(); });
|
||||
CMD_ANY_VALUE_V ("network.http.max_cache_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_cache_connections(value); });
|
||||
CMD_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); });
|
||||
CMD_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); });
|
||||
CMD_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); });
|
||||
|
||||
CMD2_ANY ("network.send_buffer.size", [nw_config](auto, auto) { return nw_config->send_buffer_size(); });
|
||||
CMD2_ANY_VALUE_V ("network.send_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_send_buffer_size(value); });
|
||||
CMD2_ANY ("network.receive_buffer.size", [nw_config](auto, auto) { return nw_config->receive_buffer_size(); });
|
||||
CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_receive_buffer_size(value); });
|
||||
CMD2_ANY_STRING ("network.tos.set", [](auto, auto& str) { return apply_tos(str); });
|
||||
CMD_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); });
|
||||
CMD_ANY_VALUE_V ("network.http.ssl_verify_host.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_host(value); });
|
||||
CMD_ANY ("network.http.ssl_verify_peer", [http_stack](auto, auto) { return http_stack->ssl_verify_peer(); });
|
||||
CMD_ANY_VALUE_V ("network.http.ssl_verify_peer.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_peer(value); });
|
||||
|
||||
CMD2_ANY ("network.bind_address", [nw_config](auto, auto) { return nw_config->bind_address_best_match_str(); });
|
||||
CMD2_ANY_STRING_V("network.bind_address.set", [nw_config](auto, auto& str) { return nw_config->set_bind_address_str(str); });
|
||||
CMD2_ANY ("network.bind_address.ipv4", [nw_config](auto, auto) { return nw_config->bind_inet_address_str(); });
|
||||
CMD2_ANY_STRING_V("network.bind_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet_address_str(str); });
|
||||
CMD2_ANY ("network.bind_address.ipv6", [nw_config](auto, auto) { return nw_config->bind_inet6_address_str(); });
|
||||
CMD2_ANY_STRING_V("network.bind_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet6_address_str(str); });
|
||||
CMD_ANY ("network.send_buffer.size", [nw_config](auto, auto) { return nw_config->send_buffer_size(); });
|
||||
CMD_ANY_VALUE_V ("network.send_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_send_buffer_size(value); });
|
||||
CMD_ANY ("network.receive_buffer.size", [nw_config](auto, auto) { return nw_config->receive_buffer_size(); });
|
||||
CMD_ANY_VALUE_V ("network.receive_buffer.size.set", [nw_config](auto, auto& value) { return nw_config->set_receive_buffer_size(value); });
|
||||
CMD_ANY_STRING ("network.tos.set", [](auto, auto& str) { return apply_tos(str); });
|
||||
|
||||
CMD2_ANY ("network.local_address", [nw_config](auto, auto) { return nw_config->local_address_best_match_str(); });
|
||||
CMD2_ANY_STRING_V("network.local_address.set", [nw_config](auto, auto& str) { return nw_config->set_local_address_str(str); });
|
||||
CMD2_ANY ("network.local_address.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_address_str(); });
|
||||
CMD2_ANY_STRING_V("network.local_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet_address_str(str); });
|
||||
CMD2_ANY ("network.local_address.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_address_str(); });
|
||||
CMD2_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.bind_address", [nw_config](auto, auto) { return nw_config->bind_address_best_match_str(); });
|
||||
CMD_ANY_STRING_V("network.bind_address.set", [nw_config](auto, auto& str) { return nw_config->set_bind_address_str(str); });
|
||||
CMD_ANY ("network.bind_address.ipv4", [nw_config](auto, auto) { return nw_config->bind_inet_address_str(); });
|
||||
CMD_ANY_STRING_V("network.bind_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet_address_str(str); });
|
||||
CMD_ANY ("network.bind_address.ipv6", [nw_config](auto, auto) { return nw_config->bind_inet6_address_str(); });
|
||||
CMD_ANY_STRING_V("network.bind_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_bind_inet6_address_str(str); });
|
||||
|
||||
CMD2_ANY ("network.proxy_address", [nw_config](auto, auto) { return nw_config->proxy_address_str(); });
|
||||
CMD2_ANY_STRING_V("network.proxy_address.set", [](auto, auto& str) { return control->core()->set_proxy_address(str); });
|
||||
CMD_ANY ("network.local_address", [nw_config](auto, auto) { return nw_config->local_address_best_match_str(); });
|
||||
CMD_ANY_STRING_V("network.local_address.set", [nw_config](auto, auto& str) { return nw_config->set_local_address_str(str); });
|
||||
CMD_ANY ("network.local_address.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_address_str(); });
|
||||
CMD_ANY_STRING_V("network.local_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet_address_str(str); });
|
||||
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); });
|
||||
|
||||
CMD2_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); });
|
||||
CMD2_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); });
|
||||
CMD2_ANY_VALUE_V ("network.max_open_files.set", [file_manager](auto, auto& value) { return file_manager->set_max_open_files(value); });
|
||||
CMD2_ANY ("network.total_handshakes", [](auto, auto) { return torrent::runtime::total_handshakes(); });
|
||||
CMD2_ANY ("network.open_sockets", [](auto, auto) { return torrent::runtime::socket_manager()->size(); });
|
||||
CMD2_ANY ("network.max_open_sockets", [](auto, auto) { return torrent::runtime::socket_manager()->max_size(); });
|
||||
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", [](auto, auto& value) { return torrent::runtime::socket_manager()->set_max_size_and_adjust(value); });
|
||||
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(); });
|
||||
CMD_ANY_STRING_V("network.proxy.http.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_http_proxy_url(str); });
|
||||
|
||||
CMD2_ANY_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1));
|
||||
CMD2_ANY_STRING ("network.scgi.open_local", std::bind(&apply_scgi, std::placeholders::_2, 2));
|
||||
CMD2_VAR_BOOL ("network.scgi.dont_route", false);
|
||||
CMD2_ANY ("network.scgi.open_systemd", [](auto, auto) { return apply_scgi_systemd(); });
|
||||
CMD_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); });
|
||||
CMD_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); });
|
||||
CMD_ANY ("network.total_handshakes", [](auto, auto) { return torrent::runtime::total_handshakes(); });
|
||||
|
||||
CMD2_ANY ("network.scgi.use_gzip", [](const auto&, const auto&) { return rpc::rpc.scgi_allow_compression(); });
|
||||
CMD2_ANY_VALUE_V ("network.scgi.use_gzip.set", [](const auto&, const auto& arg) { return rpc::rpc.set_scgi_allow_compression(arg); });
|
||||
CMD2_ANY ("network.scgi.gzip.min_size", [](const auto&, const auto&) { return rpc::rpc.scgi_min_compress_size(); });
|
||||
CMD2_ANY_VALUE_V ("network.scgi.gzip.min_size.set", [](const auto&, const auto& arg) { return rpc::rpc.set_scgi_min_compress_size(arg); });
|
||||
CMD_ANY_STRING ("network.scgi.open_port", [](auto, auto& arg) { return apply_scgi(arg, 1); });
|
||||
CMD_ANY_STRING ("network.scgi.open_local", [](auto, auto& arg) { return apply_scgi(arg, 2); });
|
||||
CMD_VAR_BOOL ("network.scgi.dont_route", false);
|
||||
CMD_ANY ("network.scgi.open_systemd", [](auto, auto) { return apply_scgi_systemd(); });
|
||||
|
||||
CMD2_ANY_STRING ("network.xmlrpc.dialect.set", [](const auto&, const auto& arg) { return apply_xmlrpc_dialect(arg); })
|
||||
CMD2_ANY ("network.xmlrpc.size_limit", [](const auto&, const auto&) { return rpc::rpc.size_limit(); });
|
||||
CMD2_ANY_VALUE_V ("network.xmlrpc.size_limit.set", [](const auto&, const auto& arg) { return rpc::rpc.set_size_limit(arg); });
|
||||
CMD_ANY ("network.scgi.use_gzip", [](auto, auto) { return rpc::rpc.scgi_allow_compression(); });
|
||||
CMD_ANY_VALUE_V ("network.scgi.use_gzip.set", [](auto, auto& arg) { return rpc::rpc.set_scgi_allow_compression(arg); });
|
||||
CMD_ANY ("network.scgi.gzip.min_size", [](auto, auto) { return rpc::rpc.scgi_min_compress_size(); });
|
||||
CMD_ANY_VALUE_V ("network.scgi.gzip.min_size.set", [](auto, auto& arg) { return rpc::rpc.set_scgi_min_compress_size(arg); });
|
||||
|
||||
CMD2_VAR_BOOL ("network.rpc.use_xmlrpc", true);
|
||||
CMD2_VAR_BOOL ("network.rpc.use_jsonrpc", true);
|
||||
CMD_ANY_STRING ("network.xmlrpc.dialect.set", [](auto, auto& arg) { return apply_xmlrpc_dialect(arg); })
|
||||
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); });
|
||||
|
||||
CMD2_ANY ("network.block.ipv4", [nw_config](auto, auto) { return nw_config->is_block_ipv4(); });
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4(value); });
|
||||
CMD2_ANY ("network.block.ipv6", [nw_config](auto, auto) { return nw_config->is_block_ipv6(); });
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv6(value); });
|
||||
CMD2_ANY ("network.block.ipv4in6", [nw_config](auto, auto) { return nw_config->is_block_ipv4in6(); });
|
||||
CMD2_ANY_VALUE_V ("network.block.ipv4in6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4in6(value); });
|
||||
CMD2_ANY ("network.block.outgoing", [nw_config](auto, auto) { return nw_config->is_block_outgoing(); });
|
||||
CMD2_ANY_VALUE_V ("network.block.outgoing.set", [nw_config](auto, auto& value) { return nw_config->set_block_outgoing(value); });
|
||||
CMD2_ANY ("network.prefer.ipv6", [nw_config](auto, auto) { return nw_config->is_prefer_ipv6(); });
|
||||
CMD2_ANY_VALUE_V ("network.prefer.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_prefer_ipv6(value); });
|
||||
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); });
|
||||
CMD_ANY ("network.block.ipv6", [nw_config](auto, auto) { return nw_config->is_block_ipv6(); });
|
||||
CMD_ANY_VALUE_V ("network.block.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv6(value); });
|
||||
CMD_ANY ("network.block.ipv4in6", [nw_config](auto, auto) { return nw_config->is_block_ipv4in6(); });
|
||||
CMD_ANY_VALUE_V ("network.block.ipv4in6.set", [nw_config](auto, auto& value) { return nw_config->set_block_ipv4in6(value); });
|
||||
CMD_ANY ("network.block.outgoing", [nw_config](auto, auto) { return nw_config->is_block_outgoing(); });
|
||||
CMD_ANY_VALUE_V ("network.block.outgoing.set", [nw_config](auto, auto& value) { return nw_config->set_block_outgoing(value); });
|
||||
CMD_ANY ("network.prefer.ipv6", [nw_config](auto, auto) { return nw_config->is_prefer_ipv6(); });
|
||||
CMD_ANY_VALUE_V ("network.prefer.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_prefer_ipv6(value); });
|
||||
|
||||
rpc::rpc.mark_safe("network.port_open");
|
||||
rpc::rpc.mark_safe("network.port_random");
|
||||
@@ -329,10 +312,9 @@ initialize_command_network() {
|
||||
rpc::rpc.mark_safe("network.http.max_host_connections");
|
||||
rpc::rpc.mark_safe("network.http.max_total_connections");
|
||||
|
||||
rpc::rpc.mark_safe("network.total_handshakes");
|
||||
rpc::rpc.mark_safe("network.open_files");
|
||||
rpc::rpc.mark_safe("network.max_open_files");
|
||||
rpc::rpc.mark_safe("network.max_open_sockets");
|
||||
rpc::rpc.mark_safe("network.total_handshakes");
|
||||
|
||||
rpc::rpc.mark_safe("network.send_buffer.size");
|
||||
rpc::rpc.mark_safe("network.receive_buffer.size");
|
||||
@@ -340,11 +322,13 @@ initialize_command_network() {
|
||||
rpc::rpc.mark_safe("network.local_address");
|
||||
rpc::rpc.mark_safe("network.xmlrpc.size_limit");
|
||||
rpc::rpc.mark_safe("network.open_sockets");
|
||||
|
||||
rpc::rpc.mark_safe("network.http.cacert");
|
||||
rpc::rpc.mark_safe("network.http.capath");
|
||||
rpc::rpc.mark_safe("network.http.proxy_address");
|
||||
rpc::rpc.mark_safe("network.proxy_address");
|
||||
rpc::rpc.mark_safe("network.proxy.global");
|
||||
rpc::rpc.mark_safe("network.proxy.http");
|
||||
rpc::rpc.mark_safe("network.scgi.dont_route");
|
||||
|
||||
rpc::rpc.mark_safe("protocol.pex");
|
||||
|
||||
rpc::rpc.mark_safe("network.rpc.use_xmlrpc");
|
||||
|
||||
@@ -142,7 +142,7 @@ initialize_command_tracker() {
|
||||
lt_log_print(torrent::LOG_DHT_ERROR, "dht.port.set is no longer supported, use dht.override_port.set", 0);
|
||||
});
|
||||
CMD2_ANY ("dht.override_port", [](auto, auto) { return torrent::runtime::network_config()->override_dht_port(); });
|
||||
CMD2_ANY_VALUE_V ("dht.override_port.set", [](auto, auto& value) { return torrent::runtime::network_config()->set_override_dht_port(value); });
|
||||
CMD2_ANY_VALUE_V ("dht.override_port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_dht_port(value); });
|
||||
|
||||
CMD2_ANY_STRING ("dht.add_node", [](auto, auto& str) { return apply_dht_add_node(str); });
|
||||
CMD2_ANY ("dht.statistics", [](auto, auto) { return control->dht_manager()->dht_statistics(); });
|
||||
|
||||
+30
-23
@@ -472,11 +472,14 @@ apply_to_throttle(const torrent::Object& rawArgs) {
|
||||
// if (cond1) { branch1 } else if (cond2) { branch2 } else { branch3 }
|
||||
// <cond1>,<branch1>,<cond2>,<branch2>,<branch3>
|
||||
torrent::Object
|
||||
apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) {
|
||||
const torrent::Object::list_type& args = rawArgs.as_list();
|
||||
torrent::Object::list_const_iterator itr = args.begin();
|
||||
apply_if(rpc::target_type target, const torrent::Object& raw_args, int flags) {
|
||||
auto& args = raw_args.as_list();
|
||||
auto itr = args.begin();
|
||||
|
||||
while (itr != args.end() && itr != --args.end()) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Empty argument list to " + std::string((flags & 0x1) ? "branch" : "if") + ".");
|
||||
|
||||
{
|
||||
torrent::Object tmp;
|
||||
const torrent::Object* conditional;
|
||||
|
||||
@@ -500,40 +503,44 @@ apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) {
|
||||
result = false;
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Type not supported by 'if'.");
|
||||
throw torrent::input_error("Type not supported by " + std::string((flags & 0x1) ? "branch" : "if") + ".");
|
||||
};
|
||||
|
||||
itr++;
|
||||
|
||||
if (result)
|
||||
break;
|
||||
|
||||
itr++;
|
||||
if (!result && itr != args.end())
|
||||
itr++;
|
||||
}
|
||||
|
||||
if (itr == args.end())
|
||||
return torrent::Object();
|
||||
|
||||
if (flags & 0x1 && itr->is_string()) {
|
||||
return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first;
|
||||
if (flags & 0x1) {
|
||||
if (itr->is_string())
|
||||
return rpc::parse_command(target, itr->as_string().c_str(), itr->as_string().c_str() + itr->as_string().size()).first;
|
||||
|
||||
} else if (flags & 0x1 && itr->is_dict_key()) {
|
||||
return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target);
|
||||
if (itr->is_dict_key())
|
||||
return rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target);
|
||||
|
||||
} else if (flags & 0x1 && itr->is_list()) {
|
||||
// Move this into a special function or something. Also, might be
|
||||
// nice to have a parse_command function that takes list
|
||||
// iterator...
|
||||
if (itr->is_list()) {
|
||||
for (const auto& cmd_itr : itr->as_list()) {
|
||||
if (cmd_itr.is_string())
|
||||
rpc::parse_command(target, cmd_itr.as_string().c_str(), cmd_itr.as_string().c_str() + cmd_itr.as_string().size());
|
||||
|
||||
for (const auto& cmdItr : itr->as_list())
|
||||
if (cmdItr.is_string())
|
||||
rpc::parse_command(target, cmdItr.as_string().c_str(), cmdItr.as_string().c_str() + cmdItr.as_string().size());
|
||||
else if (cmd_itr.is_dict_key())
|
||||
rpc::commands.call_command(cmd_itr.as_dict_key().c_str(), cmd_itr.as_dict_obj(), target);
|
||||
|
||||
return torrent::Object();
|
||||
else
|
||||
throw torrent::input_error("Invalid command type in branch list.");
|
||||
}
|
||||
|
||||
} else {
|
||||
return *itr;
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
throw torrent::input_error("Invalid command type in branch.");
|
||||
}
|
||||
|
||||
return *itr;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
|
||||
+28
-10
@@ -6,6 +6,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/utils/directory_events.h>
|
||||
|
||||
#include "core/dht_manager.h"
|
||||
@@ -46,7 +47,8 @@ Control::Control()
|
||||
|
||||
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input.get(), std::placeholders::_1));
|
||||
|
||||
m_task_shutdown.slot() = std::bind(&Control::handle_shutdown, this);
|
||||
m_task_shutdown.slot() = [this] { handle_shutdown(); };
|
||||
m_task_shutdown_clear_requests.slot() = [this] { handle_shutdown_clear_requests(); };
|
||||
|
||||
m_commandScheduler->set_slot_error_message([this](const std::string& msg) { m_core->push_log_std(msg); });
|
||||
}
|
||||
@@ -68,15 +70,12 @@ Control::initialize() {
|
||||
display::Window::slot_unschedule([this](display::Window* w) { m_display->unschedule(w); });
|
||||
display::Window::slot_adjust([this]() { m_display->adjust_layout(); });
|
||||
|
||||
torrent::net_thread::http_stack()->set_user_agent(USER_AGENT);
|
||||
|
||||
m_core->listen_open();
|
||||
m_core->set_hashing_view(*m_view_manager->find_throw("hashing"));
|
||||
|
||||
m_ui->init(this);
|
||||
|
||||
if(!display::Canvas::daemon())
|
||||
m_inputStdin->insert(torrent::this_thread::poll());
|
||||
m_inputStdin->insert();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -84,9 +83,12 @@ Control::cleanup() {
|
||||
rpc::rpc.cleanup();
|
||||
|
||||
torrent::this_thread::scheduler()->erase(&m_task_shutdown);
|
||||
torrent::this_thread::scheduler()->erase(&m_task_shutdown_clear_requests);
|
||||
|
||||
if(!display::Canvas::daemon())
|
||||
m_inputStdin->remove(torrent::this_thread::poll());
|
||||
m_inputStdin->remove();
|
||||
|
||||
m_directory_events->close();
|
||||
|
||||
if (scgi_thread::thread()->is_active())
|
||||
scgi_thread::thread()->stop_thread_wait();
|
||||
@@ -111,7 +113,7 @@ Control::cleanup_exception() {
|
||||
|
||||
bool
|
||||
Control::is_shutdown_completed() {
|
||||
if (!m_shutdownQuick)
|
||||
if (!m_shutdown_quick)
|
||||
return false;
|
||||
|
||||
// Tracker requests can be disowned, so wait for these to
|
||||
@@ -135,8 +137,9 @@ Control::handle_shutdown() {
|
||||
if (scgi_thread::thread()->is_active())
|
||||
scgi_thread::thread()->stop_thread_wait();
|
||||
|
||||
if (!m_shutdownQuick) {
|
||||
if (!m_shutdown_quick) {
|
||||
torrent::runtime::network_manager()->listen_close();
|
||||
torrent::runtime::shutdown();
|
||||
|
||||
m_directory_events->close();
|
||||
m_core->shutdown(false);
|
||||
@@ -145,9 +148,24 @@ Control::handle_shutdown() {
|
||||
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown, 5s);
|
||||
|
||||
} else {
|
||||
torrent::runtime::quick_shutdown();
|
||||
m_core->shutdown(true);
|
||||
}
|
||||
|
||||
m_shutdownQuick = true;
|
||||
m_shutdownReceived = false;
|
||||
if (!m_task_shutdown_clear_requests.is_scheduled())
|
||||
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown_clear_requests, 10s);
|
||||
|
||||
m_shutdown_quick = true;
|
||||
m_shutdown_received = false;
|
||||
}
|
||||
|
||||
void
|
||||
Control::handle_shutdown_clear_requests() {
|
||||
torrent::net_thread::http_stack()->clear_requests();
|
||||
|
||||
// Use 5s for the initial wait to ensure trackers get a chance to finish both IPv4 and IPv6 requests.
|
||||
if (m_clear_requests_count++ == 0)
|
||||
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 5s);
|
||||
else
|
||||
torrent::this_thread::scheduler()->wait_for(&m_task_shutdown_clear_requests, 1s);
|
||||
}
|
||||
|
||||
+12
-6
@@ -48,17 +48,18 @@ public:
|
||||
~Control();
|
||||
|
||||
bool is_shutdown_completed();
|
||||
bool is_shutdown_received() { return m_shutdownReceived; }
|
||||
bool is_shutdown_started() { return m_shutdownQuick; }
|
||||
bool is_shutdown_received() { return m_shutdown_received; }
|
||||
bool is_shutdown_started() { return m_shutdown_quick; }
|
||||
|
||||
void initialize();
|
||||
void cleanup();
|
||||
void cleanup_exception();
|
||||
|
||||
void handle_shutdown();
|
||||
void handle_shutdown_clear_requests();
|
||||
|
||||
void receive_normal_shutdown() { m_shutdownReceived = true; }
|
||||
void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; }
|
||||
void receive_normal_shutdown() { m_shutdown_received = true; }
|
||||
void receive_quick_shutdown() { m_shutdown_received = true; m_shutdown_quick = true; }
|
||||
|
||||
core::Manager* core() { return m_core.get(); }
|
||||
core::ViewManager* view_manager() { return m_view_manager.get(); }
|
||||
@@ -107,9 +108,14 @@ private:
|
||||
std::string m_workingDirectory;
|
||||
|
||||
torrent::utils::SchedulerEntry m_task_shutdown;
|
||||
torrent::utils::SchedulerEntry m_task_shutdown_clear_requests;
|
||||
|
||||
std::atomic<bool> m_shutdownReceived{};
|
||||
std::atomic<bool> m_shutdownQuick{};
|
||||
int m_clear_requests_count{};
|
||||
|
||||
align_cacheline
|
||||
|
||||
std::atomic<bool> m_shutdown_received{};
|
||||
std::atomic<bool> m_shutdown_quick{};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+21
-7
@@ -8,6 +8,7 @@
|
||||
#include <torrent/object_stream.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/runtime/network_manager.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/tracker/dht_controller.h>
|
||||
#include <torrent/utils/log.h>
|
||||
|
||||
@@ -141,18 +142,29 @@ DhtManager::save_dht_cache() {
|
||||
|
||||
void
|
||||
DhtManager::set_mode_by_user(const std::string& arg) {
|
||||
for (int i = 0; i < dht_settings_num; i++) {
|
||||
if (arg == dht_settings[i]) {
|
||||
m_set_by_user = true;
|
||||
return set_mode_directly(i);
|
||||
}
|
||||
unsigned int mode = [arg]() {
|
||||
for (int i = 0; i < dht_settings_num; i++) {
|
||||
if (arg == dht_settings[i])
|
||||
return i;
|
||||
}
|
||||
|
||||
throw torrent::input_error("Invalid dht mode: " + arg);
|
||||
}();
|
||||
|
||||
m_set_by_user = true;
|
||||
|
||||
if (!torrent::runtime::is_network_initialized()) {
|
||||
m_start = mode;
|
||||
return;
|
||||
}
|
||||
|
||||
set_mode_directly(mode);
|
||||
}
|
||||
|
||||
void
|
||||
DhtManager::set_mode_directly(unsigned int mode) {
|
||||
if (mode >= dht_settings_num)
|
||||
throw torrent::input_error("Invalid argument.");
|
||||
throw torrent::input_error("Invalid dht mode.");
|
||||
|
||||
m_start = mode;
|
||||
|
||||
@@ -164,8 +176,10 @@ DhtManager::set_mode_directly(unsigned int mode) {
|
||||
|
||||
void
|
||||
DhtManager::set_auto_if_untouched_and_has_session() {
|
||||
if (m_set_by_user)
|
||||
if (m_set_by_user) {
|
||||
set_mode_directly(m_start);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rpc::call_command_string("session.path").empty()) {
|
||||
LT_LOG("DHT auto-start disabled, session path not set.", 0);
|
||||
|
||||
@@ -104,40 +104,42 @@ DownloadFactory::receive_load() {
|
||||
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
|
||||
|
||||
if (is_network_uri(m_uri)) {
|
||||
// Http handling here.
|
||||
m_stream.reset(new std::stringstream);
|
||||
|
||||
HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream);
|
||||
auto done_fn = [this]() { receive_loaded(); };
|
||||
auto failed_fn = [this](const std::string& error) { receive_failed(error); };
|
||||
|
||||
itr->add_done_slot(torrent::this_thread::thread(), [this]() { receive_loaded(); });
|
||||
itr->add_failed_slot(torrent::this_thread::thread(), [this](const std::string& error) { receive_failed(error); });
|
||||
m_manager->http_queue()->insert(m_uri, m_stream, done_fn, failed_fn);
|
||||
|
||||
m_variables["tied_to_file"] = (int64_t)false;
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (is_magnet_uri(m_uri)) {
|
||||
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;
|
||||
receive_loaded();
|
||||
|
||||
} else {
|
||||
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 = new torrent::Object;
|
||||
stream >> *m_object;
|
||||
|
||||
if (!stream.good())
|
||||
return receive_failed("Reading torrent file failed");
|
||||
|
||||
m_isFile = true;
|
||||
|
||||
receive_loaded();
|
||||
return;
|
||||
}
|
||||
|
||||
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 = new torrent::Object;
|
||||
stream >> *m_object;
|
||||
|
||||
if (!stream.good())
|
||||
return receive_failed("Reading torrent file failed");
|
||||
|
||||
m_isFile = true;
|
||||
|
||||
receive_loaded();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -9,17 +9,21 @@
|
||||
namespace core {
|
||||
|
||||
HttpQueue::iterator
|
||||
HttpQueue::insert(const std::string& url, std::shared_ptr<std::ostream> stream) {
|
||||
HttpQueue::insert(const std::string& url, std::shared_ptr<std::ostream> stream,
|
||||
std::function<void()> done_fn, std::function<void(const std::string&)> failed_fn) {
|
||||
auto itr = base_type::insert(end(), torrent::net::HttpGet(url, stream));
|
||||
|
||||
itr->set_max_file_size(15 << 20);
|
||||
itr->set_redirect_only_http_https();
|
||||
|
||||
for (auto& slot : m_signal_insert)
|
||||
slot(*itr);
|
||||
|
||||
itr->add_done_slot(torrent::this_thread::thread(), [this, itr]() { erase(itr); });
|
||||
itr->add_failed_slot(torrent::this_thread::thread(), [this, itr](auto) { erase(itr); });
|
||||
itr->add_done_slot(torrent::this_thread::thread(), std::move(done_fn));
|
||||
itr->add_done_slot(torrent::this_thread::thread(), [this, itr]() { erase(itr); });
|
||||
|
||||
// TODO: Downloading http torrents doesn't seem to work.
|
||||
// TODO: Quitting no longer works.
|
||||
itr->add_failed_slot(torrent::this_thread::thread(), std::move(failed_fn));
|
||||
itr->add_failed_slot(torrent::this_thread::thread(), [this, itr](auto) { erase(itr); });
|
||||
|
||||
torrent::net_thread::http_stack()->start_get(*itr);
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@ public:
|
||||
//
|
||||
// Consider adding a flag to indicate whetever HttpQueue should
|
||||
// delete the stream.
|
||||
iterator insert(const std::string& url, std::shared_ptr<std::ostream> stream);
|
||||
iterator insert(const std::string& url, std::shared_ptr<std::ostream> stream,
|
||||
std::function<void()> done_fn, std::function<void(const std::string&)> failed_fn);
|
||||
void erase(iterator itr);
|
||||
|
||||
void clear();
|
||||
|
||||
+9
-71
@@ -8,7 +8,7 @@
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <rak/regex.h>
|
||||
#include <fnmatch.h>
|
||||
#include <torrent/utils/resume.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/exceptions.h>
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "core/http_queue.h"
|
||||
#include "core/view.h"
|
||||
|
||||
#include <torrent/runtime/client_config.h>
|
||||
|
||||
namespace core {
|
||||
|
||||
const int Manager::create_start;
|
||||
@@ -151,76 +153,12 @@ Manager::cleanup() {
|
||||
|
||||
void
|
||||
Manager::shutdown(bool force) {
|
||||
if (!force)
|
||||
if (!force) {
|
||||
for (auto d : *m_download_list)
|
||||
m_download_list->pause_default(d);
|
||||
else
|
||||
} else {
|
||||
for (auto d : *m_download_list)
|
||||
m_download_list->close_quick(d);
|
||||
}
|
||||
|
||||
void
|
||||
Manager::listen_open() {
|
||||
// This stuff really should be moved outside of manager, make it
|
||||
// part of the init script.
|
||||
if (!rpc::call_command_value("network.port_open"))
|
||||
return;
|
||||
|
||||
int portFirst, portLast;
|
||||
torrent::Object portRange = rpc::call_command("network.port_range");
|
||||
|
||||
if (!portRange.is_string())
|
||||
throw torrent::input_error("Invalid port_range argument type.");
|
||||
|
||||
if (std::sscanf(portRange.as_string().c_str(), "%i-%i", &portFirst, &portLast) != 2)
|
||||
throw torrent::input_error("Invalid port_range argument.");
|
||||
|
||||
if (portFirst > portLast || portLast >= (1 << 16))
|
||||
throw torrent::input_error("Invalid port range.");
|
||||
|
||||
if (rpc::call_command_value("network.port_random")) {
|
||||
int boundary = portFirst + random() % (portLast - portFirst + 1);
|
||||
|
||||
if (torrent::runtime::network_manager()->listen_open(boundary, portLast) ||
|
||||
torrent::runtime::network_manager()->listen_open(portFirst, boundary))
|
||||
return;
|
||||
|
||||
} else {
|
||||
if (torrent::runtime::network_manager()->listen_open(portFirst, portLast))
|
||||
return;
|
||||
}
|
||||
|
||||
throw torrent::input_error("Could not open/bind port for listening: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
void
|
||||
Manager::set_proxy_address(const std::string& addr) {
|
||||
int port;
|
||||
torrent::sa_unique_ptr sa;
|
||||
|
||||
std::string buf(addr.length() + 1, '\0');
|
||||
|
||||
int err = std::sscanf(addr.c_str(), "%[^:]:%i", buf.data(), &port);
|
||||
|
||||
if (err <= 0)
|
||||
throw torrent::input_error("Could not parse proxy address.");
|
||||
|
||||
if (err == 1)
|
||||
port = 80;
|
||||
|
||||
try {
|
||||
sa = torrent::sa_copy(torrent::sa_lookup_address(buf, AF_INET).get());
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
throw torrent::input_error("Could not resolve proxy address: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
try {
|
||||
torrent::sa_set_port(sa.get(), port);
|
||||
torrent::runtime::network_config()->set_proxy_address(sa.get());
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,9 +330,9 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
// Might be an idea to use depth-first search instead.
|
||||
|
||||
for (; first != last; ++first) {
|
||||
rak::regex r(*first);
|
||||
const std::string& pattern = *first;
|
||||
|
||||
if (r.pattern().empty())
|
||||
if (pattern.empty())
|
||||
continue;
|
||||
|
||||
// Special case for ".."?
|
||||
@@ -402,8 +340,8 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
|
||||
for (auto& itr : currentCache) {
|
||||
// Only include filenames starting with '.' if the pattern
|
||||
// starts with the same.
|
||||
itr.update((r.pattern()[0] != '.') ? utils::Directory::update_hide_dot : 0);
|
||||
itr.erase(std::remove_if(itr.begin(), itr.end(), [r](const utils::directory_entry& entry) { return !r(entry.s_name); }), itr.end());
|
||||
itr.update((pattern[0] != '.') ? utils::Directory::update_hide_dot : 0);
|
||||
itr.erase(std::remove_if(itr.begin(), itr.end(), [&pattern](const utils::directory_entry& entry) { return fnmatch(pattern.c_str(), entry.s_name.c_str(), 0) != 0; }), itr.end());
|
||||
|
||||
for (const auto& cache : itr)
|
||||
nextCache.push_back(path_expand_transform(itr.path() + (itr.path() == "/" ? "" : "/"), cache));
|
||||
|
||||
@@ -55,10 +55,6 @@ public:
|
||||
|
||||
void cleanup();
|
||||
|
||||
void listen_open();
|
||||
|
||||
void set_proxy_address(const std::string& addr);
|
||||
|
||||
const std::string& magnet_path();
|
||||
void set_magnet_path(const std::string& path);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,20 +2,26 @@
|
||||
|
||||
#include "input_event.h"
|
||||
|
||||
#include <torrent/common.h>
|
||||
#include <torrent/system/poll.h>
|
||||
|
||||
#include "display/attributes.h"
|
||||
|
||||
namespace input {
|
||||
|
||||
void
|
||||
InputEvent::insert(torrent::system::Poll* p) {
|
||||
p->open(this);
|
||||
p->insert_read(this);
|
||||
InputEvent::insert() {
|
||||
torrent::this_thread::poll()->open(this);
|
||||
torrent::this_thread::poll()->insert_read(this);
|
||||
}
|
||||
|
||||
void
|
||||
InputEvent::remove(torrent::system::Poll* p) {
|
||||
p->remove_read(this);
|
||||
p->close(this);
|
||||
InputEvent::remove() {
|
||||
if (!is_open())
|
||||
return;
|
||||
|
||||
torrent::this_thread::poll()->remove_and_close(this);
|
||||
set_file_descriptor(-1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -32,6 +38,8 @@ InputEvent::event_write() {
|
||||
|
||||
void
|
||||
InputEvent::event_error() {
|
||||
torrent::this_thread::poll()->remove_and_close(this);
|
||||
set_file_descriptor(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <functional>
|
||||
|
||||
#include <torrent/event.h>
|
||||
#include <torrent/system/poll.h>
|
||||
|
||||
namespace input {
|
||||
|
||||
@@ -12,12 +11,12 @@ class InputEvent : public torrent::Event {
|
||||
public:
|
||||
typedef std::function<void (int)> slot_int;
|
||||
|
||||
InputEvent(int fd) { m_fileDesc = fd; }
|
||||
InputEvent(int fd) { set_file_descriptor(fd); }
|
||||
|
||||
const char* type_name() const override { return "input"; }
|
||||
|
||||
void insert(torrent::system::Poll* p);
|
||||
void remove(torrent::system::Poll* p);
|
||||
void insert();
|
||||
void remove();
|
||||
|
||||
void event_read() override;
|
||||
void event_write() override;
|
||||
|
||||
+108
-63
@@ -11,6 +11,9 @@
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/data/chunk_utils.h>
|
||||
#include <torrent/net/fd.h>
|
||||
#include <torrent/net/http_stack.h>
|
||||
#include <torrent/runtime/memory_manager.h>
|
||||
#include <torrent/runtime/runtime.h>
|
||||
#include <torrent/utils/chrono.h>
|
||||
#include <torrent/utils/log.h>
|
||||
|
||||
@@ -112,8 +115,16 @@ main(int argc, char** argv) {
|
||||
// TODO: Create a fake thread object for initializing other processes and enabling logging.
|
||||
torrent::initialize_main_thread();
|
||||
|
||||
// Block SIGCHLD until all threads are created, then unblock on main-thread, to avoid SIGCHLD
|
||||
// interrupting other threads.
|
||||
//
|
||||
// This means only main-thread can fork and wait for child processes.
|
||||
|
||||
SignalHandler::set_block(SIGALRM);
|
||||
SignalHandler::set_block(SIGPIPE);
|
||||
SignalHandler::set_block(SIGCHLD);
|
||||
|
||||
// All signal handlers must restore errno if they return.
|
||||
SignalHandler::set_ignore(SIGPIPE);
|
||||
SignalHandler::set_handler(SIGSEGV, std::bind(&do_panic, SIGSEGV));
|
||||
SignalHandler::set_handler(SIGILL, std::bind(&do_panic, SIGILL));
|
||||
SignalHandler::set_handler(SIGFPE, std::bind(&do_panic, SIGFPE));
|
||||
@@ -141,8 +152,8 @@ main(int argc, char** argv) {
|
||||
|
||||
SignalHandler::set_sigaction_handler(SIGBUS, &handle_sigbus);
|
||||
|
||||
torrent::log_add_group_output(torrent::LOG_NOTICE, "important");
|
||||
torrent::log_add_group_output(torrent::LOG_DHT_ERROR, "important");
|
||||
torrent::log_add_group_output(torrent::LOG_NOTICE, "important");
|
||||
torrent::log_add_group_output(torrent::LOG_DHT_ERROR, "important");
|
||||
|
||||
torrent::log_add_group_output(torrent::LOG_INFO, "complete");
|
||||
torrent::log_add_group_output(torrent::LOG_DHT_ERROR, "complete");
|
||||
@@ -156,6 +167,8 @@ main(int argc, char** argv) {
|
||||
scgi::ThreadScgi::create_thread();
|
||||
session::ThreadSession::create_thread();
|
||||
|
||||
SignalHandler::set_unblock(SIGCHLD);
|
||||
|
||||
// Initialize option handlers after libtorrent to ensure
|
||||
// torrent::ConnectionManager* are valid etc.
|
||||
initialize_commands();
|
||||
@@ -288,7 +301,8 @@ 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.set=allow_incoming,prefer_plaintext,enable_retry\n"
|
||||
"protocol.encryption.handshake.set=allow\n"
|
||||
"protocol.encryption.stream.set=allow\n"
|
||||
|
||||
"ui.color.focus.set=reverse\n"
|
||||
);
|
||||
@@ -296,56 +310,74 @@ main(int argc, char** argv) {
|
||||
// Functions that might not get depracted as they are nice for
|
||||
// configuration files, and thus might do with just some
|
||||
// cleanup.
|
||||
CMD2_REDIRECT("upload_rate", "throttle.global_up.max_rate.set_kb");
|
||||
CMD2_REDIRECT("download_rate", "throttle.global_down.max_rate.set_kb");
|
||||
CMD_REDIRECT("upload_rate", "throttle.global_up.max_rate.set_kb");
|
||||
CMD_REDIRECT("download_rate", "throttle.global_down.max_rate.set_kb");
|
||||
|
||||
CMD2_REDIRECT("ratio.enable", "group.seeding.ratio.enable");
|
||||
CMD2_REDIRECT("ratio.disable", "group.seeding.ratio.disable");
|
||||
CMD2_REDIRECT("ratio.min", "group.seeding.ratio.min");
|
||||
CMD2_REDIRECT("ratio.max", "group.seeding.ratio.max");
|
||||
CMD2_REDIRECT("ratio.upload", "group.seeding.ratio.upload");
|
||||
CMD2_REDIRECT("ratio.min.set", "group.seeding.ratio.min.set");
|
||||
CMD2_REDIRECT("ratio.max.set", "group.seeding.ratio.max.set");
|
||||
CMD2_REDIRECT("ratio.upload.set", "group.seeding.ratio.upload.set");
|
||||
CMD_REDIRECT("ratio.enable", "group.seeding.ratio.enable");
|
||||
CMD_REDIRECT("ratio.disable", "group.seeding.ratio.disable");
|
||||
CMD_REDIRECT("ratio.min", "group.seeding.ratio.min");
|
||||
CMD_REDIRECT("ratio.max", "group.seeding.ratio.max");
|
||||
CMD_REDIRECT("ratio.upload", "group.seeding.ratio.upload");
|
||||
CMD_REDIRECT("ratio.min.set", "group.seeding.ratio.min.set");
|
||||
CMD_REDIRECT("ratio.max.set", "group.seeding.ratio.max.set");
|
||||
CMD_REDIRECT("ratio.upload.set", "group.seeding.ratio.upload.set");
|
||||
|
||||
CMD2_REDIRECT("encryption", "protocol.encryption.set");
|
||||
CMD_REDIRECT("check_hash", "pieces.hash.on_completion.set");
|
||||
|
||||
CMD2_REDIRECT("check_hash", "pieces.hash.on_completion.set");
|
||||
CMD_REDIRECT("connection_leech", "protocol.connection.leech.set");
|
||||
CMD_REDIRECT("connection_seed", "protocol.connection.seed.set");
|
||||
|
||||
CMD2_REDIRECT("connection_leech", "protocol.connection.leech.set");
|
||||
CMD2_REDIRECT("connection_seed", "protocol.connection.seed.set");
|
||||
CMD_REDIRECT("min_peers", "throttle.min_peers.normal.set");
|
||||
CMD_REDIRECT("max_peers", "throttle.max_peers.normal.set");
|
||||
CMD_REDIRECT("min_peers_seed", "throttle.min_peers.seed.set");
|
||||
CMD_REDIRECT("max_peers_seed", "throttle.max_peers.seed.set");
|
||||
|
||||
CMD2_REDIRECT("min_peers", "throttle.min_peers.normal.set");
|
||||
CMD2_REDIRECT("max_peers", "throttle.max_peers.normal.set");
|
||||
CMD2_REDIRECT("min_peers_seed", "throttle.min_peers.seed.set");
|
||||
CMD2_REDIRECT("max_peers_seed", "throttle.max_peers.seed.set");
|
||||
CMD_REDIRECT("min_uploads", "throttle.min_uploads.set");
|
||||
CMD_REDIRECT("max_uploads", "throttle.max_uploads.set");
|
||||
CMD_REDIRECT("min_downloads", "throttle.min_downloads.set");
|
||||
CMD_REDIRECT("max_downloads", "throttle.max_downloads.set");
|
||||
|
||||
CMD2_REDIRECT("min_uploads", "throttle.min_uploads.set");
|
||||
CMD2_REDIRECT("max_uploads", "throttle.max_uploads.set");
|
||||
CMD2_REDIRECT("min_downloads", "throttle.min_downloads.set");
|
||||
CMD2_REDIRECT("max_downloads", "throttle.max_downloads.set");
|
||||
CMD_REDIRECT("max_uploads_div", "throttle.max_uploads.div.set");
|
||||
CMD_REDIRECT("max_uploads_global", "throttle.max_uploads.global.set");
|
||||
CMD_REDIRECT("max_downloads_div", "throttle.max_downloads.div.set");
|
||||
CMD_REDIRECT("max_downloads_global", "throttle.max_downloads.global.set");
|
||||
|
||||
CMD2_REDIRECT("max_uploads_div", "throttle.max_uploads.div.set");
|
||||
CMD2_REDIRECT("max_uploads_global", "throttle.max_uploads.global.set");
|
||||
CMD2_REDIRECT("max_downloads_div", "throttle.max_downloads.div.set");
|
||||
CMD2_REDIRECT("max_downloads_global", "throttle.max_downloads.global.set");
|
||||
CMD_REDIRECT("directory", "directory.default.set");
|
||||
CMD_REDIRECT("session", "session.path.set");
|
||||
|
||||
CMD2_REDIRECT("directory", "directory.default.set");
|
||||
CMD2_REDIRECT("session", "session.path.set");
|
||||
CMD_REDIRECT("scgi_port", "network.scgi.open_port");
|
||||
CMD_REDIRECT("scgi_local", "network.scgi.open_local");
|
||||
|
||||
CMD2_REDIRECT("scgi_port", "network.scgi.open_port");
|
||||
CMD2_REDIRECT("scgi_local", "network.scgi.open_local");
|
||||
CMD_REDIRECT("to_gm_time", "convert.gm_time");
|
||||
CMD_REDIRECT("to_gm_date", "convert.gm_date");
|
||||
CMD_REDIRECT("to_time", "convert.time");
|
||||
CMD_REDIRECT("to_date", "convert.date");
|
||||
CMD_REDIRECT("to_elapsed_time", "convert.elapsed_time");
|
||||
CMD_REDIRECT("to_kb", "convert.kb");
|
||||
CMD_REDIRECT("to_mb", "convert.mb");
|
||||
CMD_REDIRECT("to_xb", "convert.xb");
|
||||
CMD_REDIRECT("to_throttle", "convert.throttle");
|
||||
|
||||
CMD2_REDIRECT("to_gm_time", "convert.gm_time");
|
||||
CMD2_REDIRECT("to_gm_date", "convert.gm_date");
|
||||
CMD2_REDIRECT("to_time", "convert.time");
|
||||
CMD2_REDIRECT("to_date", "convert.date");
|
||||
CMD2_REDIRECT("to_elapsed_time", "convert.elapsed_time");
|
||||
CMD2_REDIRECT("to_kb", "convert.kb");
|
||||
CMD2_REDIRECT("to_mb", "convert.mb");
|
||||
CMD2_REDIRECT("to_xb", "convert.xb");
|
||||
CMD2_REDIRECT("to_throttle", "convert.throttle");
|
||||
// TODO: Deprecate these at some point a while after 1.1 release.
|
||||
|
||||
CMD_REDIRECT("d.multicall2", "d.multicall");
|
||||
CMD_REDIRECT("network.open_sockets", "system.sockets.size");
|
||||
CMD_REDIRECT("network.max_open_sockets", "system.sockets.max_size");
|
||||
CMD_REDIRECT("network.max_open_sockets.set", "system.sockets.max_size.set");
|
||||
CMD_REDIRECT("network.http.proxy_address", "network.proxy.http");
|
||||
CMD_REDIRECT("network.http.proxy_address.set", "network.proxy.http.set");
|
||||
|
||||
rpc::rpc.mark_safe("d.multicall2");
|
||||
rpc::rpc.mark_safe("network.max_open_sockets");
|
||||
rpc::rpc.mark_safe("network.http.proxy_address");
|
||||
|
||||
CMD2_ANY_VALUE_V("network.http.max_total_connections.set", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "network.http.max_total_connections.set is deprecated, use system.sockets.http.min_alloc.set instead.");
|
||||
});
|
||||
|
||||
CMD2_ANY_VALUE_V("network.max_open_files.set", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "network.max_open_files.set is deprecated, use system.sockets.files.min_alloc.set instead.");
|
||||
});
|
||||
|
||||
// if (rpc::call_command_value("method.use_intermediate") == 1) {
|
||||
|
||||
@@ -354,44 +386,53 @@ main(int argc, char** argv) {
|
||||
// }
|
||||
|
||||
if (rpc::call_command_value("method.use_deprecated") == 1) {
|
||||
CMD2_REDIRECT("execute2", "execute");
|
||||
CMD2_REDIRECT("schedule2", "schedule");
|
||||
CMD2_REDIRECT("schedule_remove2", "schedule.remove");
|
||||
CMD_REDIRECT("execute2", "execute");
|
||||
CMD_REDIRECT("schedule2", "schedule");
|
||||
CMD_REDIRECT("schedule_remove2", "schedule.remove");
|
||||
|
||||
// TODO: Remove file.append when cleaning these up.
|
||||
|
||||
CMD2_REDIRECT("bind", "network.bind_address.set");
|
||||
CMD2_REDIRECT("ip", "network.local_address.set");
|
||||
CMD2_REDIRECT("port_range", "network.port_range.set");
|
||||
CMD_REDIRECT("bind", "network.bind_address.set");
|
||||
CMD_REDIRECT("ip", "network.local_address.set");
|
||||
CMD_REDIRECT("port_range", "network.port_range.set");
|
||||
|
||||
// TODO: Check if dht is on by default.
|
||||
CMD2_REDIRECT("dht", "dht.mode.set");
|
||||
CMD_REDIRECT("dht", "dht.mode.set");
|
||||
|
||||
CMD2_REDIRECT("port_random", "network.port_random.set");
|
||||
CMD2_REDIRECT("proxy_address", "network.proxy_address.set");
|
||||
CMD_REDIRECT("port_random", "network.port_random.set");
|
||||
CMD_REDIRECT("proxy_address", "network.proxy_address.set");
|
||||
|
||||
CMD2_REDIRECT("key_layout", "keys.layout.set");
|
||||
CMD_REDIRECT("key_layout", "keys.layout.set");
|
||||
|
||||
CMD2_REDIRECT("torrent_list_layout", "ui.torrent_list.layout.set");
|
||||
CMD_REDIRECT("torrent_list_layout", "ui.torrent_list.layout.set");
|
||||
|
||||
CMD2_VAR_STRING("dht.throttle.name", "deprecated");
|
||||
rpc::rpc.mark_safe("dht.throttle.name");
|
||||
|
||||
CMD2_REDIRECT("network.http.max_open", "network.http.max_total_connections");
|
||||
CMD2_REDIRECT("network.http.max_open.set", "network.http.max_total_connections.set");
|
||||
CMD_REDIRECT("network.http.max_open", "network.http.max_total_connections");
|
||||
CMD_REDIRECT("network.http.max_open.set", "network.http.max_total_connections.set");
|
||||
|
||||
// Users should check their setups to see if they need to modify their use of these options.
|
||||
CMD2_REDIRECT("max_memory_usage", "pieces.memory.max.set");
|
||||
CMD2_REDIRECT("encoding_list", "encoding.add");
|
||||
CMD_REDIRECT("max_memory_usage", "pieces.memory.max.set");
|
||||
|
||||
CMD2_ANY_STRING_V("encoding.add", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "The 'encoding.add' command is deprecated and does nothing.");
|
||||
});
|
||||
|
||||
CMD2_ANY_LIST ("throttle.ip", []( auto, auto) {
|
||||
CMD_ANY_LIST("throttle.ip", []( auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "The 'throttle.ip' command is deprecated and does nothing.");
|
||||
return torrent::Object();
|
||||
});
|
||||
|
||||
CMD_ANY("network.port_open", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "The 'network.port_open' command is deprecated and does nothing.");
|
||||
return torrent::Object();
|
||||
});
|
||||
CMD_ANY("network.port_open.set", [](auto, auto) {
|
||||
lt_log_print(torrent::LOG_WARN, "The 'network.port_open.set' command is deprecated and does nothing.");
|
||||
return torrent::Object();
|
||||
});
|
||||
|
||||
CMD_REDIRECT("network.port_random", "network.listen.port.random");
|
||||
CMD_REDIRECT("network.port_random.set", "network.listen.port.random.set");
|
||||
CMD_REDIRECT("network.port_range", "network.listen.port.range");
|
||||
CMD_REDIRECT("network.port_range.set", "network.listen.port.range.set");
|
||||
}
|
||||
|
||||
{
|
||||
@@ -419,10 +460,14 @@ main(int argc, char** argv) {
|
||||
});
|
||||
|
||||
LT_LOG("seeded srandom and srand48 (seed:%u)", random_seed);
|
||||
LT_LOG("max memory usage: %" PRIu64, torrent::runtime::memory_manager()->max_memory_usage());
|
||||
|
||||
control->initialize();
|
||||
control->ui()->load_input_history();
|
||||
|
||||
torrent::net_thread::http_stack()->set_user_agent(USER_AGENT);
|
||||
torrent::runtime::initialize_network();
|
||||
|
||||
// Load session torrents and perform scheduled tasks to ensure session torrents are loaded
|
||||
// before arg torrents.
|
||||
control->dht_manager()->set_auto_if_untouched_and_has_session();
|
||||
|
||||
+31
-31
@@ -6,31 +6,31 @@
|
||||
#include "command.h"
|
||||
|
||||
#define COMMAND_BASE_TEMPLATE_DEFINE(func_name) \
|
||||
template const torrent::Object func_name<target_type>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<core::Download*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::Peer*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::tracker::Tracker*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::File*>(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::FileListIterator*>(command_base* rawCommand, target_type target, const torrent::Object& args);
|
||||
template const torrent::Object func_name<target_type>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<core::Download*>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::Peer*>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::tracker::Tracker*>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::File*>(command_base* command_raw, target_type target, const torrent::Object& args); \
|
||||
template const torrent::Object func_name<torrent::FileListIterator*>(command_base* command_raw, target_type target, const torrent::Object& args);
|
||||
|
||||
namespace rpc {
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call(command_base* rawCommand, target_type target, const torrent::Object& args) {
|
||||
command_base_call(command_base* command_raw, target_type target, const torrent::Object& args) {
|
||||
if (!is_target_compatible<T>(target))
|
||||
throw torrent::input_error("Target of wrong type to command.");
|
||||
throw torrent::input_error("Target of wrong type to generic command.");
|
||||
|
||||
return command_base::_call<typename command_function<T>::type, T>(rawCommand, target, args);
|
||||
return command_base::_call<typename command_function<T>::type, T>(command_raw, target, args);
|
||||
}
|
||||
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call);
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call_value_base(command_base* rawCommand, target_type target, const torrent::Object& rawArgs, int base, int unit) {
|
||||
command_base_call_value_base(command_base* command_raw, target_type target, const torrent::Object& args_raw, int base, int unit) {
|
||||
if (!is_target_compatible<T>(target))
|
||||
throw torrent::input_error("Target of wrong type to command.");
|
||||
throw torrent::input_error("Target of wrong type to value command.");
|
||||
|
||||
const torrent::Object& arg = convert_to_single_argument(rawArgs);
|
||||
auto& arg = convert_to_single_argument(args_raw);
|
||||
|
||||
if (arg.type() == torrent::Object::TYPE_STRING) {
|
||||
torrent::Object::value_type val;
|
||||
@@ -38,55 +38,55 @@ command_base_call_value_base(command_base* rawCommand, target_type target, const
|
||||
if (!parse_whole_value_nothrow(arg.as_string().c_str(), &val, base, unit))
|
||||
throw torrent::input_error("Not a value.");
|
||||
|
||||
return command_base::_call<typename command_value_function<T>::type, T>(rawCommand, target, val);
|
||||
return command_base::_call<typename command_value_function<T>::type, T>(command_raw, target, val);
|
||||
}
|
||||
|
||||
return command_base::_call<typename command_value_function<T>::type, T>(rawCommand, target, unit * arg.as_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
|
||||
command_base_call_value(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) {
|
||||
return command_base_call_value_base<T>(rawCommand, target, rawArgs, 0, 1);
|
||||
command_base_call_value(command_base* command_raw, target_type target, const torrent::Object& args_raw) {
|
||||
return command_base_call_value_base<T>(command_raw, target, args_raw, 0, 1);
|
||||
}
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call_value_kb(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) {
|
||||
return command_base_call_value_base<T>(rawCommand, target, rawArgs, 0, 1024);
|
||||
command_base_call_value_kb(command_base* command_raw, target_type target, const torrent::Object& args_raw) {
|
||||
return command_base_call_value_base<T>(command_raw, target, args_raw, 0, 1024);
|
||||
}
|
||||
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value);
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_value_kb);
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call_string(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) {
|
||||
command_base_call_string(command_base* command_raw, target_type target, const torrent::Object& args_raw) {
|
||||
if (!is_target_compatible<T>(target))
|
||||
throw torrent::input_error("Target of wrong type to command.");
|
||||
throw torrent::input_error("Target of wrong type to string command.");
|
||||
|
||||
const torrent::Object& arg = convert_to_single_argument(rawArgs);
|
||||
auto& arg = convert_to_single_argument(args_raw);
|
||||
|
||||
if (arg.type() == torrent::Object::TYPE_RAW_STRING)
|
||||
return command_base::_call<typename command_string_function<T>::type, T>(rawCommand, target, arg.as_raw_string().as_string());
|
||||
return command_base::_call<typename command_string_function<T>::type, T>(command_raw, target, arg.as_raw_string().as_string());
|
||||
|
||||
return command_base::_call<typename command_string_function<T>::type, T>(rawCommand, target, arg.as_string());
|
||||
return command_base::_call<typename command_string_function<T>::type, T>(command_raw, target, arg.as_string());
|
||||
}
|
||||
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_string);
|
||||
|
||||
template <typename T> const torrent::Object
|
||||
command_base_call_list(command_base* rawCommand, target_type target, const torrent::Object& rawArgs) {
|
||||
command_base_call_list(command_base* command_raw, target_type target, const torrent::Object& args_raw) {
|
||||
if (!is_target_compatible<T>(target))
|
||||
throw torrent::input_error("Target of wrong type to command.");
|
||||
throw torrent::input_error("Target of wrong type to list command.");
|
||||
|
||||
if (rawArgs.type() != torrent::Object::TYPE_LIST) {
|
||||
if (args_raw.type() != torrent::Object::TYPE_LIST) {
|
||||
torrent::Object::list_type arg;
|
||||
|
||||
if (!rawArgs.is_empty())
|
||||
arg.push_back(rawArgs);
|
||||
|
||||
return command_base::_call<typename command_list_function<T>::type, T>(rawCommand, target, arg);
|
||||
if (!args_raw.is_empty())
|
||||
arg.push_back(args_raw);
|
||||
|
||||
return command_base::_call<typename command_list_function<T>::type, T>(command_raw, target, arg);
|
||||
}
|
||||
|
||||
return command_base::_call<typename command_list_function<T>::type, T>(rawCommand, target, rawArgs.as_list());
|
||||
return command_base::_call<typename command_list_function<T>::type, T>(command_raw, target, args_raw.as_list());
|
||||
}
|
||||
|
||||
COMMAND_BASE_TEMPLATE_DEFINE(command_base_call_list);
|
||||
|
||||
+80
-51
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <new>
|
||||
#include <torrent/common.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/data/file_list_iterator.h>
|
||||
@@ -28,7 +29,6 @@ struct target_wrapper<void> {
|
||||
typedef no_type* cleaned_type;
|
||||
};
|
||||
|
||||
// Since c++0x isn't out yet...
|
||||
template <typename T1, typename T2, typename T3>
|
||||
struct rt_triple : private std::pair<T1, T2> {
|
||||
typedef std::pair<T1, T2> base_type;
|
||||
@@ -55,15 +55,11 @@ struct rt_triple : private std::pair<T1, T2> {
|
||||
base_type(src.first, src.second), third(src.third) {}
|
||||
};
|
||||
|
||||
// Since it gets used so many places we might as well put it in the
|
||||
// rpc namespace.
|
||||
//typedef std::pair<int, void*> target_type;
|
||||
typedef rt_triple<int, void*, void*> target_type;
|
||||
|
||||
class command_base;
|
||||
|
||||
typedef const torrent::Object (*command_base_call_type)(command_base*, target_type, const torrent::Object&);
|
||||
typedef std::function<torrent::Object (target_type, const torrent::Object&)> base_function;
|
||||
using target_type = rt_triple<int, void*, void*>;
|
||||
using base_function = std::function<torrent::Object (target_type, const torrent::Object&)>;
|
||||
using command_base_call_type = const torrent::Object (command_base*, target_type, const torrent::Object&);
|
||||
|
||||
template <typename tmpl> struct command_base_is_valid {};
|
||||
template <command_base_call_type tmpl_func> struct command_base_is_type {};
|
||||
@@ -87,17 +83,18 @@ public:
|
||||
|
||||
typedef const torrent::Object (*download_pair_slot) (command_base*, core::Download*, core::Download*, const torrent::Object&);
|
||||
|
||||
static const int target_generic = 0;
|
||||
static const int target_any = 1;
|
||||
static const int target_download = 2;
|
||||
static const int target_peer = 3;
|
||||
static const int target_tracker = 4;
|
||||
static const int target_file = 5;
|
||||
static const int target_file_itr = 6;
|
||||
static constexpr int target_generic = 0;
|
||||
static constexpr int target_any = 1;
|
||||
static constexpr int target_download = 2;
|
||||
static constexpr int target_peer = 3;
|
||||
static constexpr int target_tracker = 4;
|
||||
static constexpr int target_file = 5;
|
||||
static constexpr int target_file_itr = 6;
|
||||
static constexpr int target_download_pair = 7;
|
||||
|
||||
static const int target_download_pair = 7;
|
||||
static constexpr unsigned int max_arguments = 10;
|
||||
|
||||
static const unsigned int max_arguments = 10;
|
||||
static constexpr std::size_t optimal_alignment = std::max(alignof(std::max_align_t), alignof(base_function));
|
||||
|
||||
struct stack_type {
|
||||
torrent::Object* begin() { return reinterpret_cast<torrent::Object*>(buffer); }
|
||||
@@ -114,10 +111,48 @@ public:
|
||||
char buffer[sizeof(torrent::Object) * max_arguments];
|
||||
};
|
||||
|
||||
command_base() { new (&_pod<base_function>()) base_function(); }
|
||||
command_base(const command_base& src) { new (&_pod<base_function>()) base_function(src._pod<base_function>()); }
|
||||
command_base() : m_copy_helper(nullptr), m_dest_helper(nullptr) {}
|
||||
|
||||
~command_base() { _pod<base_function>().~base_function(); }
|
||||
command_base(const command_base& src) {
|
||||
m_copy_helper = src.m_copy_helper;
|
||||
m_dest_helper = src.m_dest_helper;
|
||||
if (src.m_copy_helper)
|
||||
src.m_copy_helper(t_pod, src.t_pod);
|
||||
}
|
||||
|
||||
command_base& operator=(const command_base& src) {
|
||||
if (this != &src) {
|
||||
if (m_dest_helper) m_dest_helper(t_pod);
|
||||
m_copy_helper = src.m_copy_helper;
|
||||
m_dest_helper = src.m_dest_helper;
|
||||
if (src.m_copy_helper)
|
||||
src.m_copy_helper(t_pod, src.t_pod);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
command_base(command_base&& src) noexcept {
|
||||
m_copy_helper = src.m_copy_helper;
|
||||
m_dest_helper = src.m_dest_helper;
|
||||
if (src.m_copy_helper)
|
||||
src.m_copy_helper(t_pod, src.t_pod);
|
||||
}
|
||||
|
||||
command_base& operator=(command_base&& src) noexcept {
|
||||
if (this != &src) {
|
||||
if (m_dest_helper) m_dest_helper(t_pod);
|
||||
m_copy_helper = src.m_copy_helper;
|
||||
m_dest_helper = src.m_dest_helper;
|
||||
if (src.m_copy_helper)
|
||||
src.m_copy_helper(t_pod, src.t_pod);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~command_base() {
|
||||
if (m_dest_helper)
|
||||
m_dest_helper(t_pod);
|
||||
}
|
||||
|
||||
static torrent::Object* argument(unsigned int index) { return current_stack.begin() + index; }
|
||||
static torrent::Object& argument_ref(unsigned int index) { return *(current_stack.begin() + index); }
|
||||
@@ -132,55 +167,51 @@ public:
|
||||
static void pop_stack(stack_type* stack, torrent::Object* last_stack);
|
||||
|
||||
template <typename T>
|
||||
void set_function(T s, [[maybe_unused]] int value = command_base_is_valid<T>::value) { _pod<T>() = s; }
|
||||
void set_function(T s, [[maybe_unused]] int value = command_base_is_valid<T>::value) {
|
||||
static_assert(sizeof(T) <= sizeof(t_pod), "t_pod storage overflow");
|
||||
static_assert(optimal_alignment >= alignof(T), "t_pod alignment insufficient for type");
|
||||
|
||||
if (m_dest_helper)
|
||||
m_dest_helper(t_pod);
|
||||
|
||||
::new (t_pod) T(std::move(s));
|
||||
|
||||
m_copy_helper = [](void* dest, const void* src) {
|
||||
::new (dest) T(*static_cast<const T*>(src));
|
||||
};
|
||||
m_dest_helper = [](void* ptr) {
|
||||
static_cast<T*>(ptr)->~T();
|
||||
};
|
||||
}
|
||||
|
||||
template <command_base_call_type T>
|
||||
void set_function_2(typename command_base_is_type<T>::type s, [[maybe_unused]] int value = command_base_is_valid<typename command_base_is_type<T>::type>::value) {
|
||||
_pod<typename command_base_is_type<T>::type>() = s;
|
||||
set_function<typename command_base_is_type<T>::type>(std::move(s));
|
||||
}
|
||||
|
||||
// The std::function object in GCC is castable between types with a
|
||||
// pointer to a struct of ctor/dtor/calls for non-POD slots. As such
|
||||
// it should be safe to cast between different std::function
|
||||
// template types, yet what the C++0x standard will say about this I
|
||||
// have no idea atm.
|
||||
template <typename tmpl> tmpl& _pod() { return reinterpret_cast<tmpl&>(t_pod); }
|
||||
template <typename tmpl> const tmpl& _pod() const { return reinterpret_cast<const tmpl&>(t_pod); }
|
||||
|
||||
template <typename Func, typename T, typename Args>
|
||||
static const torrent::Object _call(command_base* cmd, target_type target, Args args);
|
||||
|
||||
command_base& operator = (const command_base& src) {
|
||||
_pod<base_function>() = src._pod<base_function>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
// For use by functions that need to use placeholders to arguments
|
||||
// within commands. E.d. callable command strings where one of the
|
||||
// arguments within the command needs to be supplied by the caller.
|
||||
using copy_fn_t = void (*)(void* dest, const void* src);
|
||||
using dest_fn_t = void (*)(void* ptr);
|
||||
|
||||
#ifdef HAVE_CXX11
|
||||
union {
|
||||
base_function t_pod;
|
||||
// char t_pod[sizeof(base_function)];
|
||||
};
|
||||
#else
|
||||
union {
|
||||
char t_pod[sizeof(base_function)];
|
||||
};
|
||||
#endif
|
||||
alignas(optimal_alignment) char t_pod[sizeof(base_function)];
|
||||
|
||||
copy_fn_t m_copy_helper;
|
||||
dest_fn_t m_dest_helper;
|
||||
};
|
||||
|
||||
template <typename T1 = void, typename T2 = void>
|
||||
struct target_type_id {
|
||||
// Nothing here, so we cause an error.
|
||||
};
|
||||
|
||||
template <typename T> inline bool
|
||||
is_target_compatible(const target_type& target) { return target.first == target_type_id<T>::value; }
|
||||
|
||||
// Splitting pairs into separate targets.
|
||||
inline bool is_target_pair(const target_type& target) { return target.first >= command_base::target_download_pair; }
|
||||
|
||||
template <typename T> inline T
|
||||
@@ -203,7 +234,7 @@ command_base::_call(command_base* cmd, target_type target, Args args) {
|
||||
|
||||
#define COMMAND_BASE_TEMPLATE_TYPE(func_type, func_parm) \
|
||||
template <typename T, int proper = target_type_id<T>::proper_type> struct func_type { typedef std::function<func_parm> type; }; \
|
||||
\
|
||||
\
|
||||
template <> struct command_base_is_valid<func_type<target_type>::type> { static const int value = 1; }; \
|
||||
template <> struct command_base_is_valid<func_type<core::Download*>::type> { static const int value = 1; }; \
|
||||
template <> struct command_base_is_valid<func_type<torrent::Peer*>::type> { static const int value = 1; }; \
|
||||
@@ -211,8 +242,6 @@ command_base::_call(command_base* cmd, target_type target, Args args) {
|
||||
template <> struct command_base_is_valid<func_type<torrent::File*>::type> { static const int value = 1; }; \
|
||||
template <> struct command_base_is_valid<func_type<torrent::FileListIterator*>::type> { static const int value = 1; };
|
||||
|
||||
// template <typename Q> struct command_base_is_valid<typename func_type<Q>::type > { static const int value = 1; };
|
||||
|
||||
COMMAND_BASE_TEMPLATE_TYPE(command_function, torrent::Object (T, const torrent::Object&));
|
||||
COMMAND_BASE_TEMPLATE_TYPE(command_value_function, torrent::Object (T, const torrent::Object::value_type&));
|
||||
COMMAND_BASE_TEMPLATE_TYPE(command_string_function, torrent::Object (T, const std::string&));
|
||||
@@ -220,7 +249,7 @@ COMMAND_BASE_TEMPLATE_TYPE(command_list_function, torrent::Object (T, const to
|
||||
|
||||
#define COMMAND_BASE_TEMPLATE_CALL(func_name, func_type) \
|
||||
template <typename T> const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \
|
||||
\
|
||||
\
|
||||
template <> struct command_base_is_type<func_name<target_type> > { static const int value = 1; typedef func_type<target_type>::type type; }; \
|
||||
template <> struct command_base_is_type<func_name<core::Download*> > { static const int value = 1; typedef func_type<core::Download*>::type type; }; \
|
||||
template <> struct command_base_is_type<func_name<torrent::Peer*> > { static const int value = 1; typedef func_type<torrent::Peer*>::type type; }; \
|
||||
|
||||
+84
-51
@@ -1,23 +1,32 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <spawn.h>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <torrent/net/fd.h>
|
||||
#include <torrent/system/thread.h>
|
||||
#include <torrent/system/types.h>
|
||||
|
||||
#include "exec_file.h"
|
||||
#include "parse.h"
|
||||
|
||||
// Standard POSIX environment pointer
|
||||
extern char** environ;
|
||||
|
||||
namespace rpc {
|
||||
|
||||
// TODO: Access fd through torrent logging?
|
||||
|
||||
int
|
||||
ExecFile::execute(const char* file, char* const* argv, int flags) {
|
||||
assert(!((flags & flag_capture) && (flags & flag_background)));
|
||||
|
||||
// Write the executed command and its parameters to the log fd.
|
||||
[[maybe_unused]] int result;
|
||||
|
||||
@@ -34,86 +43,103 @@ ExecFile::execute(const char* file, char* const* argv, int flags) {
|
||||
result = write(m_log_fd, "\n---\n", sizeof("\n---\n"));
|
||||
}
|
||||
|
||||
int pipeFd[2];
|
||||
posix_spawn_file_actions_t actions{};
|
||||
|
||||
if ((flags & flag_capture) && pipe(pipeFd))
|
||||
throw torrent::input_error("ExecFile::execute(...) Pipe creation failed.");
|
||||
if (posix_spawn_file_actions_init(&actions) != 0)
|
||||
throw torrent::internal_error("ExecFile::execute(...) posix_spawn_file_actions_init failed.");
|
||||
|
||||
pid_t childPid = fork();
|
||||
posix_spawnattr_t attr;
|
||||
posix_spawnattr_init(&attr);
|
||||
|
||||
if (childPid == -1) {
|
||||
if (flags & flag_capture) {
|
||||
::close(pipeFd[0]);
|
||||
::close(pipeFd[1]);
|
||||
}
|
||||
throw torrent::input_error("ExecFile::execute(...) Fork failed.");
|
||||
// Try to avoid leaking open fds to the spawned process. Prefer POSIX_SPAWN_CLOEXEC_DEFAULT
|
||||
// (macOS-only) or posix_spawn_file_actions_addclosefrom_np (glibc >= 2.34, FreeBSD >= 13.1).
|
||||
//
|
||||
// Other platforms like musl libc, OpenBSD and NetBSD must rely on explicit O_CLOEXEC.
|
||||
|
||||
// Handle standard input redirection (/dev/null), posix_spawn_file_actions_addopen handles opening
|
||||
// and dup2 natively
|
||||
if (posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_RDWR, 0) != 0) {
|
||||
// Fallback if open fails inside action setup
|
||||
posix_spawn_file_actions_addclose(&actions, 0);
|
||||
}
|
||||
|
||||
if (childPid == 0) {
|
||||
if (flags & flag_background) {
|
||||
pid_t detached_pid = fork();
|
||||
int pipe_0 = -1;
|
||||
int pipe_1 = -1;
|
||||
|
||||
if (detached_pid == -1)
|
||||
_exit(-1);
|
||||
// Handle standard output redirection
|
||||
if (flags & flag_capture) {
|
||||
torrent::fd_open_pipe(pipe_0, pipe_1);
|
||||
|
||||
if (detached_pid != 0) {
|
||||
if (m_log_fd != -1)
|
||||
result = write(m_log_fd, "\n--- Background task ---\n", sizeof("\n--- Background task ---\n"));
|
||||
posix_spawn_file_actions_adddup2(&actions, pipe_1, 1);
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
// Ensure the write end of the pipe is closed in the child after duplicating.
|
||||
posix_spawn_file_actions_addclose(&actions, pipe_0);
|
||||
posix_spawn_file_actions_addclose(&actions, pipe_1);
|
||||
|
||||
m_log_fd = -1;
|
||||
flags &= ~flag_capture;
|
||||
}
|
||||
} else if (m_log_fd != -1) {
|
||||
posix_spawn_file_actions_adddup2(&actions, m_log_fd, 1);
|
||||
|
||||
int devNull = open("/dev/null", O_RDWR);
|
||||
} else {
|
||||
posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_RDWR, 0);
|
||||
}
|
||||
|
||||
if (devNull != -1)
|
||||
dup2(devNull, 0);
|
||||
else
|
||||
::close(0);
|
||||
if (m_log_fd != -1) {
|
||||
posix_spawn_file_actions_adddup2(&actions, m_log_fd, 2);
|
||||
} else {
|
||||
posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_RDWR, 0);
|
||||
}
|
||||
|
||||
if (flags & flag_capture)
|
||||
dup2(pipeFd[1], 1);
|
||||
else if (m_log_fd != -1)
|
||||
dup2(m_log_fd, 1);
|
||||
else if (devNull != -1)
|
||||
dup2(devNull, 1);
|
||||
else
|
||||
::close(1);
|
||||
short spawn_flags = 0;
|
||||
|
||||
if (m_log_fd != -1)
|
||||
dup2(m_log_fd, 2);
|
||||
else if (devNull != -1)
|
||||
dup2(devNull, 2);
|
||||
else
|
||||
::close(2);
|
||||
#if defined(POSIX_SPAWN_CLOEXEC_DEFAULT)
|
||||
spawn_flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
|
||||
#elif defined(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP)
|
||||
posix_spawn_file_actions_addclosefrom_np(&actions, 3);
|
||||
#endif
|
||||
|
||||
// Close all fd's.
|
||||
for (int i = 3, last = sysconf(_SC_OPEN_MAX); i != last; i++)
|
||||
::close(i);
|
||||
if (flags & flag_background) {
|
||||
#ifdef POSIX_SPAWN_SETSID
|
||||
spawn_flags |= POSIX_SPAWN_SETSID;
|
||||
#else
|
||||
spawn_flags |= POSIX_SPAWN_SETPGROUP;
|
||||
posix_spawnattr_setpgroup(&attr, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
result = execvp(file, argv);
|
||||
posix_spawnattr_setflags(&attr, spawn_flags);
|
||||
|
||||
_exit(result);
|
||||
pid_t child_pid{};
|
||||
int spawn_status = posix_spawnp(&child_pid, file, &actions, &attr, argv, environ);
|
||||
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
posix_spawnattr_destroy(&attr);
|
||||
|
||||
if (spawn_status != 0) {
|
||||
if (pipe_0 != -1)
|
||||
torrent::fd_close(pipe_0);
|
||||
|
||||
if (pipe_1 != -1)
|
||||
torrent::fd_close(pipe_1);
|
||||
|
||||
throw torrent::input_error("ExecFile::execute() posix_spawn failed: " + torrent::system::errno_enum_str(spawn_status));
|
||||
}
|
||||
|
||||
if (flags & flag_capture) {
|
||||
m_capture = std::string();
|
||||
::close(pipeFd[1]);
|
||||
torrent::fd_close(pipe_1);
|
||||
|
||||
char buffer[4096];
|
||||
ssize_t length;
|
||||
|
||||
do {
|
||||
length = read(pipeFd[0], buffer, sizeof(buffer));
|
||||
length = read(pipe_0, buffer, sizeof(buffer));
|
||||
|
||||
if (length > 0)
|
||||
m_capture += std::string(buffer, length);
|
||||
|
||||
} while (length > 0);
|
||||
|
||||
::close(pipeFd[0]);
|
||||
torrent::fd_close(pipe_0);
|
||||
|
||||
if (m_log_fd != -1) {
|
||||
result = write(m_log_fd, "Captured output:\n", sizeof("Captured output:\n"));
|
||||
@@ -121,9 +147,16 @@ ExecFile::execute(const char* file, char* const* argv, int flags) {
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & flag_background) {
|
||||
if (m_log_fd != -1)
|
||||
result = write(m_log_fd, "\n--- Running in Background ---\n", sizeof("\n--- Running in Background ---\n"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int status;
|
||||
|
||||
while (waitpid(childPid, &status, 0) == -1) {
|
||||
while (::waitpid(child_pid, &status, 0) == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
|
||||
+4
-5
@@ -48,7 +48,7 @@ SCgi::open_port(sockaddr* sa, unsigned int length, bool dont_route) {
|
||||
|
||||
open(reinterpret_cast<sockaddr*>(sa), length);
|
||||
|
||||
torrent::runtime::socket_manager()->register_event_or_throw(this, torrent::runtime::category_scgi, []() {});
|
||||
torrent::runtime::socket_manager()->register_event_or_throw(this, torrent::runtime::category_rpc, []() {});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -72,7 +72,7 @@ SCgi::open_named(const std::string& filename) {
|
||||
|
||||
open(reinterpret_cast<sockaddr*>(sa), offsetof(struct sockaddr_un, sun_path) + filename.size() + 1);
|
||||
|
||||
torrent::runtime::socket_manager()->register_event_or_throw(this, torrent::runtime::category_scgi, []() {});
|
||||
torrent::runtime::socket_manager()->register_event_or_throw(this, torrent::runtime::category_rpc, []() {});
|
||||
|
||||
m_path = filename;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ SCgi::open_fd(int fd) {
|
||||
|
||||
// fd is already bound and listening; no bind()/listen() needed.
|
||||
|
||||
torrent::runtime::socket_manager()->register_event_or_throw(this, torrent::runtime::category_scgi, []() {});
|
||||
torrent::runtime::socket_manager()->register_event_or_throw(this, torrent::runtime::category_rpc, []() {});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -111,7 +111,6 @@ SCgi::activate() {
|
||||
|
||||
torrent::this_thread::poll()->open(this);
|
||||
torrent::this_thread::poll()->insert_read(this);
|
||||
torrent::this_thread::poll()->insert_error(this);
|
||||
}
|
||||
|
||||
// TODO: This should close the fd to avoid reuse.
|
||||
@@ -183,7 +182,7 @@ SCgi::event_read() {
|
||||
task->cancel_open();
|
||||
};
|
||||
|
||||
bool result = torrent::runtime::socket_manager()->open_event_or_cleanup(m_current->get(), torrent::runtime::category_scgi, open_func, cleanup_func);
|
||||
bool result = torrent::runtime::socket_manager()->open_event_or_cleanup(m_current->get(), torrent::runtime::category_rpc, open_func, cleanup_func);
|
||||
|
||||
if (!result)
|
||||
break;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace rpc {
|
||||
SCgiTask::SCgiTask()
|
||||
: m_callback_id(torrent::system::make_callback_id()) {
|
||||
|
||||
set_file_descriptor(-1);
|
||||
reset_file_descriptor();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -49,7 +49,6 @@ SCgiTask::open(SCgi* parent, int fd) {
|
||||
|
||||
torrent::this_thread::poll()->open(this);
|
||||
torrent::this_thread::poll()->insert_read(this);
|
||||
torrent::this_thread::poll()->insert_error(this);
|
||||
|
||||
auto lock = std::lock_guard<std::mutex>(m_result_mutex);
|
||||
|
||||
@@ -65,7 +64,7 @@ SCgiTask::cancel_open() {
|
||||
torrent::this_thread::poll()->remove_and_close(this);
|
||||
|
||||
torrent::fd_close(file_descriptor());
|
||||
set_file_descriptor(-1);
|
||||
reset_file_descriptor();
|
||||
};
|
||||
|
||||
void
|
||||
@@ -79,7 +78,7 @@ SCgiTask::close() {
|
||||
torrent::this_thread::poll()->remove_and_close(this);
|
||||
|
||||
torrent::fd_close(file_descriptor());
|
||||
set_file_descriptor(-1);
|
||||
reset_file_descriptor();
|
||||
});
|
||||
|
||||
// The callbacks are guaranteed to be finished/canceled at this point.
|
||||
@@ -98,7 +97,7 @@ SCgiTask::event_read() {
|
||||
if (read_length <= 0)
|
||||
throw torrent::internal_error("SCgiTask::event_read() no space in buffer for event_read.");
|
||||
|
||||
int bytes = ::recv(m_fileDesc, m_buffer.data() + m_position, read_length, 0);
|
||||
int bytes = ::recv(file_descriptor(), m_buffer.data() + m_position, read_length, 0);
|
||||
|
||||
if (bytes <= 0) {
|
||||
if (bytes == 0 || !(errno == EAGAIN || errno == EINTR))
|
||||
@@ -181,7 +180,7 @@ event_read_failed:
|
||||
|
||||
void
|
||||
SCgiTask::event_write() {
|
||||
int bytes = ::send(m_fileDesc, m_buffer.data() + m_position, m_buffer.size() - m_position, 0);
|
||||
int bytes = ::send(file_descriptor(), m_buffer.data() + m_position, m_buffer.size() - m_position, 0);
|
||||
|
||||
if (bytes == -1) {
|
||||
if (!(errno == EAGAIN || errno == EINTR))
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@ public:
|
||||
|
||||
const char* type_name() const override { return "scgi-task"; }
|
||||
|
||||
bool is_open() const { return m_fileDesc != -1; }
|
||||
bool is_available() const { return m_fileDesc == -1; }
|
||||
bool is_open() const { return file_descriptor() != -1; }
|
||||
bool is_available() const { return file_descriptor() == -1; }
|
||||
|
||||
void open(SCgi* parent, int fd);
|
||||
void cancel_open();
|
||||
|
||||
@@ -42,6 +42,7 @@ SignalHandler::set_handler(unsigned int signum, slot_void slot) {
|
||||
throw std::logic_error("SignalHandler::set_handler(...) received an empty slot.");
|
||||
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = &SignalHandler::caught;
|
||||
@@ -52,6 +53,46 @@ SignalHandler::set_handler(unsigned int signum, slot_void slot) {
|
||||
m_handlers[signum] = slot;
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_block(unsigned int signum) {
|
||||
if (signum >= HIGHEST_SIGNAL)
|
||||
throw std::logic_error("SignalHandler::set_block(...) received invalid signal value.");
|
||||
|
||||
sigset_t mask;
|
||||
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signum);
|
||||
|
||||
if (pthread_sigmask(SIG_BLOCK, &mask, NULL) == -1)
|
||||
throw std::logic_error("Could not block signal: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_unblock(unsigned int signum) {
|
||||
if (signum >= HIGHEST_SIGNAL)
|
||||
throw std::logic_error("SignalHandler::set_unblock(...) received invalid signal value.");
|
||||
|
||||
sigset_t mask;
|
||||
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signum);
|
||||
|
||||
if (pthread_sigmask(SIG_UNBLOCK, &mask, NULL) == -1)
|
||||
throw std::logic_error("Could not unblock signal: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_sigchild_ignore() {
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sa.sa_flags = SA_NOCLDWAIT | SA_RESTART;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
if (sigaction(SIGCHLD, &sa, NULL) == -1)
|
||||
throw std::logic_error("Could not set sigaction (ignore) for SIGCHLD: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::set_sigaction_handler(unsigned int signum, handler_slot slot) {
|
||||
if (signum >= HIGHEST_SIGNAL)
|
||||
|
||||
+5
-34
@@ -1,37 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
#ifndef RTORRENT_SIGNAL_HANDLER_H
|
||||
#define RTORRENT_SIGNAL_HANDLER_H
|
||||
|
||||
@@ -56,6 +22,11 @@ public:
|
||||
static void set_ignore(unsigned int signum);
|
||||
static void set_handler(unsigned int signum, slot_void slot);
|
||||
|
||||
static void set_block(unsigned int signum);
|
||||
static void set_unblock(unsigned int signum);
|
||||
|
||||
static void set_sigchild_ignore();
|
||||
|
||||
static void set_sigaction_handler(unsigned int signum, handler_slot slot);
|
||||
|
||||
static const char* as_string(unsigned int signum);
|
||||
|
||||
+4
-7
@@ -3,7 +3,6 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/chunk_manager.h>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/data/file_list.h>
|
||||
@@ -31,10 +30,10 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
Download::Download(core::Download* d) :
|
||||
m_download(d) {
|
||||
Download::Download(core::Download* d)
|
||||
: m_download(d) {
|
||||
|
||||
m_windowDownloadStatus = new WDownloadStatus(d);
|
||||
m_windowDownloadStatus = std::make_unique<WDownloadStatus>(d);
|
||||
m_windowDownloadStatus->set_bottom(true);
|
||||
|
||||
m_uiArray[DISPLAY_MENU] = create_menu();
|
||||
@@ -60,8 +59,6 @@ Download::~Download() {
|
||||
assert(!is_active() && "ui::Download::~Download() called on an active object.");
|
||||
|
||||
std::for_each(m_uiArray, m_uiArray + DISPLAY_MAX_SIZE, [](ElementBase* eb) { delete eb; });
|
||||
|
||||
delete m_windowDownloadStatus;
|
||||
}
|
||||
|
||||
inline ElementBase*
|
||||
@@ -171,7 +168,7 @@ Download::activate(display::Frame* frame, [[maybe_unused]] bool focus) {
|
||||
m_frame = frame;
|
||||
m_frame->initialize_row(2);
|
||||
|
||||
m_frame->frame(1)->initialize_window(m_windowDownloadStatus);
|
||||
m_frame->frame(1)->initialize_window(m_windowDownloadStatus.get());
|
||||
m_windowDownloadStatus->set_active(true);
|
||||
|
||||
activate_display_menu(DISPLAY_PEER_LIST);
|
||||
|
||||
+1
-35
@@ -1,37 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
#ifndef RTORRENT_UI_DOWNLOAD_H
|
||||
#define RTORRENT_UI_DOWNLOAD_H
|
||||
|
||||
@@ -113,7 +79,7 @@ private:
|
||||
|
||||
bool m_focusDisplay{};
|
||||
|
||||
WDownloadStatus* m_windowDownloadStatus;
|
||||
std::unique_ptr<WDownloadStatus> m_windowDownloadStatus;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@ namespace ui {
|
||||
|
||||
class ElementLogComplete : public ElementBase {
|
||||
public:
|
||||
typedef display::WindowLogComplete WLogComplete;
|
||||
using WLogComplete = display::WindowLogComplete;
|
||||
|
||||
ElementLogComplete(torrent::log_buffer* l);
|
||||
~ElementLogComplete() override;
|
||||
|
||||
void activate(display::Frame* frame, bool focus = true);
|
||||
void disable();
|
||||
void activate(display::Frame* frame, bool focus = true) override;
|
||||
void disable() override;
|
||||
|
||||
display::Window* window();
|
||||
|
||||
@@ -32,7 +32,9 @@ private:
|
||||
|
||||
torrent::log_buffer* m_log;
|
||||
|
||||
align_cacheline std::atomic<bool> m_log_updating{};
|
||||
align_cacheline
|
||||
|
||||
std::atomic<bool> m_log_updating{};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -49,6 +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_encryption_config.cc \
|
||||
src/test_encryption_config.h \
|
||||
src/test_watch_ready_queue.cc \
|
||||
src/test_watch_ready_queue.h
|
||||
|
||||
|
||||
@@ -170,19 +170,18 @@ TestParseOptions::test_flag_libtorrent() {
|
||||
FLAG_LT_LOG_ASSERT_ERROR("resume_data|rpc_dump");
|
||||
}
|
||||
|
||||
#define FLAGS_LT_ENCRYPTION_ASSERT(flags, result) \
|
||||
CPPUNIT_ASSERT(rpc::parse_option_flags(flags, std::bind(&torrent::option_find_string_str, torrent::OPTION_ENCRYPTION, std::placeholders::_1)) == (result))
|
||||
#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_ENCRYPTION_ASSERT_ERROR(flags) \
|
||||
ASSERT_CATCH_INPUT_ERROR(rpc::parse_option_flags(flags, std::bind(&torrent::option_find_string_str, torrent::OPTION_ENCRYPTION, std::placeholders::_1)))
|
||||
#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_ENCRYPTION_ASSERT("", torrent::runtime::NetworkConfig::encryption_none);
|
||||
FLAGS_LT_ENCRYPTION_ASSERT("none", torrent::runtime::NetworkConfig::encryption_none);
|
||||
FLAGS_LT_ENCRYPTION_ASSERT("require_rc4", torrent::runtime::NetworkConfig::encryption_require_RC4);
|
||||
FLAGS_LT_ENCRYPTION_ASSERT("require_RC4", torrent::runtime::NetworkConfig::encryption_require_RC4);
|
||||
FLAGS_LT_ENCRYPTION_ASSERT("require_RC4 | enable_retry", torrent::runtime::NetworkConfig::encryption_require_RC4 | torrent::runtime::NetworkConfig::encryption_enable_retry);
|
||||
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_ENCRYPTION_ASSERT_ERROR("require_");
|
||||
FLAGS_LT_IP_TOS_ASSERT_ERROR("throughput_");
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
Reference in New Issue
Block a user