Compare commits

..

17 Commits

Author SHA1 Message Date
rakshasa d3ecc83b32 Release 0.15.7. 2025-09-05 07:28:59 +00:00
Bryant Eadon 457d5170b8 cleanup of personal information
Given the change to the README I thought it might be a good idea to also update the copyright notices which had an address too.
2025-09-05 07:28:47 +00:00
Jari Sundell 1c598d51ef Fix formatting and capitalization in README.md 2025-09-05 07:28:34 +00:00
Jari Sundell 644ea6c23f Revise README structure and donation information
Updated sections in README for clarity and formatting.
2025-09-05 07:28:25 +00:00
Bryant Eadon de3615a72c README combined
Combined README files to reduce clutter.  However, the build instructions are incomplete ... I've started by modifying these so a build will complete using the instructions once I get a closer look at libtorrent ... additions welcome.
2025-09-05 07:28:18 +00:00
Bryant Eadon e9e4064bb3 Delete uused file
minor cleanup.
2025-09-05 07:28:10 +00:00
Bryant Eadon 04fc51e76b Update README.md
proposing a new message for the release download.  to draw attention to the github repo, instead of the archive.
2025-09-05 07:28:02 +00:00
rakshasa 24693fc19e Release 0.15.6. 2025-08-23 08:08:36 +00:00
rakshasa 9661a2aaa9 Added test for xmlrpc string reflection. 2025-08-11 10:18:20 +02:00
rakshasa aaf42c247e Strict checking of d.views push_back arguments. 2025-08-11 10:16:23 +02:00
rakshasa cba48f4a10 Invert color of focus ui element. 2025-08-11 10:14:46 +02:00
rakshasa 4463bf418e Release 0.15.5. 2025-06-22 16:44:05 +00:00
Phil Rosenthal 8bd7c79755 Fix file descriptor leak in session file saving
When system.files.session.fdatasync is set to "no", file descriptors
  were not being closed after writing session files, causing a severe
  resource leak. Each save operation would leak one file descriptor.

  With hundreds of torrents, this leads to tens of thousands of leaked
  file descriptors within hours, mostly pointing to deleted session files.
  This can exhaust the system's file descriptor limit and cause rtorrent
  to fail when opening new files.

  The fix moves the close() call outside the fdatasync conditional block,
  ensuring file descriptors are always properly closed regardless of the
  fdatasync setting.
2025-06-18 19:04:45 +02:00
rakshasa f2b83d50e8 Use libtorrent stable-0.15 branch in workflow. 2025-06-08 13:01:36 +02:00
rakshasa ab40059891 Use libtorrent stable-0.15 branch in workflow. 2025-06-08 13:01:36 +02:00
rakshasa b9d880dea3 Properly handle -1 value passed to curl set_timeout. 2025-06-08 13:01:36 +02:00
rakshasa b4c59d2c7a Fixed corrupted stack in curl stack due to wrong argument type. 2025-06-07 13:17:34 +02:00
107 changed files with 3083 additions and 1366 deletions
+5 -6
View File
@@ -11,15 +11,11 @@ jobs:
- name: Update Packages
run: |
sudo apt-get update
- name: Install Dependencies
run: |
sudo apt-get install -y \
bear \
clang-tidy \
libcurl4-openssl-dev
- name: Fetch libtorrent
run: |
git clone https://github.com/rakshasa/libtorrent
cd libtorrent
git checkout stable-0.15
- name: Build libtorrent
run: |
cd libtorrent
@@ -41,6 +37,9 @@ jobs:
run: |
git remote add upstream "https://github.com/${{ github.event.pull_request.base.repo.full_name }}"
git fetch --no-tags --no-recurse-submodules upstream "${{ github.event.pull_request.base.ref }}"
- name: Install Dependencies
run: |
sudo apt-get install -y bear clang-tidy libcurl4-openssl-dev
- name: Configure Project
run: |
libtoolize
+7 -13
View File
@@ -11,14 +11,11 @@ jobs:
- name: Update Packages
run: |
sudo apt-get update
- name: Install Dependencies
run: |
sudo apt-get install -y \
libcppunit-dev \
libcurl4-openssl-dev
- name: Fetch libtorrent
run: |
git clone https://github.com/rakshasa/libtorrent
cd libtorrent
git checkout stable-0.15
- name: Build libtorrent
run: |
cd libtorrent
@@ -40,6 +37,11 @@ jobs:
run: |
git remote add upstream "https://github.com/${{ github.event.pull_request.base.repo.full_name }}"
git fetch --no-tags --no-recurse-submodules upstream "${{ github.event.pull_request.base.ref }}"
- name: Install Dependencies
run: |
sudo apt-get install -y \
libcppunit-dev \
libcurl4-openssl-dev
- name: Configure Project
run: |
libtoolize
@@ -53,12 +55,4 @@ jobs:
make
- name: Run Unit Tests
run: |
ls /usr/local/lib/
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
make check
- name: Archive test/test-suite.log
if: success() || failure()
uses: actions/upload-artifact@v4
with:
name: test-suite.log
path: test/test-suite.log
+85
View File
@@ -0,0 +1,85 @@
language: cpp
env:
global:
- MAKEFLAGS="-j 12"
matrix:
include:
- compiler: clang
env: COMPILER=clang++ SKIP_CHECK=true
- compiler: clang
env: COMPILER=clang++
addons:
apt:
packages:
- libcppunit-dev
- compiler: clang
env: COMPILER=clang++-3.6
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.6
packages:
- clang-3.6
- libcppunit-dev
- compiler: clang
env: COMPILER=clang++-3.7
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
packages:
- clang-3.7
- libcppunit-dev
- compiler: clang
env: COMPILER=clang++-3.8
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.8
packages:
- clang-3.8
- libcppunit-dev
- compiler: gcc
env: COMPILER=g++-4.7 SKIP_CHECK=true
addons:
apt:
sources: ubuntu-toolchain-r-test
packages:
- g++-4.7
- compiler: gcc
env: COMPILER=g++-4.7
addons:
apt:
sources: ubuntu-toolchain-r-test
packages:
- g++-4.7
- libcppunit-dev
- compiler: gcc
env: COMPILER=g++-4.8
addons:
apt:
sources: ubuntu-toolchain-r-test
packages:
- g++-4.8
- libcppunit-dev
# TODO: Use the same branch name if libtorrent has it.
before_install:
- git clone https://github.com/rakshasa/libtorrent.git
- |
pushd libtorrent \
&& (git checkout ${TRAVIS_BRANCH} || true) \
&& ./autogen.sh \
&& CXX="$COMPILER" ./configure --prefix=/usr \
&& make \
&& sudo make install \
&& popd
script:
- ./autogen.sh && CXX="$COMPILER" ./configure && make
- if [ ! $SKIP_CHECK ]; then make check; fi
View File
+3 -3
View File
@@ -3,17 +3,17 @@ SUBDIRS = \
src \
test
nobase_dist_pkgdata_DATA = \
lua/rtorrent.lua
EXTRA_DIST= \
rtorrent.lua \
rak/address_info.h \
rak/algorithm.h \
rak/error_number.h \
rak/file_stat.h \
rak/fs_stat.h \
rak/path.h \
rak/partial_queue.h \
rak/regex.h \
rak/socket_address.h \
rak/string_manip.h \
rak/unordered_vector.h \
scripts/checks.m4 \
+2 -2
View File
@@ -41,7 +41,7 @@ cd rtorrent
## Install build dependencies
Install [libtorrent](https://github.com/rakshasa/libtorrent) with the same version rTorrent.
Install [libtorrent](https://libtorrent.org/) with the same version rTorrent.
Generate configure scripts:
@@ -57,7 +57,7 @@ docbook2man rtorrent.1.xml
Man pages output to "doc/rtorrent.1".
RTorrent follows the development of [libtorrent](https://github.com/rakshasa/libtorrent) closely, and thus the versions must be in sync.
RTorrent follows the development of [libtorrent](https://libtorrent.org/) closely, and thus the versions must be in sync.
## USAGE
+17 -7
View File
@@ -1,6 +1,6 @@
m4_pattern_allow([PKG_CHECK_EXISTS])
AC_INIT([rtorrent],[0.16.2],[sundell.software@gmail.com])
AC_INIT([rtorrent],[0.15.7],[sundell.software@gmail.com])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIRS([scripts])
@@ -10,8 +10,7 @@ AM_PROG_AR
LT_INIT
AC_PROG_CXX
AC_DEFINE([API_VERSION], [18], [api version])
AC_DEFINE([API_VERSION], [15], [api version])
# Filter out unwanted flags added by autoconf on some systems, e.g. MacOS.
TORRENT_REMOVE_UNWANTED(CXX, $CXX, -std=c++11 -std=gnu++11)
@@ -26,9 +25,15 @@ RAK_ENABLE_DEBUG
RAK_ENABLE_EXTRA_DEBUG
RAK_ENABLE_WERROR
TORRENT_DISABLE_IPV6
TORRENT_ENABLE_ARCH
TORRENT_WITH_SYSROOT
TORRENT_WITHOUT_VARIABLE_FDSET
TORRENT_WITHOUT_STATVFS
TORRENT_WITHOUT_STATFS
AC_ARG_ENABLE(execinfo,
AS_HELP_STRING([--disable-execinfo],
[disable libexecinfo [[default=enable]]]),
@@ -47,8 +52,9 @@ if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
fi
PKG_CHECK_MODULES([LIBCURL], [libcurl],, [LIBCURL_CHECK_CONFIG])
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.2])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.15.7])
AC_LANG_PUSH(C++)
TORRENT_WITH_XMLRPC_C
@@ -61,14 +67,18 @@ if test ${with_xmlrpc_c+y} && test ${with_xmlrpc_tinyxml2+y}; then
AC_MSG_ERROR([--with-xmlrpc-c and --with-xmlrpc-tinyxml2 cannot be used together. Please choose only one])
fi
AC_DEFINE(HAVE_CONFIG_H, 1, true if config.h was included)
AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION "/") + torrent::version()], Http user agent)
AC_CHECK_FUNCS(posix_memalign)
dnl Only update global build variables immediately before generating the output,
dnl to avoid affecting the global build environment for other autoconf checks.
LIBS="$PTHREAD_LIBS $CURSES_LIB $CURSES_LIBS $DEPENDENCIES_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
LIBS="$PTHREAD_LIBS $CURSES_LIB $CURSES_LIBS $LIBCURL $LIBCURL_LIBS $DEPENDENCIES_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
TORRENT_CHECK_CACHELINE()
TORRENT_CHECK_POPCOUNT()
AC_CONFIG_FILES([
+4 -14
View File
@@ -4,30 +4,20 @@
# log.open_file = "log name", "file path"
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
A newly opened log file is not connected to any logging events.
Some control over formatting will be provided at a later date.
## Appending to log files
log.append_file = "rtorrent.log", "/tmp/rtorrent.log"
The `log.open_file` clears any existing contents of the file. If you'd
prefer to have a single log file that persists across application
restarts, you can use the `log.append_file` in place of the
`log.open_file` configuration key.
## Adding outputs to events
# log.add_output = "logging event", "log name"
log.add_output = "info", "rtorrent.log"
log.add_output = "dht_all", "tracker.log"
log.add_output = "tracker_events", "tracker.log"
log.add_output = "tracker_requests", "tracker.log"
log.add_output = "dht_debug", "tracker.log"
log.add_output = "tracker_debug", "tracker.log"
Each log handle can be added to multiple different logging events.
@@ -41,7 +31,7 @@ Each log handle can be added to multiple different logging events.
"debug"
The above events receive logging events from all the sub-groups
displayed below, and each event also receiving events from the event
displayed below, and each event also reciving events from the event
above in importance.
Thus some high-volume sub-group events such as “tracker\_debug” are not
+3 -4
View File
@@ -5,7 +5,7 @@
\begin{verbatim}
# log.open_file = "log name", "file path"
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
log.open_file = "rtorrent.log", (cat,/tmp/rtorrent.log.,(system.pid))
\end{verbatim}
A newly opened log file is not connected to any logging events.
@@ -20,9 +20,8 @@ Some control over formatting will be provided at a later date.
log.add_output = "info", "rtorrent.log"
log.add_output = "dht_all", "tracker.log"
log.add_output = "tracker_events", "tracker.log"
log.add_output = "tracker_requests", "tracker.log"
log.add_output = "dht_debug", "tracker.log"
log.add_output = "tracker_debug", "tracker.log"
\end{verbatim}
Each log handle can be added to multiple different logging events.
-4
View File
@@ -119,10 +119,6 @@
#
#ui.torrent_list.layout.set = "full"
# Set navigation keymap style ("vi", "emacs"). Default is "emacs".
#
#ui.keymap.style.set = "emacs"
# Run rTorrent as a daemon, controlled via XMLRPC.
#
#system.daemon.set = false
+1 -4
View File
@@ -101,11 +101,8 @@ schedule2 = watch_load, 11, 10, ((load.verbose, (cat, (cfg.watch), "load/*.torre
# Levels = critical error warn notice info debug
# Groups = connection_* dht_* peer_* rpc_* storage_* thread_* tracker_* torrent_*
print = (cat, "Logging to ", (cfg.logfile))
log.open_file = "log", (cfg.logfile)
log.add_output = "info", "log"
#log.add_output = "tracker_events", "log"
#log.add_output = "tracker_requests", "log"
##log.add_output = "tracker_debug", "log"
### END of rtorrent.rc ###
-142
View File
@@ -1,142 +0,0 @@
--[[
A minimal rTorrent configuration that provides the basic features
you want to have in addition to the built-in defaults.
See https://github.com/rakshasa/rtorrent/wiki/CONFIG-Template
for an up-to-date version.
How to use this file:
1. Copy to destination, remove '-example' suffix
2. Create rtorrent.rc, containing single command, which executes THIS file.
For example:
lua.execute = (cat, (system.env, HOME), "/.config/rtorrent/rtorrent.rc.lua")
]]--
--[[ Bootstrap START ]]--
local rtorrent = require('rtorrent')
rc = rtorrent.autocall
--[[ Helper functions ]]--
local function makeArgs(cmdline)
return 'sh', '-c', "'"..table.concat(cmdline, "' '").."'"
end
-- Instance layout (base paths)
local home = os.getenv('HOME')
local cfg = {}
cfg.basedir = home..'/rtorrent/'
cfg.download = cfg.basedir..'download/'
cfg.logs = cfg.basedir..'log/'
cfg.logfile = cfg.logs..'rtorrent-'..rc.system.time()..'.log'
cfg.session = cfg.basedir..'.session/'
cfg.watch = cfg.basedir..'watch/'
rc.method.insert('cfg.download', 'private|const|string', cfg.download)
rc.method.insert('cfg.logs', 'private|const|string', cfg.logs)
rc.method.insert('cfg.logfile', 'private|const|string', cfg.logfile)
rc.method.insert('cfg.session', 'private|const|string', cfg.session)
rc.method.insert('cfg.watch', 'private|const|string', cfg.watch)
-- Create instance directories
rc.execute.throw(
makeArgs({'mkdir', '-p',
cfg.download,
cfg.logs,
cfg.session,
cfg.watch..'/load',
cfg.watch..'/start'}))
-- Listening port for incoming peer traffic (fixed; you can also randomize it)
rc.network.port_range = '50000-50000'
rc.network.port_random = false
-- Tracker-less torrent and UDP tracker support
-- (conservative settings for 'private' trackers, change for 'public')
rc.dht.mode = 'disable'
rc.protocol.pex = false
rc.trackers.use_udp = false
-- Peer settings
rc.throttle.max_uploads = 100
rc.throttle.max_uploads.global = 250
rc.throttle.min_peers.normal = 20
rc.throttle.max_peers.normal = 60
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')
-- Limits for file handle resources, this is optimized for
-- an `ulimit` of 1024 (a common default). You MUST leave
-- a ceiling of handles reserved for rTorrent's internal needs!
rc.network.http.max_open = 50
rc.network.max_open_files = 600
rc.network.max_open_sockets = 300
-- Memory resource usage (increase if you have a large number of items loaded,
-- and/or the available resources to spend)
rc.pieces.memory.max = '1800M'
rc.network.xmlrpc.size_limit = '4M'
-- Basic operational settings (no need to change these)
rc.session.path = cfg.session
rc.directory.default = cfg.download
rc.log.execute(cfg.logs.."execute.log")
--rc.log.xmlrpc(cfg.logs.."xmlrpc.log")
rc.execute.nothrow(
"sh", "-c", table.concat(
{"echo >", rc.session.path(), "rtorrent.pid", " ", rc.system.pid()
}))
-- Other operational settings (check & adapt)
rc.encoding.add('utf8')
rc.system.umask = 0027
rc.system.cwd = rc.directory.default()
rc.network.http.dns_cache_timeout = 25
rc.schedule2('monitor_diskspace', '15', '60', 'close_low_diskspace=1000M')
--rc.pieces.hash.on_completion = false
--rc.view.sort_current('seeding', 'greater=d.ratio=')
--rc.keys.layout = 'qwerty'
--rc.network.http.capath = '/etc/ssl/certs'
--rc.network.http.ssl_verify_peer = 0
--rc.network.http.ssl_verify_host = 0
--rc.network.rpc.use_xmlrpc = true
--rc.network.rpc.use_jsonrpc = true
-- Some additional values and commands
-- NOTE: just common names, not commands
rc.method.insert('system.startup_time', 'value|const', rc.system.time())
rc.method.insert('d.data_path', 'simple',
[[if=(d.is_multi_file),
(cat, (d.directory), /),
(cat, (d.directory), /, (d.name))]])
rc.method.insert('d.session_file', 'simple', 'cat=(session.path), (d.hash), .torrent')
-- Watch directories (add more as you like, but use unique schedule names)
rc.schedule2('watch_start', '10', '10', 'load.start_verbose=(cat, (cfg.watch), "start/*.torrent")')
rc.schedule2('watch_load', '11', '10', 'load.verbose=(cat, (cfg.watch), "load/*.torrent")')
-- Run the rTorrent process as a daemon in the background
-- (and control via XMLRPC sockets)
--rc.system.daemon = true
--rc.network.scgi.open_local(cfg.session..'rtorrent.sock')
--rc.execute.nothrow('chmod', '770', cfg.session..'rtorrent.sock')
-- Logging:
-- Levels = critical error warn notice info debug
-- Groups = connection_* dht_* peer_* rpc_* storage_* thread_* tracker_* torrent_*
rc.print('Logging to '..rc.cfg.logfile())
rc.log.open_file('log', rc.cfg.logfile())
rc.log.add_output('info', 'log')
--rc.log.add_output('tracker_events', 'log')
--rc.log.add_output('tracker_requests', 'log')
--[[ END of rtorrent.rc.lua ]]--
-127
View File
@@ -1,127 +0,0 @@
-- The "rtorrent" table is passed in by the C++ code, modify and
-- return it for loading.
local args = {...}
local rtorrent = args[1]
local math = require('math')
-- Autocall
-- Passes an empty first argument implicitly, as "".
-- Allows syntax like:
-- - `rtorrent.autocall.system.hostname()` or
-- - `rtorrent.autocall.session.directory.set("/tmp/")`
-- Has assignment operator, syntax sugar for `.set()` with single argument
-- - `rtorrent.autocall.session.directory = "/tmp/"`
-- Autocall-chains can be reused as aliases:
-- ```lua
-- a = rtorrent.autocall.system
-- a.hostname() -- same as `rtorrent.autocall.system.hostname()`
-- a.pid() -- same as `rtorrent.autocall.system.pid()`
local mt = {}
function mt.__call (t, ...)
name = table.concat(rawget(t, "__namestack"), ".")
tg = rawget(t, "__target") or ""
success, ret = pcall(rtorrent.call, name, tg, ...)
if not success then error(name..": "..ret, 2) end
return ret
end
function mt.__index (t, key)
ns = {table.unpack(rawget(t, "__namestack") or {})}
tg = rawget(t, "__target") or nil
table.insert(ns, key)
return setmetatable({__namestack=ns, __target=tg}, mt)
end
function mt.__newindex (t, key, value)
t[key].set(value)
end
rtorrent["autocall"] = setmetatable({}, mt)
-- Target-object
-- Sets first argment for Autocall, for commands that require target.
-- Second argument allows to add prefix to command.
-- Allows syntax like:
-- - `rtorrent.Target("some_infohash").d.name()` or
-- - `rtorrent.Target:new("some_infohash").d.name()`
-- Also can be stored as variable
local Target = setmetatable({
new = function (self, target, prefix)
return self(target, prefix)
end;
}, {
__call = function (self, target, prefix)
return setmetatable(
{__namestack={prefix}, __target=target}, mt)
end
})
rtorrent["Target"] = Target
-- Some aliases for Target-commands
for i, p in ipairs({ "d", "f", "p", "t", "load" }) do
rtorrent[p] = function (target) return Target(target, p) end
end
-- Insert Lua method
-- Allow insert global lua-finction `func_name` at rtorrent slot `name`
-- @param name string rtorrent's slot
-- @param func_name string name of global lua-function
-- @param method_args number|string[]|number[]
-- rtorrent's arguments like `(d.name)` to be passed to lua-function when it be
-- called by rtorrent:
--
-- 1) non-negative integer - number of first arguments to be passed
--
-- example:
-- rtorrent.insert_lua_method('d.watch_handler', 'watch_handler', 1)
--
-- gives following rtorrent event handler:
-- d.watch_handler=$argument.0
--
-- 2) table (array) of strings - concrete rtorrent strings, passed in specified
-- order
--
-- example:
-- rtorrent.insert_lua_method('d.watch_handler', 'watch_handler', { '$argument.0=' })
--
-- gives following rtorrent event handler:
-- d.watch_handler=$argument.0
--
-- 3) table (array) of non-negative integer - indexes, converted to
-- $argument.0, $argument.1 ..., passed in specified order
--
-- example:
-- rtorrent.insert_lua_method('d.watch_handler', 'watch_handler', { 1, 0 })
-- or:
-- rtorrent.insert_lua_method('d.watch_handler', 'watch_handler', { [1]=1, [2]=0 })
--
-- gives following rtorrent event handler:
-- d.watch_handler=$argument.1,$argument.0
--
-- NOTE: first argement of func_name is always target, may be empty string
rtorrent["insert_lua_method"] = function (name, func_name, method_args)
local args = {}
if method_args == nil then method_args = 0 end
if math.type(method_args) == 'integer' and method_args >= 0 then
for i = 1, method_args do
args[i] = "$argument." .. i-1 .. "="
end
elseif type(method_args) == 'table' then
for i, v in ipairs(method_args) do
if type(v) == 'string' then
args[i] = v
elseif math.type(v) == 'integer' and v >= 0 then
args[i] = "$argument." .. v .. "="
else
error("Incorrect arguments")
end
end
else
error("Incorrect arguments")
end
local arg_str = table.concat(args, ",")
if #arg_str > 0 then arg_str = ","..arg_str end
rtorrent.autocall.method.insert(name, "simple", 'lua.execute.str="return '..func_name..'(...)"'..arg_str)
end
return rtorrent
+39 -4
View File
@@ -1,3 +1,36 @@
// 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
// Wrapper for addrinfo with focus on zero-copy conversion to and from
// the c-type and wrapper.
//
@@ -8,7 +41,7 @@
#define RAK_ADDRESS_INFO_H
#include <netdb.h>
#include <cstring>
#include <rak/socket_address.h>
namespace rak {
@@ -24,12 +57,14 @@ public:
int socket_type() const { return m_addrinfo.ai_socktype; }
void set_socket_type(int t) { m_addrinfo.ai_socktype = t; }
int protocol() const { return m_addrinfo.ai_protocol; }
void set_protocol(int p) { m_addrinfo.ai_protocol = p; }
size_t length() const { return m_addrinfo.ai_addrlen; }
socket_address* address() { return reinterpret_cast<socket_address*>(m_addrinfo.ai_addr); }
addrinfo* c_addrinfo() { return &m_addrinfo; }
const addrinfo* c_addrinfo() const { return &m_addrinfo; }
@@ -51,7 +86,7 @@ address_info::get_address_info(const char* node, int pfamily, int stype, address
hints.clear();
hints.set_family(pfamily);
hints.set_socket_type(stype);
return ::getaddrinfo(node, NULL, hints.c_addrinfo(), reinterpret_cast<addrinfo**>(ai));
}
+2 -1
View File
@@ -36,6 +36,7 @@
#define RAK_ALGORITHM_H
#include <algorithm>
#include <functional>
#include <limits>
namespace rak {
@@ -112,7 +113,7 @@ advance_backward(_InputIter __first, _InputIter __last, _Distance __distance) {
}
template <typename _Value>
struct compare_base {
struct compare_base : public std::function<bool(_Value, _Value)> {
bool operator () (const _Value& complete, const _Value& base) const {
return !complete.compare(0, base.size(), base);
}
+84
View File
@@ -0,0 +1,84 @@
// 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 <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RAK_FS_STAT_H
#define RAK_FS_STAT_H
#include <string>
#include <cinttypes>
#include <rak/error_number.h>
#if HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#if HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#if HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
namespace rak {
class fs_stat {
public:
typedef FS_STAT_SIZE_TYPE blocksize_type;
typedef FS_STAT_COUNT_TYPE blockcount_type;
typedef FS_STAT_STRUCT fs_stat_type;
bool update(int fd) { return FS_STAT_FD; }
bool update(const char* fn) { return FS_STAT_FN; }
bool update(const std::string& filename) { return update(filename.c_str()); }
blocksize_type blocksize() { return FS_STAT_BLOCK_SIZE; }
blockcount_type blocks_avail() { return m_stat.f_bavail; }
int64_t bytes_avail() { return (int64_t) blocksize() * m_stat.f_bavail; }
private:
fs_stat_type m_stat;
};
}
#endif
+1 -1
View File
@@ -48,7 +48,7 @@
namespace rak {
class regex {
class regex : public std::function<bool (std::string)> {
public:
regex() {}
regex(const std::string& p) : m_pattern(p) {}
+557
View File
@@ -0,0 +1,557 @@
// 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>
// Wrappers for the various sockaddr types with focus on zero-copy
// casting between the original type and the wrapper class.
//
// The default ctor does not initialize any data.
//
// _n suffixes indicate that the argument or return value is in
// network byte order, _h that they are in hardware byte order.
// Add define for inet6 scope id?
#ifndef RAK_SOCKET_ADDRESS_H
#define RAK_SOCKET_ADDRESS_H
#include <cinttypes>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include <string>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
namespace rak {
class socket_address_inet;
class socket_address_inet6;
class socket_address {
public:
static const sa_family_t af_inet = AF_INET;
static const int pf_inet = PF_INET;
static const sa_family_t af_inet6 = AF_INET6;
static const int pf_inet6 = PF_INET6;
static const sa_family_t af_unspec = AF_UNSPEC;
static const int pf_unspec = PF_UNSPEC;
#ifdef AF_LOCAL
static const sa_family_t af_local = AF_LOCAL;
static const int pf_local = PF_LOCAL;
#else
static const sa_family_t af_local = AF_UNIX;
static const int pf_local = PF_UNIX;
#endif
bool is_any() const;
bool is_valid() const;
bool is_bindable() const;
bool is_address_any() const;
bool is_valid_inet_class() const { return family() == af_inet || family() == af_inet6; }
void clear() { std::memset(this, 0, sizeof(socket_address)); set_family(); }
sa_family_t family() const { return m_sockaddr.sa_family; }
void set_family() { m_sockaddr.sa_family = af_unspec; }
uint16_t port() const;
void set_port(uint16_t p);
std::string address_str() const;
bool address_c_str(char* buf, socklen_t size) const;
std::string pretty_address_str() const;
// Attemts to set it as an inet, then an inet6 address. It will
// never set anything but net addresses, no local/unix.
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
bool set_address_c_str(const char* a);
uint32_t length() const;
socket_address_inet* sa_inet() { return reinterpret_cast<socket_address_inet*>(this); }
const socket_address_inet* sa_inet() const { return reinterpret_cast<const socket_address_inet*>(this); }
sockaddr* c_sockaddr() { return &m_sockaddr; }
sockaddr_in* c_sockaddr_inet() { return &m_sockaddrInet; }
const sockaddr* c_sockaddr() const { return &m_sockaddr; }
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddrInet; }
socket_address_inet6* sa_inet6() { return reinterpret_cast<socket_address_inet6*>(this); }
const socket_address_inet6* sa_inet6() const { return reinterpret_cast<const socket_address_inet6*>(this); }
sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddrInet6; }
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddrInet6; }
// Copy a socket address which has the length 'length. Zero out any
// extranous bytes and ensure it does not go beyond the size of this
// struct.
void copy(const socket_address& src, size_t length);
void copy_sockaddr(const sockaddr* src);
static socket_address* cast_from(sockaddr* sa) { return reinterpret_cast<socket_address*>(sa); }
static const socket_address* cast_from(const sockaddr* sa) { return reinterpret_cast<const socket_address*>(sa); }
// The different families will be sorted according to the
// sa_family_t's numeric value.
bool operator == (const socket_address& rhs) const;
bool operator < (const socket_address& rhs) const;
bool operator == (const sockaddr& rhs) const { return *this == *cast_from(&rhs); }
bool operator == (const sockaddr* rhs) const { return *this == *cast_from(rhs); }
bool operator < (const sockaddr& rhs) const { return *this == *cast_from(&rhs); }
bool operator < (const sockaddr* rhs) const { return *this == *cast_from(rhs); }
private:
union {
sockaddr m_sockaddr;
sockaddr_in m_sockaddrInet;
sockaddr_in6 m_sockaddrInet6;
};
};
// Remember to set the AF_INET.
class socket_address_inet {
public:
bool is_any() const { return is_port_any() && is_address_any(); }
bool is_valid() const { return !is_port_any() && !is_address_any(); }
bool is_port_any() const { return port() == 0; }
bool is_address_any() const { return m_sockaddr.sin_addr.s_addr == htonl(INADDR_ANY); }
void clear() { std::memset(this, 0, sizeof(socket_address_inet)); set_family(); }
uint16_t port() const { return ntohs(m_sockaddr.sin_port); }
uint16_t port_n() const { return m_sockaddr.sin_port; }
void set_port(uint16_t p) { m_sockaddr.sin_port = htons(p); }
void set_port_n(uint16_t p) { m_sockaddr.sin_port = p; }
// Should address() return the uint32_t?
in_addr address() const { return m_sockaddr.sin_addr; }
uint32_t address_h() const { return ntohl(m_sockaddr.sin_addr.s_addr); }
uint32_t address_n() const { return m_sockaddr.sin_addr.s_addr; }
std::string address_str() const;
bool address_c_str(char* buf, socklen_t size) const;
void set_address(in_addr a) { m_sockaddr.sin_addr = a; }
void set_address_h(uint32_t a) { m_sockaddr.sin_addr.s_addr = htonl(a); }
void set_address_n(uint32_t a) { m_sockaddr.sin_addr.s_addr = a; }
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
bool set_address_c_str(const char* a);
void set_address_any() { set_port(0); set_address_h(INADDR_ANY); }
sa_family_t family() const { return m_sockaddr.sin_family; }
void set_family() { m_sockaddr.sin_family = AF_INET; }
sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
sockaddr_in* c_sockaddr_inet() { return &m_sockaddr; }
const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
socket_address_inet6 to_mapped_address() const;
bool operator == (const socket_address_inet& rhs) const;
bool operator < (const socket_address_inet& rhs) const;
private:
struct sockaddr_in m_sockaddr;
};
class socket_address_inet6 {
public:
bool is_any() const { return is_port_any() && is_address_any(); }
bool is_valid() const { return !is_port_any() && !is_address_any(); }
bool is_port_any() const { return port() == 0; }
bool is_address_any() const { return std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }
void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
uint16_t port() const { return ntohs(m_sockaddr.sin6_port); }
uint16_t port_n() const { return m_sockaddr.sin6_port; }
void set_port(uint16_t p) { m_sockaddr.sin6_port = htons(p); }
void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; }
in6_addr address() const { return m_sockaddr.sin6_addr; }
const in6_addr* address_ptr() const { return &m_sockaddr.sin6_addr; }
std::string address_str() const;
bool address_c_str(char* buf, socklen_t size) const;
void set_address(in6_addr a) { m_sockaddr.sin6_addr = a; }
bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
bool set_address_c_str(const char* a);
void set_address_any() { set_port(0); set_address(in6addr_any); }
std::string pretty_address_str() const;
sa_family_t family() const { return m_sockaddr.sin6_family; }
void set_family() { m_sockaddr.sin6_family = AF_INET6; }
sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; }
const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddr; }
socket_address normalize_address() const;
bool operator == (const socket_address_inet6& rhs) const;
bool operator < (const socket_address_inet6& rhs) const;
private:
struct sockaddr_in6 m_sockaddr;
};
inline bool
socket_address::is_any() const {
switch (family()) {
case af_inet:
return sa_inet()->is_any();
case af_inet6:
return sa_inet6()->is_any();
default:
return false;
}
}
inline bool
socket_address::is_valid() const {
switch (family()) {
case af_inet:
return sa_inet()->is_valid();
case af_inet6:
return sa_inet6()->is_valid();
default:
return false;
}
}
inline bool
socket_address::is_bindable() const {
switch (family()) {
case af_inet:
return !sa_inet()->is_address_any();
case af_inet6:
return !sa_inet6()->is_address_any();
default:
return false;
}
}
inline bool
socket_address::is_address_any() const {
switch (family()) {
case af_inet:
return sa_inet()->is_address_any();
case af_inet6:
return sa_inet6()->is_address_any();
default:
return true;
}
}
inline uint16_t
socket_address::port() const {
switch (family()) {
case af_inet:
return sa_inet()->port();
case af_inet6:
return sa_inet6()->port();
default:
return 0;
}
}
inline void
socket_address::set_port(uint16_t p) {
switch (family()) {
case af_inet:
return sa_inet()->set_port(p);
case af_inet6:
return sa_inet6()->set_port(p);
default:
break;
}
}
inline std::string
socket_address::address_str() const {
switch (family()) {
case af_inet:
return sa_inet()->address_str();
case af_inet6:
return sa_inet6()->address_str();
default:
return std::string();
}
}
inline bool
socket_address::address_c_str(char* buf, socklen_t size) const {
switch (family()) {
case af_inet:
return sa_inet()->address_c_str(buf, size);
case af_inet6:
return sa_inet6()->address_c_str(buf, size);
default:
return false;
}
}
inline std::string
socket_address::pretty_address_str() const {
switch (family()) {
case af_inet:
return sa_inet()->address_str();
case af_inet6:
return sa_inet6()->pretty_address_str();
case af_unspec:
return std::string("unspec");
default:
return std::string("invalid");
}
}
inline bool
socket_address::set_address_c_str(const char* a) {
if (sa_inet()->set_address_c_str(a)) {
sa_inet()->set_family();
return true;
} else if (sa_inet6()->set_address_c_str(a)) {
sa_inet6()->set_family();
return true;
} else {
return false;
}
}
// Is the zero length really needed, should we require some length?
inline uint32_t
socket_address::length() const {
switch(family()) {
case af_inet:
return sizeof(sockaddr_in);
case af_inet6:
return sizeof(sockaddr_in6);
default:
return 0;
}
}
inline void
socket_address::copy(const socket_address& src, size_t length) {
length = std::min(length, sizeof(socket_address));
std::memset(this, 0, sizeof(socket_address));
std::memcpy(this, &src, length);
}
inline void
socket_address::copy_sockaddr(const sockaddr* src) {
std::memset(this, 0, sizeof(socket_address));
std::memcpy(this, src, socket_address::cast_from(src)->length());
}
inline bool
socket_address::operator == (const socket_address& rhs) const {
if (family() != rhs.family())
return false;
switch (family()) {
case af_inet:
return *sa_inet() == *rhs.sa_inet();
case af_inet6:
return *sa_inet6() == *rhs.sa_inet6();
default:
throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
}
}
inline bool
socket_address::operator < (const socket_address& rhs) const {
if (family() != rhs.family())
return family() < rhs.family();
switch (family()) {
case af_inet:
return *sa_inet() < *rhs.sa_inet();
case af_inet6:
return *sa_inet6() < *rhs.sa_inet6();
default:
throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
}
}
inline std::string
socket_address_inet::address_str() const {
char buf[INET_ADDRSTRLEN];
if (!address_c_str(buf, INET_ADDRSTRLEN))
return std::string();
return std::string(buf);
}
inline bool
socket_address_inet::address_c_str(char* buf, socklen_t size) const {
return inet_ntop(family(), &m_sockaddr.sin_addr, buf, size);
}
inline bool
socket_address_inet::set_address_c_str(const char* a) {
return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
}
inline socket_address_inet6
socket_address_inet::to_mapped_address() const {
uint32_t addr32[4];
addr32[0] = 0;
addr32[1] = 0;
addr32[2] = htonl(0xffff);
addr32[3] = m_sockaddr.sin_addr.s_addr;
socket_address_inet6 sa;
sa.clear();
sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
sa.set_port_n(m_sockaddr.sin_port);
return sa;
}
inline bool
socket_address_inet::operator == (const socket_address_inet& rhs) const {
return
m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
m_sockaddr.sin_port == rhs.m_sockaddr.sin_port;
}
inline bool
socket_address_inet::operator < (const socket_address_inet& rhs) const {
return
m_sockaddr.sin_addr.s_addr < rhs.m_sockaddr.sin_addr.s_addr ||
(m_sockaddr.sin_addr.s_addr == rhs.m_sockaddr.sin_addr.s_addr &&
m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
}
inline std::string
socket_address_inet6::address_str() const {
char buf[INET6_ADDRSTRLEN];
if (!address_c_str(buf, INET6_ADDRSTRLEN))
return std::string();
return std::string(buf);
}
inline bool
socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
}
inline bool
socket_address_inet6::set_address_c_str(const char* a) {
return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
}
inline std::string
socket_address_inet6::pretty_address_str() const {
char buf[INET6_ADDRSTRLEN + 2 + 6];
if (inet_ntop(family(), &m_sockaddr.sin6_addr, buf + 1, INET6_ADDRSTRLEN) == NULL)
return std::string();
buf[0] = '[';
char* last_char = (char*)std::memchr(buf + 1, 0, INET6_ADDRSTRLEN);
// TODO: Throw exception here.
if (last_char == NULL || last_char >= buf + 1 + INET6_ADDRSTRLEN)
throw std::logic_error("inet_ntop for inet6 returned bad buffer");
*(last_char++) = ']';
if (!is_port_any()) {
if (snprintf(last_char, 7, ":%" PRIu16, port()) == -1)
return std::string("error"); // TODO: Throw here.
} else {
*last_char = '\0';
}
return std::string(buf);
}
inline socket_address
socket_address_inet6::normalize_address() const {
const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) {
socket_address addr4;
addr4.sa_inet()->set_family();
addr4.sa_inet()->set_address_n(addr32[3]);
addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port);
return addr4;
}
return *reinterpret_cast<const socket_address*>(this);
}
inline bool
socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
return
memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 &&
m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port;
}
inline bool
socket_address_inet6::operator < (const socket_address_inet6& rhs) const {
int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr));
return
addr_comp < 0 ||
(addr_comp == 0 ||
m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
}
}
#endif
+42
View File
@@ -0,0 +1,42 @@
-- the "rtorrent" table is passed in by the C++ code, modify and
-- return it for loading.
local args = {...}
local rtorrent = args[1]
-- Autocall
-- Allows syntax like `rtorrent.autocall.system.hostname()`
local mt = {}
function mt.__call (t, ...)
name = table.concat(rawget(t, "__namestack"), ".")
success, ret = pcall(rtorrent.call, name, ...)
if not success then error(name..": "..ret, 2) end
return ret
end
function mt.__index (t, key)
ns = rawget(t, "__namestack") or {}
table.insert(ns, key)
return setmetatable({__namestack=ns}, mt)
end
rtorrent["autocall"] = setmetatable({}, mt)
-- Autocall-config Same as autocall, but passes an empty first target
-- implicitly, for syntax like `rtorrent.autocall_config.session.directory.set("/tmp/")`
local mt = {}
function mt.__call (t, ...)
name = table.concat(rawget(t, "__namestack"), ".")
success, ret = pcall(rtorrent.call, name, "", ...)
if not success then error(name..": "..ret, 2) end
return ret
end
function mt.__index (t, key)
ns = rawget(t, "__namestack")
if ns == nil then
if _G[key] ~= nil then return _G[key] end
ns = {}
end
table.insert(ns, key)
return setmetatable({__namestack=ns}, mt)
end
rtorrent["autocall_config"] = setmetatable({}, mt)
return rtorrent
+128 -1
View File
@@ -118,6 +118,19 @@ AC_DEFUN([TORRENT_WITHOUT_KQUEUE], [
])
AC_DEFUN([TORRENT_WITHOUT_VARIABLE_FDSET], [
AC_ARG_WITH(variable-fdset,
AS_HELP_STRING([--without-variable-fdset],[do not use non-portable variable sized fd_set's]),
[
if test "$withval" = "yes"; then
AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size)
fi
], [
AC_DEFINE(USE_VARIABLE_FDSET, 1, defined when we allow the use of fd_set's of any size)
])
])
AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
AC_MSG_CHECKING(for fallocate)
@@ -157,6 +170,121 @@ AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [
])
])
AC_DEFUN([TORRENT_CHECK_STATVFS], [
AC_CHECK_HEADERS(sys/vfs.h sys/statvfs.h sys/statfs.h)
AC_MSG_CHECKING(for statvfs)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#if HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#if HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
]], [[
struct statvfs s; fsblkcnt_t c;
statvfs("", &s);
fstatvfs(0, &s);
]])],[
AC_DEFINE(FS_STAT_FD, [fstatvfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
AC_DEFINE(FS_STAT_FN, [statvfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
AC_DEFINE(FS_STAT_STRUCT, [struct statvfs], Type of second argument to statfs function)
AC_DEFINE(FS_STAT_SIZE_TYPE, [unsigned long], Type of block size member in stat struct)
AC_DEFINE(FS_STAT_COUNT_TYPE, [fsblkcnt_t], Type of block count member in stat struct)
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_frsize)], Determine the block size)
AC_MSG_RESULT(ok)
have_stat_vfs=yes
],[
AC_MSG_RESULT(no)
have_stat_vfs=no
])
])
AC_DEFUN([TORRENT_CHECK_STATFS], [
AC_CHECK_HEADERS(sys/statfs.h sys/param.h sys/mount.h)
AC_MSG_CHECKING(for statfs)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#if HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
]], [[
struct statfs s;
statfs("", &s);
fstatfs(0, &s);
]])],[
AC_DEFINE(FS_STAT_FD, [fstatfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
AC_DEFINE(FS_STAT_FN, [statfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
AC_DEFINE(FS_STAT_STRUCT, [struct statfs], Type of second argument to statfs function)
AC_DEFINE(FS_STAT_SIZE_TYPE, [long], Type of block size member in stat struct)
AC_DEFINE(FS_STAT_COUNT_TYPE, [long], Type of block count member in stat struct)
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_bsize)], Determine the block size)
AC_MSG_RESULT(ok)
have_stat_vfs=yes
],[
AC_MSG_RESULT(no)
have_stat_vfs=no
])
])
AC_DEFUN([TORRENT_DISABLED_STATFS], [
AC_DEFINE(FS_STAT_FD, [(errno = ENOSYS) == 0], Function to determine filesystem stats from fd)
AC_DEFINE(FS_STAT_FN, [(errno = ENOSYS) == 0], Function to determine filesystem stats from filename)
AC_DEFINE(FS_STAT_STRUCT, [struct {blocksize_type f_bsize; blockcount_type f_bavail;}], Type of second argument to statfs function)
AC_DEFINE(FS_STAT_SIZE_TYPE, [int], Type of block size member in stat struct)
AC_DEFINE(FS_STAT_COUNT_TYPE, [int], Type of block count member in stat struct)
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(4096)], Determine the block size)
AC_MSG_RESULT(No filesystem stats available)
])
AC_DEFUN([TORRENT_WITHOUT_STATVFS], [
AC_ARG_WITH(statvfs,
AS_HELP_STRING([--without-statvfs],[don't try to use statvfs to find free diskspace]),
[
if test "$withval" = "yes"; then
TORRENT_CHECK_STATVFS
else
have_stat_vfs=no
fi
],
[
TORRENT_CHECK_STATVFS
])
])
AC_DEFUN([TORRENT_WITHOUT_STATFS], [
AC_ARG_WITH(statfs,
AS_HELP_STRING([--without-statfs],[don't try to use statfs to find free diskspace]),
[
if test "$have_stat_vfs" = "no"; then
if test "$withval" = "yes"; then
TORRENT_CHECK_STATFS
else
TORRENT_DISABLED_STATFS
fi
fi
],
[
if test "$have_stat_vfs" = "no"; then
TORRENT_CHECK_STATFS
if test "$have_stat_vfs" = "no"; then
TORRENT_DISABLED_STATFS
fi
fi
])
])
AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
AC_ARG_WITH(address-space,
AS_HELP_STRING([--with-address-space=MB],[change the default address space size [[default=1024mb]]]),
@@ -284,7 +412,6 @@ AC_DEFUN([TORRENT_WITH_LUA], [
AX_LUA_LIBS
AX_LUA_HEADERS
AC_DEFINE(HAVE_LUA, 1, Use LUA.)
AC_DEFINE(LUA_DATADIR, [PACKAGE_DATADIR "/lua"], [LUA data directory])
LIBS="$LIBS $LUA_LIB"
CXXFLAGS="$CXXFLAGS $LUA_INCLUDE"
fi
+1 -3
View File
@@ -23,15 +23,13 @@ AC_DEFUN([TORRENT_WITH_SYSROOT], [
AC_DEFUN([TORRENT_REMOVE_UNWANTED],
[
AC_REQUIRE([AC_PROG_GREP])
values_to_check=`for i in $2; do echo $i; done`
unwanted_values=`for i in $3; do echo $i; done`
if test -z "${unwanted_values}"; then
$1="$2"
else
result=`echo "${values_to_check}" | $GREP -Fvx -- "${unwanted_values}" | $GREP -v '^$'`
# join with spaces, squeeze repeats, and trim trailing space
$1=$(printf '%s\n' "$result" | tr '\n' ' ' | sed 's/ */ /g; s/ *$//')
$1=$(echo "$result" | tr -d '\n')
fi
])
+8 -1
View File
@@ -5,6 +5,12 @@ rtorrent_LDADD = libsub_root.a @PTHREAD_LIBS@
rtorrent_SOURCES = main.cc
libsub_root_a_SOURCES = \
core/curl_get.cc \
core/curl_get.h \
core/curl_socket.cc \
core/curl_socket.h \
core/curl_stack.cc \
core/curl_stack.h \
core/dht_manager.cc \
core/dht_manager.h \
core/download.cc \
@@ -13,6 +19,7 @@ libsub_root_a_SOURCES = \
core/download_factory.h \
core/download_list.cc \
core/download_list.h \
core/download_slot_map.h \
core/download_store.cc \
core/download_store.h \
core/http_queue.cc \
@@ -195,4 +202,4 @@ libsub_root_a_SOURCES = \
thread_worker.h
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -DPACKAGE_DATADIR=\"$(pkgdatadir)\"
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)
+28 -20
View File
@@ -6,7 +6,9 @@
#include <netdb.h>
#include <unistd.h>
#include <rak/file_stat.h>
#include <rak/error_number.h>
#include <rak/path.h>
#include <rak/socket_address.h>
#include <rak/string_manip.h>
#include <rak/regex.h>
#include <torrent/rate.h>
@@ -102,19 +104,22 @@ apply_d_change_link(core::Download* download, const torrent::Object::list_type&
switch (changeType) {
case 0:
if (symlink(target.c_str(), link.c_str()) == -1)
lt_log_print(torrent::LOG_TORRENT_WARN, "create_link failed: %s", std::strerror(errno));
if (symlink(target.c_str(), link.c_str()) == -1){
lt_log_print(torrent::LOG_TORRENT_WARN, "create_link failed: %s",
rak::error_number::current().c_str());
}
break;
case 1:
{
rak::file_stat fileStat;
errno = 0;
if (!fileStat.update_link(link) || !fileStat.is_link() || unlink(link.c_str()) == -1)
lt_log_print(torrent::LOG_TORRENT_WARN, "delete_link failed: %s", std::strerror(errno));
rak::error_number::clear_global();
if (!fileStat.update_link(link) || !fileStat.is_link() ||
unlink(link.c_str()) == -1){
lt_log_print(torrent::LOG_TORRENT_WARN, "delete_link failed: %s",
rak::error_number::current().c_str());
}
break;
}
default:
@@ -132,7 +137,7 @@ apply_d_delete_tied(core::Download* download) {
return torrent::Object();
if (::unlink(rak::path_expand(tie).c_str()) == -1)
control->core()->push_log_std("Could not unlink tied file: " + std::string(std::strerror(errno)));
control->core()->push_log_std("Could not unlink tied file: " + std::string(rak::error_number::current().c_str()));
rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(download));
return torrent::Object();
@@ -260,12 +265,12 @@ retrieve_d_custom_map(core::Download* download, bool keys_only, const torrent::O
throw torrent::bencode_error("d.custom.keys/items takes no arguments.");
torrent::Object result = keys_only ? torrent::Object::create_list() : torrent::Object::create_map();
torrent::Object::map_type& entries = download->bencode()->get_key("rtorrent").get_key("custom").as_map();
for (const auto& entry : download->bencode()->get_key("rtorrent").get_key("custom").as_map())
if (keys_only)
result.as_list().push_back(entry.first);
else
result.as_map()[entry.first] = entry.second;
for (torrent::Object::map_type::const_iterator itr = entries.begin(), last = entries.end(); itr != last; itr++) {
if (keys_only) result.as_list().push_back(itr->first);
else result.as_map()[itr->first] = itr->second;
}
return result;
}
@@ -348,23 +353,25 @@ f_multicall(core::Download* download, const torrent::Object::list_type& args) {
bool use_regex = true;
if (args.front().is_list())
for (const auto& o : args.front().as_list())
regex_list.push_back(o.as_string_c());
std::transform(args.front().as_list().begin(), args.front().as_list().end(),
std::back_inserter(regex_list),
std::bind(&torrent::Object::as_string_c, std::placeholders::_1));
else if (args.front().is_string() && !args.front().as_string().empty())
regex_list.push_back(args.front().as_string());
else
use_regex = false;
for (const auto& file : *download->file_list()) {
for (torrent::FileList::const_iterator itr = download->file_list()->begin(), last = download->file_list()->end(); itr != last; itr++) {
if (use_regex &&
std::none_of(regex_list.begin(), regex_list.end(), [&file](const auto& r) { return r(file->path()->as_string()); }))
std::find_if(regex_list.begin(), regex_list.end(),
std::bind(&rak::regex::operator(), std::placeholders::_1, (*itr)->path()->as_string())) == regex_list.end())
continue;
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++) {
const std::string& cmd = cItr->as_string();
row.push_back(rpc::parse_command(rpc::make_target(file.get()), cmd.c_str(), cmd.c_str() + cmd.size()).first);
row.push_back(rpc::parse_command(rpc::make_target(itr->get()), cmd.c_str(), cmd.c_str() + cmd.size()).first);
}
}
@@ -414,13 +421,14 @@ p_multicall(core::Download* download, const torrent::Object::list_type& args) {
torrent::Object resultRaw = torrent::Object::create_list();
torrent::Object::list_type& result = resultRaw.as_list();
for (const auto& connection : *download->connection_list()) {
for (torrent::ConnectionList::const_iterator itr = download->connection_list()->begin(), last = download->connection_list()->end();
itr != last; itr++) {
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++) {
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);
row.push_back(rpc::parse_command(rpc::make_target(*itr), cmd.c_str(), cmd.c_str() + cmd.size()).first);
}
}
+8 -6
View File
@@ -25,9 +25,9 @@ static std::vector<std::pair<const char*, int>> object_storage_flags = {
static int
object_storage_parse_flag(const std::string& flag) {
for (auto [n, f] : object_storage_flags)
if (n == flag)
return f;
for (auto f : object_storage_flags)
if (f.first == flag)
return f.second;
throw torrent::input_error("unknown flag");
}
@@ -380,11 +380,13 @@ system_method_set_key(const torrent::Object::list_type& args) {
torrent::Object
system_method_list_keys(const torrent::Object::string_type& args) {
const torrent::Object::map_type& multi_cmd = control->object_storage()->get_str(args).as_map();
torrent::Object rawResult = torrent::Object::create_list();
torrent::Object::list_type& result = rawResult.as_list();
for (const auto& itr : control->object_storage()->get_str(args).as_map())
result.push_back(itr.first);
for (torrent::Object::map_const_iterator itr = multi_cmd.begin(), last = multi_cmd.end(); itr != last; itr++)
result.push_back(itr->first);
return rawResult;
}
@@ -411,7 +413,7 @@ initialize_command_dynamic() {
// Keep these for future use when we deprecate more commands.
CMD2_VAR_BOOL ("method.use_deprecated", false);
CMD2_VAR_VALUE ("method.use_intermediate", 3);
CMD2_VAR_VALUE ("method.use_intermediate", 0);
CMD2_ANY_LIST ("method.insert", std::bind(&system_method_insert, std::placeholders::_2));
CMD2_ANY_LIST ("method.insert.value", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_value_type));
+23 -21
View File
@@ -25,7 +25,7 @@
torrent::Object
apply_on_ratio(const torrent::Object& rawArgs) {
auto& group_name = rawArgs.as_string();
auto view_itr = control->view_manager()->find(rpc::commands.call("group." + group_name + ".view", rpc::make_target()).as_string());
auto view_itr = control->view_manager()->find(rpc::commands.call("group2." + group_name + ".view", rpc::make_target()).as_string());
if (view_itr == control->view_manager()->end())
throw torrent::input_error("Could not find view.");
@@ -33,9 +33,9 @@ apply_on_ratio(const torrent::Object& rawArgs) {
// first argument: minimum ratio to reach
// second argument: minimum upload amount to reach [optional]
// third argument: maximum ratio to reach [optional]
int64_t min_ratio = rpc::commands.call("group." + group_name + ".ratio.min", rpc::make_target()).as_value();
int64_t max_ratio = rpc::commands.call("group." + group_name + ".ratio.max", rpc::make_target()).as_value();
int64_t min_upload = rpc::commands.call("group." + group_name + ".ratio.upload", rpc::make_target()).as_value();
int64_t min_ratio = rpc::commands.call("group2." + group_name + ".ratio.min", rpc::make_target()).as_value();
int64_t max_ratio = rpc::commands.call("group2." + group_name + ".ratio.max", rpc::make_target()).as_value();
int64_t min_upload = rpc::commands.call("group2." + group_name + ".ratio.upload", rpc::make_target()).as_value();
std::vector<core::Download*> downloads;
@@ -55,23 +55,23 @@ apply_on_ratio(const torrent::Object& rawArgs) {
auto ratio_command = "group." + group_name + ".ratio.command";
for (const auto& download : downloads)
rpc::commands.call_catch(ratio_command, rpc::make_target(download), torrent::Object(), "Ratio reached, but command failed: ");
for (std::vector<core::Download*>::iterator itr = downloads.begin(), last = downloads.end(); itr != last; itr++)
rpc::commands.call_catch(ratio_command, rpc::make_target(*itr), torrent::Object(), "Ratio reached, but command failed: ");
return torrent::Object();
}
torrent::Object
apply_start_tied() {
for (const auto& download : *control->core()->download_list()) {
if (rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
for (auto itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) {
if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 1)
continue;
rak::file_stat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
if (!tied_to_file.empty() && fs.update(rak::path_expand(tied_to_file)))
rpc::parse_command_single(rpc::make_target(download), "d.try_start=");
rpc::parse_command_single(rpc::make_target(*itr), "d.try_start=");
}
return torrent::Object();
@@ -79,15 +79,15 @@ apply_start_tied() {
torrent::Object
apply_stop_untied() {
for (const auto& download : *control->core()->download_list()) {
if (rpc::call_command_value("d.state", rpc::make_target(download)) == 0)
for (auto itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) {
if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 0)
continue;
rak::file_stat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
if (!tied_to_file.empty() && !fs.update(rak::path_expand(tied_to_file)))
rpc::parse_command_single(rpc::make_target(download), "d.try_stop=");
rpc::parse_command_single(rpc::make_target(*itr), "d.try_stop=");
}
return torrent::Object();
@@ -95,12 +95,12 @@ apply_stop_untied() {
torrent::Object
apply_close_untied() {
for (const auto& download : *control->core()->download_list()) {
for (auto itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) {
rak::file_stat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr));
if (rpc::call_command_value("d.ignore_commands", rpc::make_target(download)) == 0 && !tied_to_file.empty() && !fs.update(rak::path_expand(tied_to_file)))
rpc::parse_command_single(rpc::make_target(download), "d.try_close=");
if (rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) == 0 && !tied_to_file.empty() && !fs.update(rak::path_expand(tied_to_file)))
rpc::parse_command_single(rpc::make_target(*itr), "d.try_close=");
}
return torrent::Object();
@@ -234,7 +234,9 @@ d_multicall(const torrent::Object::list_type& args) {
// Add some pre-parsing of the commands, so we don't spend time
// parsing and searching command map for every single call.
std::vector<core::Download*> dlist((*view_itr)->begin_visible(), (*view_itr)->end_visible());
std::vector<core::Download*> dlist((*view_itr)->size_visible());
std::copy((*view_itr)->begin_visible(), (*view_itr)->end_visible(), dlist.data());
torrent::Object resultRaw = torrent::Object::create_list();
torrent::Object::list_type& result = resultRaw.as_list();
@@ -273,14 +275,14 @@ d_multicall_filtered(const torrent::Object::list_type& args) {
torrent::Object::list_type& result = resultRaw.as_list();
++arg; // skip to first command
for (const auto& item : dlist) {
for (core::View::iterator item = dlist.begin(); item != dlist.end(); ++item) {
// Add empty row to result
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
// Call the provided commands and assemble their results
for (torrent::Object::list_const_iterator command = arg; command != args.end(); command++) {
auto& cmdstr = command->as_string();
row.push_back(rpc::parse_command(rpc::make_target(item), cmdstr.c_str(), cmdstr.c_str() + cmdstr.size()).first);
row.push_back(rpc::parse_command(rpc::make_target(*item), cmdstr.c_str(), cmdstr.c_str() + cmdstr.size()).first);
}
}
+2 -2
View File
@@ -74,8 +74,8 @@ apply_f_path_components(torrent::File* file) {
torrent::Object resultRaw = torrent::Object::create_list();
torrent::Object::list_type& result = resultRaw.as_list();
for (const auto& itr : *file->path())
result.push_back(itr);
for (torrent::Path::const_iterator itr = file->path()->begin(), last = file->path()->end(); itr != last; itr++)
result.push_back(*itr);
return resultRaw;
}
+2 -1
View File
@@ -180,7 +180,8 @@ apply_cg_insert(const std::string& arg) {
if (rpc::parse_whole_value_nothrow(arg.c_str(), &dummy))
throw torrent::input_error("Cannot use a value string as choke group name.");
if (arg.empty() || std::any_of(cg_list_hack.begin(), cg_list_hack.end(), [&arg](auto cg) { return arg == cg->name(); }))
if (arg.empty() ||
std::find_if(cg_list_hack.begin(), cg_list_hack.end(), [&arg](torrent::choke_group* cg) { return arg == cg->name(); }) != cg_list_hack.end())
throw torrent::input_error("Duplicate name for choke group.");
cg_list_hack.push_back(new torrent::choke_group());
+34
View File
@@ -1,3 +1,37 @@
// 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>
#include "config.h"
#include <torrent/exceptions.h>
+12 -9
View File
@@ -100,21 +100,24 @@ void initialize_commands();
CMD2_ANY(key, std::bind(&rpc::command_function_call_object, torrent::Object(torrent::raw_string::from_c_str(cmds)), \
std::placeholders::_1, std::placeholders::_2));
#define CMD2_REDIRECT(from_key, to_key) \
#define CMD2_REDIRECT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_NO_EXPORT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_MUTABLE(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc);
#define CMD2_REDIRECT_STR(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc);
#define CMD2_REDIRECT_STR_NO_EXPORT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, 0);
#define CMD2_REDIRECT_GENERIC(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_GENERIC_NO_EXPORT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_no_target | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_FILE(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_file_target | rpc::CommandMap::flag_dont_delete);
#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);
#define CMD2_REDIRECT_GENERIC_STR(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, \
rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_no_target);
#define CMD2_REDIRECT_GENERIC_STR_NO_EXPORT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, \
rpc::CommandMap::flag_no_target);
//
// Conversion of return types:
+31 -19
View File
@@ -12,7 +12,6 @@
#include <torrent/chunk_manager.h>
#include <torrent/data/file_manager.h>
#include <torrent/data/chunk_utils.h>
#include <torrent/utils/chrono.h>
#include <torrent/utils/option_strings.h>
#include "core/download.h"
@@ -35,10 +34,11 @@ typedef torrent::FileManager FM_t;
torrent::Object
apply_pieces_stats_total_size() {
uint64_t size = 0;
core::DownloadList* d_list = control->core()->download_list();
for (const auto& d : *control->core()->download_list())
if (d->is_active())
size += d->file_list()->size_bytes();
for (core::DownloadList::iterator itr = d_list->begin(), last = d_list->end(); itr != last; itr++)
if ((*itr)->is_active())
size += (*itr)->file_list()->size_bytes();
return size;
}
@@ -116,22 +116,34 @@ group_insert(const torrent::Object::list_type& args) {
"schedule_remove2=group." + name + ".ratio"));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.command", "simple",
"d.try_close= ;d.ignore_commands.set=1"));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".view", "string", view));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.min", "value", (int64_t)200));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.max", "value", (int64_t)300));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.upload", "value", (int64_t)20 << 20));
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".view", "string", view));
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.min", "value", (int64_t)200));
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.max", "value", (int64_t)300));
rpc::commands.call("method.insert", rpc::create_object_list("group2." + name + ".ratio.upload", "value", (int64_t)20 << 20));
if (rpc::call_command_value("method.use_intermediate") == 3) {
// Cleaned up in 0.16.1:
if (rpc::call_command_value("method.use_intermediate") == 1) {
// Deprecated in 0.7.0:
CMD2_REDIRECT_MUTABLE("group2." + name + ".view", "group." + name + ".view");
CMD2_REDIRECT_MUTABLE("group2." + name + ".view.set", "group." + name + ".view.set");
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.min", "group." + name + ".ratio.min");
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.min.set", "group." + name + ".ratio.min.set");
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.max", "group." + name + ".ratio.max");
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.max.set", "group." + name + ".ratio.max.set");
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.upload", "group." + name + ".ratio.upload");
CMD2_REDIRECT_MUTABLE("group2." + name + ".ratio.upload.set", "group." + name + ".ratio.upload.set");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".view", "group2." + name + ".view");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".view.set", "group2." + name + ".view.set");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.min", "group2." + name + ".ratio.min");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.min.set", "group2." + name + ".ratio.min.set");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.max", "group2." + name + ".ratio.max");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.max.set", "group2." + name + ".ratio.max.set");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.upload", "group2." + name + ".ratio.upload");
CMD2_REDIRECT_GENERIC_STR("group." + name + ".ratio.upload.set", "group2." + name + ".ratio.upload.set");
} if (rpc::call_command_value("method.use_intermediate") == 2) {
// Deprecated in 0.7.0:
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view", "group2." + name + ".view");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".view.set", "group2." + name + ".view.set");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.min", "group2." + name + ".ratio.min");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.min.set", "group2." + name + ".ratio.min.set");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.max", "group2." + name + ".ratio.max");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.max.set", "group2." + name + ".ratio.max.set");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.upload", "group2." + name + ".ratio.upload");
CMD2_REDIRECT_GENERIC_STR_NO_EXPORT("group." + name + ".ratio.upload.set", "group2." + name + ".ratio.upload.set");
}
return name;
@@ -236,7 +248,7 @@ initialize_command_local() {
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");
CMD2_REDIRECT_GENERIC_NO_EXPORT("system.shutdown", "system.shutdown.normal");
CMD2_ANY ("system.cwd", std::bind(&system_get_cwd));
CMD2_ANY_STRING ("system.cwd.set", std::bind(&system_set_cwd, std::placeholders::_2));
+6 -5
View File
@@ -108,18 +108,19 @@ apply_log(const torrent::Object::string_type& arg, int logType) {
torrent::Object
log_vmmap_dump(const std::string& str) {
core::DownloadList* d_list = control->core()->download_list();
std::vector<torrent::vm_mapping> all_mappings;
for (const auto& d : *control->core()->download_list()) {
std::vector<torrent::vm_mapping> tmp_mappings = torrent::chunk_list_mapping(d->download());
for (core::DownloadList::iterator itr = d_list->begin(), last = d_list->end(); itr != last; itr++) {
std::vector<torrent::vm_mapping> tmp_mappings = torrent::chunk_list_mapping((*itr)->download());
all_mappings.insert(all_mappings.end(), tmp_mappings.begin(), tmp_mappings.end());
all_mappings.insert(all_mappings.end(), tmp_mappings.begin(), tmp_mappings.end());
}
FILE* log_file = fopen(str.c_str(), "w");
for (auto& all_mapping : all_mappings) {
fprintf(log_file, "%8p-%8p [%5llxk]\n", all_mapping.ptr, (char*)all_mapping.ptr + all_mapping.length, (long long unsigned int)(all_mapping.length / 1024));
for (std::vector<torrent::vm_mapping>::iterator itr = all_mappings.begin(), last = all_mappings.end(); itr != last; itr++) {
fprintf(log_file, "%8p-%8p [%5llxk]\n", itr->ptr, (char*)itr->ptr + itr->length, (long long unsigned int)(itr->length / 1024));
}
fclose(log_file);
+105 -100
View File
@@ -5,18 +5,16 @@
#include <unistd.h>
#include <rak/address_info.h>
#include <rak/path.h>
#include <torrent/connection_manager.h>
#include <torrent/tracker/tracker.h>
#include <torrent/torrent.h>
#include <torrent/rate.h>
#include <torrent/data/file_manager.h>
#include <torrent/download/resource_manager.h>
#include <torrent/net/http_stack.h>
#include <torrent/net/network_config.h>
#include <torrent/net/network_manager.h>
#include <torrent/net/socket_address.h>
#include <torrent/tracker/tracker.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "core/curl_stack.h"
#include "core/download.h"
#include "core/manager.h"
#include "rpc/scgi.h"
@@ -30,18 +28,18 @@
torrent::Object
apply_encryption(const torrent::Object::list_type& args) {
uint32_t options_mask = torrent::net::NetworkConfig::encryption_none;
uint32_t options_mask = torrent::ConnectionManager::encryption_none;
for (const auto& arg : args) {
uint32_t opt = torrent::option_find_string(torrent::OPTION_ENCRYPTION, arg.as_string().c_str());
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
uint32_t opt = torrent::option_find_string(torrent::OPTION_ENCRYPTION, itr->as_string().c_str());
if (opt == torrent::net::NetworkConfig::encryption_none)
options_mask = torrent::net::NetworkConfig::encryption_none;
if (opt == torrent::ConnectionManager::encryption_none)
options_mask = torrent::ConnectionManager::encryption_none;
else
options_mask |= opt;
}
torrent::config::network_config()->set_encryption_options(options_mask);
torrent::connection_manager()->set_encryption_options(options_mask);
return torrent::Object();
}
@@ -53,7 +51,7 @@ apply_tos(const torrent::Object::string_type& arg) {
if (!rpc::parse_whole_value_nothrow(arg.c_str(), &value, 16, 1))
value = torrent::option_find_string(torrent::OPTION_IP_TOS, arg.c_str());
torrent::config::network_config()->set_priority(value);
torrent::connection_manager()->set_priority(value);
return torrent::Object();
}
@@ -61,20 +59,45 @@ apply_tos(const torrent::Object::string_type& arg) {
torrent::Object apply_encoding_list(const std::string& arg) { torrent::encoding_list()->push_back(arg); return torrent::Object(); }
void
initialize_rpc_handlers() {
rpc::rpc.initialize_handlers();
initialize_rpc() {
rpc::rpc.initialize();
rpc::rpc.slot_find_download() = [](const char* hash) {
return control->core()->download_list()->find_hex_ptr(hash);
};
rpc::rpc.slot_find_file() = [](core::Download* d, uint32_t index) -> torrent::File* {
if (index >= d->file_list()->size_files())
throw torrent::input_error("invalid parameters: index not found");
return (*d->file_list())[index].get();
};
rpc::rpc.slot_find_tracker() = [](core::Download* d, uint32_t index) -> torrent::tracker::Tracker {
if (index >= d->tracker_controller().size())
throw torrent::input_error("invalid parameters: index not found");
// TODO: This should be rewritten to check if the tracker is valid and use a different
// function.
return d->tracker_controller().at(index);
};
rpc::rpc.slot_find_peer() = [](core::Download* d, const torrent::HashString& hash) -> torrent::Peer* {
auto itr = d->connection_list()->find(hash.c_str());
if (itr == d->connection_list()->end())
throw torrent::input_error("invalid parameters: hash not found");
return *itr;
};
unsigned int count = 0;
for (const auto& [name, cmd] : rpc::commands) {
if (!(cmd.m_flags & rpc::CommandMap::flag_public_rpc))
for (rpc::CommandMap::const_iterator itr = rpc::commands.begin(), last = rpc::commands.end(); itr != last; itr++, count++) {
if (!(itr->second.m_flags & rpc::CommandMap::flag_public_rpc))
continue;
rpc::rpc.insert_command(name.c_str(), cmd.m_parm, cmd.m_doc);
++count;
rpc::rpc.insert_command(itr->first.c_str(), itr->second.m_parm, itr->second.m_doc);
}
lt_log_print(torrent::LOG_RPC_EVENTS, "RPC manager initialized with %u functions.", count);
lt_log_print(torrent::LOG_RPC_EVENTS, "RPC initialized with %u functions.", count);
}
torrent::Object
@@ -82,12 +105,13 @@ apply_scgi(const std::string& arg, int type) {
if (worker_thread->scgi() != NULL)
throw torrent::input_error("SCGI already enabled.");
initialize_rpc_handlers();
initialize_rpc();
rpc::SCgi* scgi = new rpc::SCgi;
rak::address_info* ai = NULL;
torrent::sa_unique_ptr sa;
rak::socket_address sa;
rak::socket_address* saPtr;
try {
int port, err;
@@ -98,17 +122,17 @@ apply_scgi(const std::string& arg, int type) {
switch (type) {
case 1:
if (std::sscanf(arg.c_str(), ":%i%c", &port, &dummy) == 1) {
sa = torrent::sa_make_inet();
sa.sa_inet()->clear();
saPtr = &sa;
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is open to any address and is a security risk");
} else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2 ||
std::sscanf(arg.c_str(), "[%64[^]]]:%i%c", address, &port, &dummy) == 2) { // [xx::xx]:port format
if ((err = rak::address_info::get_address_info(address, PF_UNSPEC, SOCK_STREAM, &ai)) != 0)
if ((err = rak::address_info::get_address_info(address,PF_UNSPEC, SOCK_STREAM, &ai)) != 0)
throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + ".");
sa = torrent::sa_copy(ai->c_addrinfo()->ai_addr);
saPtr = ai->address();
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is bound to an address and might be a security risk");
@@ -119,8 +143,8 @@ apply_scgi(const std::string& arg, int type) {
if (port <= 0 || port >= (1 << 16))
throw torrent::input_error("Invalid port number.");
torrent::sap_set_port(sa, port);
scgi->open_port(sa.get(), torrent::sap_length(sa), rpc::call_command_value("network.scgi.dont_route"));
saPtr->set_port(port);
scgi->open_port(saPtr, saPtr->length(), rpc::call_command_value("network.scgi.dont_route"));
break;
@@ -165,11 +189,9 @@ apply_xmlrpc_dialect(const std::string& arg) {
void
initialize_command_network() {
auto cm = torrent::connection_manager();
auto file_manager = torrent::file_manager();
auto http_stack = torrent::net_thread::http_stack();
auto nw_config = torrent::config::network_config();
auto nw_manager = torrent::runtime::network_manager();
torrent::ConnectionManager* cm = torrent::connection_manager();
torrent::FileManager* fileManager = torrent::file_manager();
core::CurlStack* httpStack = control->core()->http_stack();
CMD2_ANY_STRING ("encoding.add", std::bind(&apply_encoding_list, std::placeholders::_2));
@@ -178,91 +200,74 @@ initialize_command_network() {
CMD2_VAR_BOOL ("network.port_random", true);
CMD2_VAR_STRING ("network.port_range", "6881-6999");
CMD2_ANY ("network.listen.port", [nw_manager](auto, auto) { return nw_manager->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); });
CMD2_ANY ("network.listen.port", std::bind(&torrent::ConnectionManager::listen_port, cm));
CMD2_ANY ("network.listen.backlog", std::bind(&torrent::ConnectionManager::listen_backlog, cm));
CMD2_ANY_VALUE_V ("network.listen.backlog.set", std::bind(&torrent::ConnectionManager::set_listen_backlog, cm, std::placeholders::_2));
CMD2_VAR_BOOL ("protocol.pex", true);
CMD2_ANY_LIST ("protocol.encryption.set", [](auto, auto& args) { return apply_encryption(args); });
CMD2_VAR_BOOL ("protocol.pex", true);
CMD2_ANY_LIST ("protocol.encryption.set", std::bind(&apply_encryption, std::placeholders::_2));
CMD2_VAR_STRING ("protocol.connection.leech", "leech");
CMD2_VAR_STRING ("protocol.connection.seed", "seed");
CMD2_VAR_STRING ("protocol.connection.leech", "leech");
CMD2_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.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");
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); });
CMD2_ANY ("network.http.cacert", std::bind(&core::CurlStack::http_cacert, httpStack));
CMD2_ANY_STRING_V("network.http.cacert.set", std::bind(&core::CurlStack::set_http_cacert, httpStack, std::placeholders::_2));
CMD2_ANY ("network.http.capath", std::bind(&core::CurlStack::http_capath, httpStack));
CMD2_ANY_STRING_V("network.http.capath.set", std::bind(&core::CurlStack::set_http_capath, httpStack, std::placeholders::_2));
CMD2_ANY ("network.http.dns_cache_timeout", std::bind(&core::CurlStack::dns_timeout, httpStack));
CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", std::bind(&core::CurlStack::set_dns_timeout, httpStack, std::placeholders::_2));
CMD2_ANY ("network.http.current_open", std::bind(&core::CurlStack::active, httpStack));
CMD2_ANY ("network.http.max_open", std::bind(&core::CurlStack::max_active, httpStack));
CMD2_ANY_VALUE_V ("network.http.max_open.set", std::bind(&core::CurlStack::set_max_active, httpStack, std::placeholders::_2));
CMD2_ANY ("network.http.proxy_address", std::bind(&core::CurlStack::http_proxy, httpStack));
CMD2_ANY_STRING_V("network.http.proxy_address.set", std::bind(&core::CurlStack::set_http_proxy, httpStack, std::placeholders::_2));
CMD2_ANY ("network.http.ssl_verify_host", std::bind(&core::CurlStack::ssl_verify_host, httpStack));
CMD2_ANY_VALUE_V ("network.http.ssl_verify_host.set", std::bind(&core::CurlStack::set_ssl_verify_host, httpStack, std::placeholders::_2));
CMD2_ANY ("network.http.ssl_verify_peer", std::bind(&core::CurlStack::ssl_verify_peer, httpStack));
CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", std::bind(&core::CurlStack::set_ssl_verify_peer, httpStack, std::placeholders::_2));
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); });
CMD2_ANY ("network.send_buffer.size", std::bind(&torrent::ConnectionManager::send_buffer_size, cm));
CMD2_ANY_VALUE_V ("network.send_buffer.size.set", std::bind(&torrent::ConnectionManager::set_send_buffer_size, cm, std::placeholders::_2));
CMD2_ANY ("network.receive_buffer.size", std::bind(&torrent::ConnectionManager::receive_buffer_size, cm));
CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", std::bind(&torrent::ConnectionManager::set_receive_buffer_size, cm, std::placeholders::_2));
CMD2_ANY_STRING ("network.tos.set", std::bind(&apply_tos, std::placeholders::_2));
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); });
CMD2_ANY ("network.bind_address", std::bind(&core::Manager::bind_address, control->core()));
CMD2_ANY_STRING_V("network.bind_address.set", std::bind(&core::Manager::set_bind_address, control->core(), std::placeholders::_2));
CMD2_ANY ("network.local_address", std::bind(&core::Manager::local_address, control->core()));
CMD2_ANY_STRING_V("network.local_address.set", std::bind(&core::Manager::set_local_address, control->core(), std::placeholders::_2));
CMD2_ANY ("network.proxy_address", std::bind(&core::Manager::proxy_address, control->core()));
CMD2_ANY_STRING_V("network.proxy_address.set", std::bind(&core::Manager::set_proxy_address, control->core(), std::placeholders::_2));
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); });
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); });
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::total_handshakes(); });
CMD2_ANY ("network.open_sockets", [cm](auto, auto) { return cm->size(); });
CMD2_ANY ("network.max_open_sockets", [cm](auto, auto) { return cm->max_size(); });
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", [cm](auto, auto& value) { return cm->set_max_size(value); });
CMD2_ANY ("network.open_files", std::bind(&torrent::FileManager::open_files, fileManager));
CMD2_ANY ("network.max_open_files", std::bind(&torrent::FileManager::max_open_files, fileManager));
CMD2_ANY_VALUE_V ("network.max_open_files.set", std::bind(&torrent::FileManager::set_max_open_files, fileManager, std::placeholders::_2));
CMD2_ANY ("network.total_handshakes", std::bind(&torrent::total_handshakes));
CMD2_ANY ("network.open_sockets", std::bind(&torrent::ConnectionManager::size, cm));
CMD2_ANY ("network.max_open_sockets", std::bind(&torrent::ConnectionManager::max_size, cm));
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", std::bind(&torrent::ConnectionManager::set_max_size, cm, std::placeholders::_2));
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_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); });
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); });
CMD2_VAR_BOOL ("network.rpc.use_xmlrpc", true);
CMD2_VAR_BOOL ("network.rpc.use_jsonrpc", true);
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); });
CMD2_ANY ("network.block.ipv4", std::bind(&torrent::ConnectionManager::is_block_ipv4, cm));
CMD2_ANY_VALUE_V ("network.block.ipv4.set", std::bind(&torrent::ConnectionManager::set_block_ipv4, cm, std::placeholders::_2));
CMD2_ANY ("network.block.ipv6", std::bind(&torrent::ConnectionManager::is_block_ipv6, cm));
CMD2_ANY_VALUE_V ("network.block.ipv6.set", std::bind(&torrent::ConnectionManager::set_block_ipv6, cm, std::placeholders::_2));
CMD2_ANY ("network.prefer.ipv6", std::bind(&torrent::ConnectionManager::is_prefer_ipv6, cm));
CMD2_ANY_VALUE_V ("network.prefer.ipv6.set", std::bind(&torrent::ConnectionManager::set_prefer_ipv6, cm, std::placeholders::_2));
}
+43 -8
View File
@@ -1,9 +1,45 @@
// 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>
#include "config.h"
#include <rak/error_number.h>
#include <rak/path.h>
#include <rak/socket_address.h>
#include <rak/string_manip.h>
#include <torrent/bitfield.h>
#include <torrent/rate.h>
#include <torrent/net/socket_address.h>
#include <torrent/peer/connection_list.h>
#include <torrent/peer/peer.h>
#include <torrent/peer/peer_info.h>
@@ -31,18 +67,17 @@ retrieve_p_id_html(torrent::Peer* peer) {
torrent::Object
retrieve_p_address(torrent::Peer* peer) {
auto sa = peer->peer_info()->socket_address();
auto addr_str = torrent::sa_addr_str(sa);
const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address());
if (sa->sa_family == AF_INET6)
return "[" + addr_str + "]";
return addr_str;
if (addr->family() == rak::socket_address::af_inet6)
return "[" + addr->address_str() + "]";
else
return addr->address_str();
}
torrent::Object
retrieve_p_port(torrent::Peer* peer) {
return torrent::sa_port(peer->peer_info()->socket_address());
return rak::socket_address::cast_from(peer->peer_info()->socket_address())->port();
}
torrent::Object
+46 -19
View File
@@ -1,14 +1,47 @@
// 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>
#include "config.h"
#include <cstdio>
#include <rak/address_info.h>
#include <torrent/throttle.h>
#include <torrent/rate.h>
#include <torrent/download/resource_manager.h>
#include <torrent/net/socket_address.h>
#include "core/manager.h"
#include "ui/root.h"
#include "rak/address_info.h"
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
@@ -24,16 +57,13 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
rak::address_info* ai;
ret = std::sscanf(itr->as_string().c_str(), "%1023[^/]/%d%c", host, &prefixWidth, &dummy);
if (ret < 1 || rak::address_info::get_address_info(host, PF_INET, SOCK_STREAM, &ai) != 0)
throw torrent::input_error("Could not resolve host.");
uint32_t begin, end;
auto sa = torrent::sa_copy(ai->c_addrinfo()->ai_addr);
auto sa_addr = htonl(reinterpret_cast<sockaddr_in*>(sa.get())->sin_addr.s_addr);
begin = end = sa_addr;
rak::socket_address sa;
sa.copy(*ai->address(), ai->length());
begin = end = sa.sa_inet()->address_h();
rak::address_info::free_address_info(ai);
if (ret == 2) {
@@ -41,21 +71,18 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
throw torrent::input_error("Cannot specify both network and range end.");
uint32_t netmask = std::numeric_limits<uint32_t>::max() << (32 - prefixWidth);
if (prefixWidth >= 32 || sa_addr & ~netmask)
if (prefixWidth >= 32 || sa.sa_inet()->address_h() & ~netmask)
throw torrent::input_error("Invalid address/prefix.");
end = sa_addr | ~netmask;
end = sa.sa_inet()->address_h() | ~netmask;
} else if (++itr != args.end()) {
if (rak::address_info::get_address_info(itr->as_string().c_str(), PF_INET, SOCK_STREAM, &ai) != 0)
throw torrent::input_error("Could not resolve host.");
sa = torrent::sa_copy(ai->c_addrinfo()->ai_addr);
sa_addr = htonl(reinterpret_cast<sockaddr_in*>(sa.get())->sin_addr.s_addr);
sa.copy(*ai->address(), ai->length());
rak::address_info::free_address_info(ai);
end = sa_addr;
end = sa.sa_inet()->address_h();
}
// convert to [begin, end) making sure the end doesn't overflow
@@ -167,10 +194,10 @@ initialize_command_throttle() {
CMD2_VAR_VALUE ("throttle.max_downloads.div._val", 1);
CMD2_VAR_VALUE ("throttle.max_downloads.global._val", 0);
CMD2_REDIRECT ("throttle.max_uploads.div", "throttle.max_uploads.div._val");
CMD2_REDIRECT ("throttle.max_uploads.global", "throttle.max_uploads.global._val");
CMD2_REDIRECT ("throttle.max_downloads.div", "throttle.max_downloads.div._val");
CMD2_REDIRECT ("throttle.max_downloads.global", "throttle.max_downloads.global._val");
CMD2_REDIRECT_GENERIC("throttle.max_uploads.div", "throttle.max_uploads.div._val");
CMD2_REDIRECT_GENERIC("throttle.max_uploads.global", "throttle.max_uploads.global._val");
CMD2_REDIRECT_GENERIC("throttle.max_downloads.div", "throttle.max_downloads.div._val");
CMD2_REDIRECT_GENERIC("throttle.max_downloads.global", "throttle.max_downloads.global._val");
CMD2_ANY_VALUE ("throttle.max_uploads.div.set", std::bind(&throttle_update, "throttle.max_uploads.div._val.set", std::placeholders::_2));
CMD2_ANY_VALUE ("throttle.max_uploads.global.set", std::bind(&throttle_update, "throttle.max_uploads.global._val.set", std::placeholders::_2));
+21 -33
View File
@@ -3,7 +3,8 @@
#include <cassert>
#include <cstdio>
#include <netdb.h>
#include <torrent/net/network_config.h>
#include <rak/address_info.h>
#include <rak/error_number.h>
#include <torrent/net/resolver.h>
#include <torrent/tracker/dht_controller.h>
#include <torrent/tracker/tracker.h>
@@ -30,11 +31,11 @@ apply_dht_add_node(const std::string& arg) {
if (!torrent::dht_controller()->is_valid())
throw torrent::input_error("DHT not enabled.");
int port;
int port, ret;
char dummy;
char host[1024];
int ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy);
if (ret == 1)
port = 6881;
@@ -46,18 +47,13 @@ apply_dht_add_node(const std::string& arg) {
assert(std::this_thread::get_id() == torrent::main_thread::thread()->thread_id());
auto host_str = std::string(host);
// TODO: Move this lookup to DhtController.
// Currently discarding SOCK_STREAM.
torrent::this_thread::resolver()->resolve_specific(nullptr, host_str, PF_INET, [host_str, port](torrent::c_sa_shared_ptr sa, int err) {
torrent::this_thread::resolver()->resolve_specific(nullptr, host, PF_INET, [port](torrent::c_sa_shared_ptr sa, int err) {
if (sa == nullptr) {
lt_log_print(torrent::LOG_DHT_ERROR, "dht.add_node : could not resolve host : %s (%s)", gai_strerror(err), host_str.c_str());
lt_log_print(torrent::LOG_DHT_WARN, "Could not resolve host: %s", gai_strerror(err));
return;
}
lt_log_print(torrent::LOG_DHT_CONTROLLER, "dht.add_node : %s", host_str.c_str());
torrent::dht_controller()->add_node(sa.get(), port);
});
@@ -67,22 +63,22 @@ apply_dht_add_node(const std::string& arg) {
torrent::Object
apply_enable_trackers(int64_t arg) {
if (arg == 0) {
for (auto download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.disable(); });
for (auto itr : *control->core()->download_list())
itr->tracker_controller().for_each([](auto& tracker) { tracker.disable(); });
} else if (rpc::call_command_value("trackers.use_udp") == 0) {
for (auto download : *control->core()->download_list()) {
download->tracker_controller().for_each([](auto& tracker) {
if (tracker.type() == torrent::TRACKER_UDP)
tracker.disable();
else
tracker.enable();
});
for (auto itr : *control->core()->download_list()) {
itr->tracker_controller().for_each([](auto& tracker) {
if (tracker.type() == torrent::TRACKER_UDP)
tracker.disable();
else
tracker.enable();
});
}
} else {
for (auto download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.enable(); });
for (auto itr : *control->core()->download_list())
itr->tracker_controller().for_each([](auto& tracker) { tracker.enable(); });
}
return torrent::Object();
@@ -141,18 +137,10 @@ initialize_command_tracker() {
CMD2_VAR_VALUE ("trackers.numwant", -1);
CMD2_VAR_BOOL ("trackers.use_udp", true);
auto dht_manager = control->dht_manager();
CMD2_ANY_STRING_V ("dht.mode.set", std::bind(&core::DhtManager::set_mode, control->dht_manager(), std::placeholders::_2));
CMD2_ANY ("dht.port", std::bind(&torrent::tracker::DhtController::port, torrent::dht_controller()));
CMD2_ANY_VALUE_V ("dht.port.set", [](auto, auto) {
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", std::bind(&torrent::net::NetworkConfig::override_dht_port, torrent::config::network_config()));
CMD2_ANY_VALUE_V ("dht.override_port.set", std::bind(&torrent::net::NetworkConfig::set_override_dht_port, torrent::config::network_config(), std::placeholders::_2));
CMD2_VAR_VALUE ("dht.port", int64_t(6881));
CMD2_ANY_STRING ("dht.add_node", std::bind(&apply_dht_add_node, std::placeholders::_2));
CMD2_ANY ("dht.statistics", std::bind(&core::DhtManager::dht_statistics, dht_manager));
CMD2_ANY ("dht.throttle.name", std::bind(&core::DhtManager::throttle_name, dht_manager));
CMD2_ANY_STRING_V ("dht.throttle.name.set", std::bind(&core::DhtManager::set_throttle_name, dht_manager, std::placeholders::_2));
CMD2_ANY ("dht.statistics", std::bind(&core::DhtManager::dht_statistics, control->dht_manager()));
CMD2_ANY ("dht.throttle.name", std::bind(&core::DhtManager::throttle_name, control->dht_manager()));
CMD2_ANY_STRING_V ("dht.throttle.name.set", std::bind(&core::DhtManager::set_throttle_name, control->dht_manager(), std::placeholders::_2));
}
+41 -44
View File
@@ -75,8 +75,8 @@ apply_view_list() {
torrent::Object rawResult = torrent::Object::create_list();
torrent::Object::list_type& result = rawResult.as_list();
for (auto itr : *control->view_manager())
result.push_back(itr->name());
for (core::ViewManager::const_iterator itr = control->view_manager()->begin(), last = control->view_manager()->end(); itr != last; itr++)
result.push_back((*itr)->name());
return rawResult;
}
@@ -193,18 +193,18 @@ apply_and(rpc::target_type target, const torrent::Object& rawArgs) {
if (rawArgs.type() != torrent::Object::TYPE_LIST)
return as_boolean(rawArgs);
for (const auto& itr : rawArgs.as_list())
if (itr.is_dict_key()) {
if (!as_boolean(rpc::commands.call_command(itr.as_dict_key().c_str(), itr.as_dict_obj(), target)))
for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++)
if (itr->is_dict_key()) {
if (!as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)))
return (int64_t)false;
} else if (itr.is_value()) {
if (!itr.as_value())
} else if (itr->is_value()) {
if (!itr->as_value())
return (int64_t)false;
} else {
// TODO: Switch to new versions that only accept the new command syntax.
if (!as_boolean(rpc::parse_command_single(target, itr.as_string())))
if (!as_boolean(rpc::parse_command_single(target, itr->as_string())))
return (int64_t)false;
}
@@ -216,17 +216,17 @@ apply_or(rpc::target_type target, const torrent::Object& rawArgs) {
if (rawArgs.type() != torrent::Object::TYPE_LIST)
return as_boolean(rawArgs);
for (const auto& itr : rawArgs.as_list())
if (itr.is_dict_key()) {
if (as_boolean(rpc::commands.call_command(itr.as_dict_key().c_str(), itr.as_dict_obj(), target)))
for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++)
if (itr->is_dict_key()) {
if (as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)))
return (int64_t)true;
} else if (itr.is_value()) {
if (itr.as_value())
} else if (itr->is_value()) {
if (itr->as_value())
return (int64_t)true;
} else {
if (as_boolean(rpc::parse_command_single(target, itr.as_string())))
if (as_boolean(rpc::parse_command_single(target, itr->as_string())))
return (int64_t)true;
}
@@ -526,9 +526,9 @@ apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) {
// nice to have a parse_command function that takes list
// iterator...
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());
for (torrent::Object::list_type::const_iterator cmdItr = itr->as_list().begin(), last = itr->as_list().end(); cmdItr != last; cmdItr++)
if (cmdItr->is_string())
rpc::parse_command(target, cmdItr->as_string().c_str(), cmdItr->as_string().c_str() + cmdItr->as_string().size());
return torrent::Object();
@@ -630,26 +630,26 @@ as_vector(const torrent::Object::list_type& args) {
std::vector<int64_t> result;
for (const auto& arg : args) {
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
if (arg.is_value()) {
result.push_back(arg.as_value());
} else if (arg.is_string()) {
result.push_back(rpc::convert_to_value(arg.as_string()));
} else if (arg.is_list()) {
std::vector<int64_t> subResult = as_vector(arg.as_list());
if (itr->is_value()) {
result.push_back(itr->as_value());
} else if (itr->is_string()) {
result.push_back(rpc::convert_to_value(itr->as_string()));
} else if (itr->is_list()) {
std::vector<int64_t> subResult = as_vector(itr->as_list());
result.insert(result.end(), subResult.begin(), subResult.end());
} else {
throw torrent::input_error("Wrong type supplied to as_vector.");
}
}
return result;
}
template <typename Comp>
int64_t
apply_math_basic(const char* name, Comp op, const torrent::Object::list_type& args) {
apply_math_basic(const char* name, const std::function<int64_t(int64_t,int64_t)> op, const torrent::Object::list_type& args) {
int64_t val = 0, rhs = 0;
bool divides = !strcmp(name, "math.div") || !strcmp(name, "math.mod");
@@ -678,9 +678,8 @@ apply_math_basic(const char* name, Comp op, const torrent::Object::list_type& ar
return val;
}
template <typename Comp>
int64_t
apply_arith_basic(Comp op, const torrent::Object::list_type& args) {
apply_arith_basic(const std::function<int64_t(int64_t,int64_t)> op, const torrent::Object::list_type& args) {
if (args.size() == 0)
throw torrent::input_error("Wrong argument count in apply_arith_basic.");
@@ -712,19 +711,20 @@ apply_arith_count(const torrent::Object::list_type& args) {
int64_t val = 0;
for (const auto& arg : args) {
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
switch (arg.type()) {
switch (itr->type()) {
case torrent::Object::TYPE_VALUE:
case torrent::Object::TYPE_STRING:
val++;
break;
case torrent::Object::TYPE_LIST:
val += apply_arith_count(arg.as_list());
val += apply_arith_count(itr->as_list());
break;
default:
throw torrent::input_error("Wrong type supplied to apply_arith_count.");
}
}
return val;
@@ -752,9 +752,9 @@ cmd_status_throttle_names(bool up, const torrent::Object::list_type& args) {
std::vector<std::string> throttle_name_list;
for (const auto& arg : args) {
if (arg.is_string())
throttle_name_list.push_back(arg.as_string());
for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) {
if (itr->is_string())
throttle_name_list.push_back(itr->as_string());
}
if (up)
@@ -825,9 +825,6 @@ initialize_command_ui() {
CMD2_ANY_LIST ("ui.status.throttle.up.set", std::bind(&cmd_status_throttle_names, true, std::placeholders::_2));
CMD2_ANY_LIST ("ui.status.throttle.down.set", std::bind(&cmd_status_throttle_names, false, std::placeholders::_2));
CMD2_ANY ("ui.keymap.style", std::bind(&ui::Root::keymap_style, control->ui()));
CMD2_ANY_STRING_V("ui.keymap.style.set", std::bind(&ui::Root::set_keymap_style, control->ui(), std::placeholders::_2));
// TODO: Add 'option_string' for rtorrent-specific options.
CMD2_VAR_STRING("ui.torrent_list.layout", "full");
@@ -862,13 +859,13 @@ initialize_command_ui() {
CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2));
CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2));
CMD2_ANY_LIST("math.add", [](auto, const auto& args) { return apply_math_basic("math.add", std::plus(), args); });
CMD2_ANY_LIST("math.sub", [](auto, const auto& args) { return apply_math_basic("math.sub", std::minus(), args); });
CMD2_ANY_LIST("math.mul", [](auto, const auto& args) { return apply_math_basic("math.mul", std::multiplies(), args); });
CMD2_ANY_LIST("math.div", [](auto, const auto& args) { return apply_math_basic("math.div", std::divides(), args); });
CMD2_ANY_LIST("math.mod", [](auto, const auto& args) { return apply_math_basic("math.mod", std::modulus(), args); });
CMD2_ANY_LIST("math.min", [](auto, const auto& args) { return apply_arith_basic(std::less(), args); });
CMD2_ANY_LIST("math.max", [](auto, const auto& args) { return apply_arith_basic(std::greater(), args); });
CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, "math.add", std::plus<int64_t>(), std::placeholders::_2));
CMD2_ANY_LIST("math.sub", std::bind(&apply_math_basic, "math.sub", std::minus<int64_t>(), std::placeholders::_2));
CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, "math.mul", std::multiplies<int64_t>(), std::placeholders::_2));
CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, "math.div", std::divides<int64_t>(), std::placeholders::_2));
CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, "math.mod", std::modulus<int64_t>(), std::placeholders::_2));
CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less<int64_t>(), std::placeholders::_2));
CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater<int64_t>(), std::placeholders::_2));
CMD2_ANY_LIST("math.cnt", std::bind(&apply_arith_count, std::placeholders::_2));
CMD2_ANY_LIST("math.avg", std::bind(&apply_arith_other, "average", std::placeholders::_2));
CMD2_ANY_LIST("math.med", std::bind(&apply_arith_other, "median", std::placeholders::_2));
+31 -21
View File
@@ -1,13 +1,11 @@
#include "config.h"
#include "control.h"
#include <unistd.h>
#include <sys/stat.h>
#include <torrent/net/http_stack.h>
#include <torrent/net/network_manager.h>
#include <torrent/connection_manager.h>
#include <torrent/utils/directory_events.h>
#include "core/curl_stack.h"
#include "core/dht_manager.h"
#include "core/download_store.h"
#include "core/http_queue.h"
@@ -28,8 +26,10 @@
#include "rpc/object_storage.h"
#include "ui/root.h"
Control::Control()
: m_ui(new ui::Root()),
#include "control.h"
Control::Control() :
m_ui(new ui::Root()),
m_display(new display::Manager()),
m_input(new input::Manager()),
m_inputStdin(new input::InputEvent(STDIN_FILENO)),
@@ -38,11 +38,11 @@ Control::Control()
m_lua_engine(new rpc::LuaEngine()),
m_directory_events(new torrent::directory_events()) {
m_core = std::make_unique<core::Manager>();
m_view_manager = std::make_unique<core::ViewManager>();
m_dht_manager = std::make_unique<core::DhtManager>();
m_core = new core::Manager();
m_viewManager = new core::ViewManager();
m_dhtManager = new core::DhtManager();
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input.get(), std::placeholders::_1));
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input, std::placeholders::_1));
m_task_shutdown.slot() = std::bind(&Control::handle_shutdown, this);
@@ -50,10 +50,20 @@ Control::Control()
}
Control::~Control() {
m_view_manager.reset();
delete m_inputStdin;
delete m_input;
m_ui.reset();
m_display.reset();
delete m_viewManager;
delete m_ui;
delete m_display;
delete m_core;
delete m_dhtManager;
delete m_directory_events;
delete m_commandScheduler;
delete m_objectStorage;
delete m_lua_engine;
}
void
@@ -63,16 +73,19 @@ 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->http_stack()->set_user_agent(USER_AGENT);
m_core->initialize_second();
m_core->listen_open();
m_core->download_store()->enable(rpc::call_command_value("session.use_lock"));
m_core->set_hashing_view(*m_view_manager->find_throw("hashing"));
m_core->set_hashing_view(*m_viewManager->find_throw("hashing"));
m_ui->init(this);
if(!display::Canvas::daemon())
if(!display::Canvas::daemon()) {
m_inputStdin->insert(torrent::this_thread::poll());
}
}
void
@@ -109,10 +122,7 @@ Control::is_shutdown_completed() {
// Tracker requests can be disowned, so wait for these to
// finish. The edge case of torrent http downloads may delay
// shutdown.
// TODO: We keep http requests in the queue for a while after, so improve this check to ignore
// those.
if (torrent::net_thread::http_stack()->size() != 0 || !core()->http_queue()->empty())
if (!core()->http_stack()->empty() || !core()->http_queue()->empty())
return false;
return torrent::is_inactive();
@@ -126,7 +136,7 @@ Control::handle_shutdown() {
if (worker_thread->is_active())
worker_thread->stop_thread_wait();
torrent::runtime::network_manager()->listen_close();
torrent::connection_manager()->listen_close();
m_directory_events->close();
m_core->shutdown(false);
+22 -23
View File
@@ -3,7 +3,6 @@
#include <atomic>
#include <cinttypes>
#include <memory>
#include <sys/types.h>
#include <torrent/torrent.h>
#include <torrent/utils/scheduler.h>
@@ -56,20 +55,20 @@ public:
void receive_normal_shutdown() { m_shutdownReceived = true; }
void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; }
core::Manager* core() { return m_core.get(); }
core::ViewManager* view_manager() { return m_view_manager.get(); }
core::DhtManager* dht_manager() { return m_dht_manager.get(); }
core::Manager* core() { return m_core; }
core::ViewManager* view_manager() { return m_viewManager; }
core::DhtManager* dht_manager() { return m_dhtManager; }
ui::Root* ui() { return m_ui.get(); }
display::Manager* display() { return m_display.get(); }
input::Manager* input() { return m_input.get(); }
input::InputEvent* input_stdin() { return m_inputStdin.get(); }
ui::Root* ui() { return m_ui; }
display::Manager* display() { return m_display; }
input::Manager* input() { return m_input; }
input::InputEvent* input_stdin() { return m_inputStdin; }
rpc::CommandScheduler* command_scheduler() { return m_commandScheduler.get(); }
rpc::object_storage* object_storage() { return m_objectStorage.get(); }
rpc::LuaEngine* lua_engine() { return m_lua_engine.get(); }
rpc::CommandScheduler* command_scheduler() { return m_commandScheduler; }
rpc::object_storage* object_storage() { return m_objectStorage; }
rpc::LuaEngine* lua_engine() { return m_lua_engine; }
torrent::directory_events* directory_events() { return m_directory_events.get(); }
torrent::directory_events* directory_events() { return m_directory_events; }
uint64_t tick() const { return m_tick; }
void inc_tick() { m_tick++; }
@@ -81,19 +80,19 @@ private:
Control(const Control&);
void operator = (const Control&);
std::unique_ptr<core::Manager> m_core;
std::unique_ptr<core::ViewManager> m_view_manager;
std::unique_ptr<core::DhtManager> m_dht_manager;
core::Manager* m_core;
core::ViewManager* m_viewManager;
core::DhtManager* m_dhtManager;
std::unique_ptr<ui::Root> m_ui;
std::unique_ptr<display::Manager> m_display;
std::unique_ptr<input::Manager> m_input;
std::unique_ptr<input::InputEvent> m_inputStdin;
ui::Root* m_ui;
display::Manager* m_display;
input::Manager* m_input;
input::InputEvent* m_inputStdin;
std::unique_ptr<rpc::CommandScheduler> m_commandScheduler;
std::unique_ptr<rpc::object_storage> m_objectStorage;
std::unique_ptr<rpc::LuaEngine> m_lua_engine;
std::unique_ptr<torrent::directory_events> m_directory_events;
rpc::CommandScheduler* m_commandScheduler;
rpc::object_storage* m_objectStorage;
rpc::LuaEngine* m_lua_engine;
torrent::directory_events* m_directory_events;
uint64_t m_tick{};
+122
View File
@@ -0,0 +1,122 @@
#include "config.h"
#include "core/curl_get.h"
#include <iostream>
#include <curl/curl.h>
#include <curl/easy.h>
#include <torrent/exceptions.h>
#include "globals.h"
#include "core/curl_stack.h"
namespace core {
size_t
curl_get_receive_write(void* data, size_t size, size_t nmemb, void* handle) {
if (!((CurlGet*)handle)->stream()->write((const char*)data, size * nmemb).fail())
return size * nmemb;
else
return 0;
}
CurlGet::CurlGet(CurlStack* s) :
m_stack(s) {
m_task_timeout.slot() = [this]() { receive_timeout(); };
}
CurlGet::~CurlGet() {
close();
}
void
CurlGet::start() {
if (is_busy())
throw torrent::internal_error("Tried to call CurlGet::start on a busy object.");
if (m_stream == NULL)
throw torrent::internal_error("Tried to call CurlGet::start without a valid output stream.");
if (!m_stack->is_running())
return;
m_handle = curl_easy_init();
if (m_handle == NULL)
throw torrent::internal_error("Call to curl_easy_init() failed.");
curl_easy_setopt(m_handle, CURLOPT_URL, m_url.c_str());
curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, &curl_get_receive_write);
curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this);
if (m_timeout != 0) {
curl_easy_setopt(m_handle, CURLOPT_CONNECTTIMEOUT, (long)60);
curl_easy_setopt(m_handle, CURLOPT_TIMEOUT, (long)m_timeout);
// Normally libcurl should handle the timeout. But sometimes that doesn't
// work right so we do a fallback timeout that just aborts the transfer.
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&m_task_timeout, 5s + 1s*m_timeout);
}
curl_easy_setopt(m_handle, CURLOPT_FORBID_REUSE, (long)1);
curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1);
curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5);
curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
m_ipv6 = false;
m_stack->add_get(this);
}
void
CurlGet::close() {
torrent::this_thread::scheduler()->erase(&m_task_timeout);
if (!is_busy())
return;
m_stack->remove_get(this);
curl_easy_cleanup(m_handle);
m_handle = NULL;
}
void
CurlGet::retry_ipv6() {
CURL* nhandle = curl_easy_duphandle(m_handle);
curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
curl_easy_cleanup(m_handle);
m_handle = nhandle;
m_ipv6 = true;
}
void
CurlGet::receive_timeout() {
return m_stack->transfer_done(m_handle, "Timed out");
}
curl_off_t
CurlGet::size_done() {
curl_off_t d = 0;
curl_easy_getinfo(m_handle, CURLINFO_SIZE_DOWNLOAD_T, &d);
return d;
}
curl_off_t
CurlGet::size_total() {
curl_off_t d = 0;
curl_easy_getinfo(m_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &d);
return d;
}
}
+54
View File
@@ -0,0 +1,54 @@
#ifndef RTORRENT_CORE_CURL_GET_H
#define RTORRENT_CORE_CURL_GET_H
#include <iosfwd>
#include <string>
#include <curl/curl.h>
#include <torrent/http.h>
#include <torrent/utils/scheduler.h>
namespace core {
class CurlStack;
class CurlGet : public torrent::Http {
public:
CurlGet(CurlStack* s);
virtual ~CurlGet();
void start();
void close();
bool is_using_ipv6() { return m_ipv6; }
void retry_ipv6();
bool is_busy() const { return m_handle; }
bool is_active() const { return m_active; }
void set_active(bool a) { m_active = a; }
curl_off_t size_done();
curl_off_t size_total();
CURL* handle() { return m_handle; }
private:
friend class CurlStack;
CurlGet(const CurlGet&) = delete;
void operator = (const CurlGet&) = delete;
void receive_timeout();
bool m_active{};
bool m_ipv6;
torrent::utils::SchedulerEntry m_task_timeout;
CURL* m_handle{};
CurlStack* m_stack;
};
}
#endif
+99
View File
@@ -0,0 +1,99 @@
#include "config.h"
#include "curl_socket.h"
#include <cassert>
#include <curl/multi.h>
#include <torrent/poll.h>
#include <torrent/exceptions.h>
#include <torrent/utils/thread.h>
#include "control.h"
#include "core/curl_stack.h"
namespace core {
int
CurlSocket::receive_socket([[maybe_unused]] void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp) {
CurlStack* stack = (CurlStack*)userp;
CurlSocket* socket = (CurlSocket*)socketp;
if (!stack->is_running())
return 0;
if (what == CURL_POLL_REMOVE) {
// We also probably need the special code here as we're not
// guaranteed that the fd will be closed, afaik.
if (socket != NULL)
socket->close();
// TODO: Consider the possibility that we'll need to set the
// fd-associated pointer curl holds to NULL.
delete socket;
return 0;
}
if (socket == NULL) {
socket = stack->new_socket(fd);
torrent::this_thread::poll()->open(socket);
// No interface for libcurl to signal when it's interested in error events.
// Assume that hence it must always be interested in them.
torrent::this_thread::poll()->insert_error(socket);
}
if (what == CURL_POLL_NONE || what == CURL_POLL_OUT)
torrent::this_thread::poll()->remove_read(socket);
else
torrent::this_thread::poll()->insert_read(socket);
if (what == CURL_POLL_NONE || what == CURL_POLL_IN)
torrent::this_thread::poll()->remove_write(socket);
else
torrent::this_thread::poll()->insert_write(socket);
return 0;
}
CurlSocket::~CurlSocket() {
assert(m_fileDesc == -1 && "CurlSocket::~CurlSocket() m_fileDesc != -1.");
}
void
CurlSocket::close() {
if (m_fileDesc == -1)
throw torrent::internal_error("CurlSocket::close() m_fileDesc == -1.");
torrent::this_thread::poll()->closed(this);
m_fileDesc = -1;
}
void
CurlSocket::event_read() {
#if (LIBCURL_VERSION_NUM >= 0x071003)
return m_stack->receive_action(this, CURL_CSELECT_IN);
#else
return m_stack->receive_action(this, 0);
#endif
}
void
CurlSocket::event_write() {
#if (LIBCURL_VERSION_NUM >= 0x071003)
return m_stack->receive_action(this, CURL_CSELECT_OUT);
#else
return m_stack->receive_action(this, 0);
#endif
}
void
CurlSocket::event_error() {
#if (LIBCURL_VERSION_NUM >= 0x071003)
return m_stack->receive_action(this, CURL_CSELECT_ERR);
#else
return m_stack->receive_action(this, 0);
#endif
}
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef RTORRENT_CORE_CURL_SOCKET_H
#define RTORRENT_CORE_CURL_SOCKET_H
#include <curl/curl.h>
#include <torrent/event.h>
#include "globals.h"
namespace core {
class CurlStack;
class CurlSocket : public torrent::Event {
public:
CurlSocket(int fd, CurlStack* stack) : m_stack(stack) { m_fileDesc = fd; }
~CurlSocket();
const char* type_name() const { return "curl"; }
void close();
static int receive_socket(void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp);
private:
CurlSocket(const CurlSocket&);
void operator = (const CurlSocket&);
virtual void event_read();
virtual void event_write();
virtual void event_error();
CurlStack* m_stack;
};
}
#endif
+247
View File
@@ -0,0 +1,247 @@
#include "config.h"
#include <algorithm>
#include <curl/multi.h>
#include <torrent/exceptions.h>
#include "curl_get.h"
#include "curl_socket.h"
#include "curl_stack.h"
namespace core {
CurlStack::CurlStack() {
m_handle = (void*)curl_multi_init();
m_task_timeout.slot() = std::bind(&CurlStack::receive_timeout, this);
#if (LIBCURL_VERSION_NUM >= 0x071000)
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERDATA, this);
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERFUNCTION, &CurlStack::set_timeout);
#endif
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETDATA, this);
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETFUNCTION, &CurlSocket::receive_socket);
}
CurlStack::~CurlStack() {
shutdown();
}
void
CurlStack::shutdown() {
if (!m_running)
return;
m_running = false;
while (!empty())
front()->close();
curl_multi_cleanup((CURLM*)m_handle);
torrent::this_thread::scheduler()->erase(&m_task_timeout);
}
CurlGet*
CurlStack::new_object() {
return new CurlGet(this);
}
CurlSocket*
CurlStack::new_socket(int fd) {
if (!m_running)
throw torrent::internal_error("CurlStack::new_socket() called when not running.");
CurlSocket* socket = new CurlSocket(fd, this);
curl_multi_assign((CURLM*)m_handle, fd, socket);
return socket;
}
void
CurlStack::receive_action(CurlSocket* socket, int events) {
CURLMcode code;
do {
int count;
#if (LIBCURL_VERSION_NUM >= 0x071003)
code = curl_multi_socket_action((CURLM*)m_handle,
socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT,
events,
&count);
#else
code = curl_multi_socket((CURLM*)m_handle,
socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT,
&count);
#endif
if (code > 0)
throw torrent::internal_error("Error calling curl_multi_socket_action.");
// Socket might be removed when cleaning handles below, future
// calls should not use it.
socket = NULL;
events = 0;
if ((unsigned int)count != size()) {
while (process_done_handle())
; // Do nothing.
if (empty())
torrent::this_thread::scheduler()->erase(&m_task_timeout);
}
} while (code == CURLM_CALL_MULTI_PERFORM);
}
bool
CurlStack::process_done_handle() {
int remaining_msgs = 0;
CURLMsg* msg = curl_multi_info_read((CURLM*)m_handle, &remaining_msgs);
if (msg == NULL)
return false;
if (msg->msg != CURLMSG_DONE)
throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
if (msg->data.result == CURLE_COULDNT_RESOLVE_HOST) {
iterator itr = std::find_if(begin(), end(), [&msg](CurlGet* get) { return get->handle() == msg->easy_handle; });
if (itr == end())
throw torrent::internal_error("Could not find CurlGet when calling CurlStack::receive_action.");
if (!(*itr)->is_using_ipv6()) {
(*itr)->retry_ipv6();
if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_add_handle.");
}
} else {
transfer_done(msg->easy_handle,
msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
}
return remaining_msgs != 0;
}
void
CurlStack::transfer_done(void* handle, const char* msg) {
iterator itr = std::find_if(begin(), end(), [&handle](CurlGet* get) { return get->handle() == handle; });
if (itr == end())
throw torrent::internal_error("Could not find CurlGet with the right easy_handle.");
if (msg == NULL)
(*itr)->trigger_done();
else
(*itr)->trigger_failed(msg);
}
void
CurlStack::receive_timeout() {
receive_action(NULL, 0);
if (!empty() && !m_task_timeout.is_scheduled()) {
// Sometimes libcurl forgets to reset the timeout. Try to poll the value in that case, or use 10
// seconds max.
long timeout_ms;
curl_multi_timeout((CURLM*)m_handle, &timeout_ms);
auto timeout = std::max<std::chrono::microseconds>(std::chrono::milliseconds(timeout_ms), 10s);
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_timeout, timeout);
}
}
void
CurlStack::add_get(CurlGet* get) {
if (!m_user_agent.empty())
curl_easy_setopt(get->handle(), CURLOPT_USERAGENT, m_user_agent.c_str());
if (!m_http_proxy.empty())
curl_easy_setopt(get->handle(), CURLOPT_PROXY, m_http_proxy.c_str());
if (!m_bind_address.empty())
curl_easy_setopt(get->handle(), CURLOPT_INTERFACE, m_bind_address.c_str());
if (!m_http_ca_path.empty())
curl_easy_setopt(get->handle(), CURLOPT_CAPATH, m_http_ca_path.c_str());
if (!m_http_ca_cert.empty())
curl_easy_setopt(get->handle(), CURLOPT_CAINFO, m_http_ca_cert.c_str());
curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYHOST, (long)(m_ssl_verify_host ? 2 : 0));
curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYPEER, (long)(m_ssl_verify_peer ? 1 : 0));
curl_easy_setopt(get->handle(), CURLOPT_DNS_CACHE_TIMEOUT, m_dns_timeout);
base_type::push_back(get);
if (m_active >= m_max_active)
return;
m_active++;
get->set_active(true);
if (curl_multi_add_handle((CURLM*)m_handle, get->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_add_handle.");
#if (LIBCURL_VERSION_NUM < 0x071000)
receive_timeout();
#endif
}
void
CurlStack::remove_get(CurlGet* get) {
iterator itr = std::find(begin(), end(), get);
if (itr == end())
throw torrent::internal_error("Could not find CurlGet when calling CurlStack::remove.");
base_type::erase(itr);
// The CurlGet object was never activated, so we just skip this one.
if (!get->is_active())
return;
get->set_active(false);
if (curl_multi_remove_handle((CURLM*)m_handle, get->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_remove_handle.");
if (m_active == m_max_active &&
(itr = std::find_if(begin(), end(), [](CurlGet* get) { return !get->is_active(); })) != end()) {
(*itr)->set_active(true);
if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_add_handle.");
} else {
m_active--;
}
}
void
CurlStack::global_init() {
curl_global_init(CURL_GLOBAL_ALL);
}
void
CurlStack::global_cleanup() {
curl_global_cleanup();
}
// TODO: Is this function supposed to set a per-handle timeout, or is
// it the shortest timeout amongst all handles?
int
CurlStack::set_timeout(void*, long timeout_ms, void* userp) {
CurlStack* stack = (CurlStack*)userp;
if (timeout_ms == -1)
torrent::this_thread::scheduler()->erase(&stack->m_task_timeout);
else
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&stack->m_task_timeout, std::chrono::milliseconds(timeout_ms));
return 0;
}
}
+120
View File
@@ -0,0 +1,120 @@
#ifndef RTORRENT_CORE_CURL_STACK_H
#define RTORRENT_CORE_CURL_STACK_H
#include <deque>
#include <string>
#include <torrent/utils/scheduler.h>
namespace core {
class CurlGet;
class CurlSocket;
// By using a deque instead of vector we allow for cheaper removal of
// the oldest elements, those that will be first in the in the
// deque.
//
// This should fit well with the use-case of a http stack, thus
// we get most of the cache locality benefits of a vector with fast
// removal of elements.
class CurlStack : std::deque<CurlGet*> {
public:
friend class CurlGet;
typedef std::deque<CurlGet*> base_type;
using base_type::value_type;
using base_type::iterator;
using base_type::const_iterator;
using base_type::reverse_iterator;
using base_type::const_reverse_iterator;
using base_type::begin;
using base_type::end;
using base_type::rbegin;
using base_type::rend;
using base_type::back;
using base_type::front;
using base_type::size;
using base_type::empty;
CurlStack();
~CurlStack();
void shutdown();
bool is_running() const { return m_running; }
CurlGet* new_object();
CurlSocket* new_socket(int fd);
unsigned int active() const { return m_active; }
unsigned int max_active() const { return m_max_active; }
void set_max_active(unsigned int a) { m_max_active = a; }
const std::string& user_agent() const { return m_user_agent; }
const std::string& http_proxy() const { return m_http_proxy; }
const std::string& bind_address() const { return m_bind_address; }
const std::string& http_capath() const { return m_http_ca_path; }
const std::string& http_cacert() const { return m_http_ca_cert; }
void set_user_agent(const std::string& s) { m_user_agent = s; }
void set_http_proxy(const std::string& s) { m_http_proxy = s; }
void set_bind_address(const std::string& s) { m_bind_address = s; }
void set_http_capath(const std::string& s) { m_http_ca_path = s; }
void set_http_cacert(const std::string& s) { m_http_ca_cert = s; }
bool ssl_verify_host() const { return m_ssl_verify_host; }
bool ssl_verify_peer() const { return m_ssl_verify_peer; }
void set_ssl_verify_host(bool s) { m_ssl_verify_host = s; }
void set_ssl_verify_peer(bool s) { m_ssl_verify_peer = s; }
long dns_timeout() const { return m_dns_timeout; }
void set_dns_timeout(long timeout) { m_dns_timeout = timeout; }
static void global_init();
static void global_cleanup();
void receive_action(CurlSocket* socket, int type);
static int set_timeout(void*, long timeout_ms, void* userp);
void transfer_done(void* handle, const char* msg);
protected:
void add_get(CurlGet* get);
void remove_get(CurlGet* get);
private:
CurlStack(const CurlStack&) = delete;
void operator = (const CurlStack&) = delete;
void receive_timeout();
bool process_done_handle();
void* m_handle;
bool m_running{true};
unsigned int m_active{0};
unsigned int m_max_active{32};
torrent::utils::SchedulerEntry m_task_timeout;
std::string m_user_agent;
std::string m_http_proxy;
std::string m_bind_address;
std::string m_http_ca_path;
std::string m_http_ca_cert;
bool m_ssl_verify_host{true};
bool m_ssl_verify_peer{true};
long m_dns_timeout{60};
};
}
#endif
+17 -15
View File
@@ -18,11 +18,8 @@
#include "download_store.h"
#include "manager.h"
#define LT_LOG(log_fmt, ...) \
lt_log_print_subsystem(torrent::LOG_DHT_CONTROLLER, "dht_manager", log_fmt, __VA_ARGS__);
#define LT_LOG_ERROR(log_fmt, ...) \
lt_log_print_subsystem(torrent::LOG_DHT_ERROR, "dht_manager", log_fmt, __VA_ARGS__);
#define LT_LOG_THIS(log_fmt, ...) \
lt_log_print_subsystem(torrent::LOG_DHT_MANAGER, "dht_manager", log_fmt, __VA_ARGS__);
namespace core {
@@ -36,7 +33,7 @@ DhtManager::~DhtManager() {
void
DhtManager::load_dht_cache() {
if (m_start == dht_disable || !control->core()->download_store()->is_enabled()) {
LT_LOG("ignoring cache file", 0);
LT_LOG_THIS("ignoring cache file", 0);
return;
}
@@ -51,14 +48,14 @@ DhtManager::load_dht_cache() {
// If the cache file is corrupted we will just discard it with an
// error message.
if (cache_stream.fail()) {
LT_LOG_ERROR("cache file corrupted, discarding (path:%s)", cache_filename.c_str());
LT_LOG_THIS("cache file corrupted, discarding (path:%s)", cache_filename.c_str());
cache = torrent::Object::create_map();
} else {
LT_LOG("cache file read (path:%s)", cache_filename.c_str());
LT_LOG_THIS("cache file read (path:%s)", cache_filename.c_str());
}
} else {
LT_LOG("could not open cache file (path:%s)", cache_filename.c_str());
LT_LOG_THIS("could not open cache file (path:%s)", cache_filename.c_str());
}
torrent::dht_controller()->initialize(cache);
@@ -72,12 +69,12 @@ DhtManager::start_dht() {
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
if (!torrent::dht_controller()->is_valid()) {
LT_LOG("server start skipped, manager is uninitialized", 0);
LT_LOG_THIS("server start skipped, manager is uninitialized", 0);
return;
}
if (torrent::dht_controller()->is_active()) {
LT_LOG("server start skipped, already active", 0);
LT_LOG_THIS("server start skipped, already active", 0);
return;
}
@@ -85,7 +82,12 @@ DhtManager::start_dht() {
torrent::dht_controller()->set_upload_throttle(throttles.first);
torrent::dht_controller()->set_download_throttle(throttles.second);
if (!torrent::dht_controller()->start()) {
int port = rpc::call_command_value("dht.port");
if (port <= 0)
return;
if (!torrent::dht_controller()->start(port)) {
m_start = dht_off;
return;
}
@@ -110,7 +112,7 @@ DhtManager::stop_dht() {
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
if (torrent::dht_controller()->is_active()) {
LT_LOG("stopping server", 0);
LT_LOG_THIS("stopping server", 0);
log_statistics(true);
torrent::dht_controller()->stop();
@@ -194,7 +196,7 @@ DhtManager::log_statistics(bool force) {
// We should have had clients ping us at least but have received
// nothing, that means the UDP port is probably unreachable.
if (torrent::dht_controller()->is_receiving_requests())
LT_LOG("listening port appears to be unreachable, no queries received", 0);
LT_LOG_THIS("listening port appears to be unreachable, no queries received", 0);
torrent::dht_controller()->set_receive_requests(false);
}
@@ -202,7 +204,7 @@ DhtManager::log_statistics(bool force) {
if (stats.queries_sent - m_dhtPrevQueriesSent > stats.num_nodes * 2 + 20 && stats.replies_received == m_dhtPrevRepliesReceived) {
// No replies to over 20 queries plus two per node we have. Probably firewalled.
if (!m_warned)
LT_LOG("listening port appears to be firewalled, no replies received", 0);
LT_LOG_THIS("listening port appears to be firewalled, no replies received", 0);
m_warned = true;
return false;
+1 -1
View File
@@ -46,8 +46,8 @@ private:
torrent::utils::SchedulerEntry m_stop_timeout;
bool m_warned{};
int m_start{dht_off};
int m_start{dht_off};
std::string m_throttleName;
};
-1
View File
@@ -7,7 +7,6 @@
#include <torrent/rate.h>
#include <torrent/torrent.h>
#include <torrent/tracker/tracker.h>
#include <torrent/data/file.h>
#include <torrent/data/file_list.h>
#include "rpc/parse_commands.h"
+27 -23
View File
@@ -1,12 +1,11 @@
#include "config.h"
#include "download_factory.h"
#include <cstdlib>
#include <fstream>
#include <functional>
#include <sstream>
#include <stdexcept>
#include <rak/path.h>
#include <torrent/utils/log.h>
#include <torrent/utils/resume.h>
@@ -15,16 +14,19 @@
#include <torrent/exceptions.h>
#include <torrent/rate.h>
#include <torrent/data/file_utils.h>
#include <torrent/net/http_stack.h>
#include "control.h"
#include "globals.h"
#include "core/download.h"
#include "core/download_store.h"
#include "core/http_queue.h"
#include "core/manager.h"
#include "rpc/parse_commands.h"
#include "curl_get.h"
#include "control.h"
#include "http_queue.h"
#include "globals.h"
#include "manager.h"
#include "download.h"
#include "download_factory.h"
#include "download_store.h"
namespace core {
bool
@@ -75,7 +77,9 @@ DownloadFactory::~DownloadFactory() {
torrent::this_thread::scheduler()->erase(&m_task_load);
torrent::this_thread::scheduler()->erase(&m_task_commit);
delete m_stream;
delete m_object;
m_stream = NULL;
}
void
@@ -90,7 +94,7 @@ DownloadFactory::load_raw_data(const std::string& input) {
if (m_stream)
throw torrent::internal_error("DownloadFactory::load*() called on an object with m_stream != NULL");
m_stream.reset(new std::stringstream(input));
m_stream = new std::stringstream(input);
m_loaded = true;
}
@@ -106,18 +110,17 @@ DownloadFactory::receive_load() {
if (is_network_uri(m_uri)) {
// Http handling here.
m_stream.reset(new std::stringstream);
m_stream = new std::stringstream;
HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream);
itr->add_done_slot([this]() { receive_loaded(); });
itr->add_failed_slot([this](const std::string& error) { receive_failed(error); });
(*itr)->signal_done().push_front(std::bind(&DownloadFactory::receive_loaded, this));
(*itr)->signal_failed().push_front(std::bind(&DownloadFactory::receive_failed, this, std::placeholders::_1));
m_variables["tied_to_file"] = (int64_t)false;
} else if (is_magnet_uri(m_uri)) {
// DEBUG: Use m_object.
m_stream.reset(new std::stringstream());
m_stream = new std::stringstream();
*m_stream << "d10:magnet-uri" << m_uri.length() << ":" << m_uri << "e";
m_variables["tied_to_file"] = (int64_t)false;
@@ -169,8 +172,8 @@ DownloadFactory::receive_success() {
else
tracker_key = random() % (std::numeric_limits<uint32_t>::max() - 1) + 1;
Download* download = m_stream != nullptr ?
m_manager->download_list()->create(m_stream.get(), tracker_key, m_printLog) :
Download* download = m_stream != NULL ?
m_manager->download_list()->create(m_stream, tracker_key, m_printLog) :
m_manager->download_list()->create(m_object, tracker_key, m_printLog);
m_object = NULL;
@@ -191,8 +194,8 @@ DownloadFactory::receive_success() {
torrent::Object::list_type& commands = meta.insert_key("commands", torrent::Object::create_list()).as_list();
for (auto& m_command : m_commands)
commands.push_back(m_command);
for (command_list_type::iterator itr = m_commands.begin(); itr != m_commands.end(); ++itr)
commands.push_back(*itr);
}
if (m_session) {
@@ -286,8 +289,9 @@ DownloadFactory::receive_success() {
if (torrent::log_groups[torrent::LOG_TORRENT_DEBUG].valid())
log_created(download, rtorrent);
for (const auto& command : m_commands)
rpc::parse_command_multiple_std(command, rpc::make_target(download));
std::for_each(m_commands.begin(), m_commands.end(), [&download](const std::string& cmd) {
rpc::parse_command_multiple_std(cmd, rpc::make_target(download));
});
if (m_manager->download_list()->find(infohash) == m_manager->download_list()->end())
throw torrent::input_error("The newly created download was removed.");
@@ -332,8 +336,8 @@ DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
dump << "---COMMANDS---" << std::endl;
for (const auto& m_command : m_commands) {
dump << m_command << std::endl;
for (command_list_type::const_iterator itr = m_commands.begin(); itr != m_commands.end(); itr++) {
dump << *itr << std::endl;
}
std::string dump_str = dump.str();
+3 -3
View File
@@ -62,9 +62,9 @@ private:
void initialize_rtorrent(Download* download, torrent::Object* rtorrent);
Manager* m_manager;
std::shared_ptr<std::iostream> m_stream;
torrent::Object* m_object{};
Manager* m_manager;
std::iostream* m_stream{};
torrent::Object* m_object{};
bool m_commited{};
bool m_loaded{};
+3 -6
View File
@@ -167,10 +167,8 @@ DownloadList::insert(Download* download) {
// This needs to be separated into two different calls to ensure
// the download remains in the view.
for (auto v : *control->view_manager())
v->insert(download);
for (auto v : *control->view_manager())
v->filter_download(download);
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), [&download](View* v) { v->insert(download); });
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), [&download](View* v) { v->filter_download(download); });
DL_TRIGGER_EVENT(*itr, "event.download.inserted");
@@ -203,8 +201,7 @@ DownloadList::erase(iterator itr) {
control->core()->download_store()->remove(*itr);
DL_TRIGGER_EVENT(*itr, "event.download.erased");
for (auto v : *control->view_manager())
v->erase(*itr);
std::for_each(control->view_manager()->begin(), control->view_manager()->end(), [itr](View* v) { v->erase(*itr); });
torrent::download_remove(*(*itr)->download());
delete *itr;
+67
View File
@@ -0,0 +1,67 @@
// 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 <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H
#define RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H
#include <functional>
#include <map>
#include <string>
#include "download.h"
namespace core {
class DownloadSlotMap : public std::map<std::string, std::function<void (Download*)> > {
public:
typedef std::function<void (Download*)> slot_download;
typedef std::map<std::string, slot_download> Base;
void insert(const std::string& key, slot_download s) { Base::operator[](key) = s; }
void erase(const std::string& key) { Base::erase(key); }
void for_each(Download* d);
};
inline void
DownloadSlotMap::for_each(Download* d) {
for (iterator itr = begin(), last = end(); itr != last; ++itr)
itr->second(d);
}
}
#endif
+25 -17
View File
@@ -1,37 +1,43 @@
#include "config.h"
#include "http_queue.h"
#include <memory>
#include <sstream>
#include <torrent/http.h>
#include <torrent/common.h>
#include <torrent/net/http_get.h>
#include <torrent/net/http_stack.h>
#include "http_queue.h"
#include "curl_get.h"
namespace core {
HttpQueue::iterator
HttpQueue::insert(const std::string& url, std::shared_ptr<std::ostream> stream) {
auto itr = base_type::insert(end(), torrent::net::HttpGet(url, stream));
HttpQueue::insert(const std::string& url, std::iostream* s) {
std::unique_ptr<CurlGet> h(m_slot_factory());
for (auto& slot : m_signal_insert)
slot(*itr);
h->set_url(url);
h->set_stream(s);
h->set_timeout(5 * 60);
itr->add_done_slot([this, itr]() { erase(itr); });
itr->add_failed_slot([this, itr](auto) { erase(itr); });
iterator signal_itr = base_type::insert(end(), h.get());
// TODO: Downloading http torrents doesn't seem to work.
// TODO: Quitting no longer works.
h->signal_done().push_back(std::bind(&HttpQueue::erase, this, signal_itr));
h->signal_failed().push_back(std::bind(&HttpQueue::erase, this, signal_itr));
torrent::net_thread::http_stack()->start_get(*itr);
(*signal_itr)->start();
return itr;
h.release();
for (signal_curl_get::iterator itr = m_signal_insert.begin(), last = m_signal_insert.end(); itr != last; itr++)
(*itr)(*signal_itr);
return signal_itr;
}
void
HttpQueue::erase(iterator signal_itr) {
for (const auto& slot : m_signal_erase)
slot(*signal_itr);
for (signal_curl_get::iterator itr = m_signal_erase.begin(), last = m_signal_erase.end(); itr != last; itr++)
(*itr)(*signal_itr);
signal_itr->close_and_keep_callbacks();
delete *signal_itr;
base_type::erase(signal_itr);
}
@@ -39,6 +45,8 @@ void
HttpQueue::clear() {
while (!empty())
erase(begin());
base_type::clear();
}
}
+10 -9
View File
@@ -3,20 +3,18 @@
#include <functional>
#include <iosfwd>
#include <memory>
#include <list>
#include <string>
#include <torrent/net/http_get.h>
namespace core {
// TODO: Remove this.
class CurlGet;
class HttpQueue : private std::list<torrent::net::HttpGet> {
class HttpQueue : private std::list<CurlGet*> {
public:
using base_type = std::list<torrent::net::HttpGet>;
using slot_curl_get = std::function<void (torrent::net::HttpGet)>;
using signal_curl_get = std::list<slot_curl_get>;
typedef std::list<CurlGet*> base_type;
typedef std::function<CurlGet* ()> slot_factory;
typedef std::function<void (CurlGet*)> slot_curl_get;
typedef std::list<slot_curl_get> signal_curl_get;
using base_type::iterator;
using base_type::const_iterator;
@@ -39,15 +37,18 @@ 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::iostream* s);
void erase(iterator itr);
void clear();
void set_slot_factory(slot_factory s) { m_slot_factory = s; }
signal_curl_get& signal_insert() { return m_signal_insert; }
signal_curl_get& signal_erase() { return m_signal_erase; }
private:
slot_factory m_slot_factory;
signal_curl_get m_signal_insert;
signal_curl_get m_signal_erase;
};
+121 -42
View File
@@ -7,6 +7,7 @@
#include <unistd.h>
#include <sys/select.h>
#include <rak/address_info.h>
#include <rak/error_number.h>
#include <rak/regex.h>
#include <rak/path.h>
#include <rak/string_manip.h>
@@ -17,10 +18,6 @@
#include <torrent/exceptions.h>
#include <torrent/object_stream.h>
#include <torrent/throttle.h>
#include <torrent/net/http_stack.h>
#include <torrent/net/network_config.h>
#include <torrent/net/network_manager.h>
#include <torrent/net/socket_address.h>
#include <torrent/utils/log.h>
#include "rpc/parse_commands.h"
@@ -29,13 +26,15 @@
#include "utils/file_status_cache.h"
#include "globals.h"
#include "curl_get.h"
#include "curl_stack.h"
#include "control.h"
#include "core/download.h"
#include "core/download_factory.h"
#include "core/download_store.h"
#include "core/http_queue.h"
#include "core/manager.h"
#include "core/view.h"
#include "download.h"
#include "download_factory.h"
#include "download_store.h"
#include "http_queue.h"
#include "manager.h"
#include "view.h"
namespace core {
@@ -58,6 +57,7 @@ Manager::Manager() :
m_download_list = std::make_unique<DownloadList>();
m_file_status_cache = std::make_unique<FileStatusCache>();
m_http_queue = std::make_unique<HttpQueue>();
m_http_stack = std::make_unique<CurlStack>();
torrent::Throttle* unthrottled = torrent::Throttle::create_throttle();
unthrottled->set_max_rate(0);
@@ -99,10 +99,7 @@ Manager::set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePai
torrent::ThrottlePair
Manager::get_address_throttle(const sockaddr* addr) {
if (addr->sa_family != AF_INET)
return torrent::ThrottlePair(nullptr, nullptr);
return m_addressThrottles.get(ntohl(reinterpret_cast<const sockaddr_in*>(addr)->sin_addr.s_addr), torrent::ThrottlePair(nullptr, nullptr));
return m_addressThrottles.get(rak::socket_address::cast_from(addr)->sa_inet()->address_h(), torrent::ThrottlePair(nullptr, nullptr));
}
int64_t
@@ -134,24 +131,39 @@ Manager::retrieve_throttle_value(const torrent::Object::string_type& name, bool
}
}
// Most of this should be possible to move out.
void
Manager::initialize_second() {
torrent::Http::slot_factory() = std::bind(&CurlStack::new_object, m_http_stack.get());
m_http_queue->set_slot_factory(std::bind(&CurlStack::new_object, m_http_stack.get()));
CurlStack::global_init();
}
void
Manager::cleanup() {
m_http_stack->shutdown();
// Need to disconnect log signals? Not really since we won't receive
// any more.
m_download_list->clear();
// When we implement asynchronous DNS lookups, we need to cancel them
// here before the torrent::* objects are deleted.
torrent::cleanup();
m_http_stack.reset();
CurlStack::global_cleanup();
}
void
Manager::shutdown(bool force) {
if (!force)
for (auto d : *m_download_list)
m_download_list->pause_default(d);
std::for_each(m_download_list->begin(), m_download_list->end(), [this](Download* d) { m_download_list->pause_default(d); });
else
for (auto d : *m_download_list)
m_download_list->close_quick(d);
std::for_each(m_download_list->begin(), m_download_list->end(), [this](Download* d) { m_download_list->close_quick(d); });
}
void
@@ -164,11 +176,15 @@ Manager::listen_open() {
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 (portRange.is_string()) {
if (std::sscanf(portRange.as_string().c_str(), "%i-%i", &portFirst, &portLast) != 2)
throw torrent::input_error("Invalid port_range argument.");
if (std::sscanf(portRange.as_string().c_str(), "%i-%i", &portFirst, &portLast) != 2)
// } else if (portRange.is_list()) {
} else {
throw torrent::input_error("Invalid port_range argument.");
}
if (portFirst > portLast || portLast >= (1 << 16))
throw torrent::input_error("Invalid port range.");
@@ -176,16 +192,81 @@ Manager::listen_open() {
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))
if (torrent::connection_manager()->listen_open(boundary, portLast) ||
torrent::connection_manager()->listen_open(portFirst, boundary))
return;
} else {
if (torrent::runtime::network_manager()->listen_open(portFirst, portLast))
if (torrent::connection_manager()->listen_open(portFirst, portLast))
return;
}
throw torrent::input_error("Could not open/bind port for listening: " + std::string(std::strerror(errno)));
throw torrent::input_error("Could not open/bind port for listening: " + std::string(rak::error_number::current().c_str()));
}
std::string
Manager::bind_address() const {
return rak::socket_address::cast_from(torrent::connection_manager()->bind_address())->address_str();
}
void
Manager::set_bind_address(const std::string& addr) {
int err;
rak::address_info* ai;
if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 &&
(err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0)
throw torrent::input_error("Could not set bind address: " + std::string(rak::address_info::strerror(err)) + ".");
try {
if (torrent::connection_manager()->listen_port() != 0) {
torrent::connection_manager()->listen_close();
torrent::connection_manager()->set_bind_address(ai->address()->c_sockaddr());
listen_open();
} else {
torrent::connection_manager()->set_bind_address(ai->address()->c_sockaddr());
}
m_http_stack->set_bind_address(!ai->address()->is_address_any() ? ai->address()->address_str() : std::string());
rak::address_info::free_address_info(ai);
} catch (torrent::input_error& e) {
rak::address_info::free_address_info(ai);
throw e;
}
}
std::string
Manager::local_address() const {
return rak::socket_address::cast_from(torrent::connection_manager()->local_address())->address_str();
}
void
Manager::set_local_address(const std::string& addr) {
int err;
rak::address_info* ai;
if ((err = rak::address_info::get_address_info(addr.c_str(), PF_INET, SOCK_STREAM, &ai)) != 0 &&
(err = rak::address_info::get_address_info(addr.c_str(), PF_INET6, SOCK_STREAM, &ai)) != 0)
throw torrent::input_error("Could not set local address: " + std::string(rak::address_info::strerror(err)) + ".");
try {
torrent::connection_manager()->set_local_address(ai->address()->c_sockaddr());
rak::address_info::free_address_info(ai);
} catch (torrent::input_error& e) {
rak::address_info::free_address_info(ai);
throw e;
}
}
std::string
Manager::proxy_address() const {
return rak::socket_address::cast_from(torrent::connection_manager()->proxy_address())->address_str();
}
void
@@ -208,10 +289,8 @@ Manager::set_proxy_address(const std::string& addr) {
try {
auto sa = torrent::sa_copy(ai->c_addrinfo()->ai_addr);
torrent::sap_set_port(sa, port);
torrent::config::network_config()->set_proxy_address(sa.get());
ai->address()->set_port(port);
torrent::connection_manager()->set_proxy_address(ai->address()->c_sockaddr());
rak::address_info::free_address_info(ai);
@@ -285,8 +364,8 @@ Manager::try_create_download_from_meta_download(torrent::Object* bencode, const
torrent::Object& meta = bencode->get_key("rtorrent_meta_download");
torrent::Object::list_type& commands = meta.get_key_list("commands");
for (const auto& command : commands)
f->commands().insert(f->commands().end(), command.as_string());
for (torrent::Object::list_type::const_iterator itr = commands.begin(); itr != commands.end(); ++itr)
f->commands().insert(f->commands().end(), itr->as_string());
f->set_start(meta.get_key_value("start"));
f->set_print_log(meta.get_key_value("print_log"));
@@ -339,22 +418,22 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
// Special case for ".."?
for (auto& itr : currentCache) {
for (std::vector<utils::Directory>::iterator itr = currentCache.begin(); itr != currentCache.end(); ++itr) {
// 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((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());
for (const auto& cache : itr)
nextCache.push_back(path_expand_transform(itr.path() + (itr.path() == "/" ? "" : "/"), cache));
std::transform(itr->begin(), itr->end(), std::back_inserter(nextCache), [itr](const utils::directory_entry& entry) {
return path_expand_transform(itr->path() + (itr->path() == "/" ? "" : "/"), entry);
});
}
currentCache.clear();
currentCache.swap(nextCache);
}
for (const auto& cache : currentCache)
paths->push_back(cache.path());
std::transform(currentCache.begin(), currentCache.end(), std::back_inserter(*paths), std::mem_fn(&utils::Directory::path));
}
bool
@@ -375,8 +454,8 @@ Manager::try_create_download_expand(const std::string& uri, int flags, command_l
path_expand(&paths, uri);
if (!paths.empty())
for (auto& path : paths)
try_create_download(path, flags, commands);
for (std::vector<std::string>::iterator itr = paths.begin(); itr != paths.end(); ++itr)
try_create_download(*itr, flags, commands);
else
try_create_download(uri, flags, commands);
@@ -387,8 +466,8 @@ Manager::try_create_download_expand(const std::string& uri, int flags, command_l
// hashing view and starts hashing if nessesary.
void
Manager::receive_hashing_changed() {
bool foundHashing = std::any_of(m_hashingView->begin_visible(), m_hashingView->end_visible(),
std::mem_fn(&Download::is_hash_checking));
bool foundHashing = std::find_if(m_hashingView->begin_visible(), m_hashingView->end_visible(),
std::mem_fn(&Download::is_hash_checking)) != m_hashingView->end_visible();
// Try quick hashing all those with hashing == initial, set them to
// something else when failed.
+12
View File
@@ -21,6 +21,7 @@ class FileStatusCache;
namespace core {
class CurlStack;
class DownloadStore;
class HttpQueue;
@@ -41,6 +42,7 @@ public:
FileStatusCache* file_status_cache() { return m_file_status_cache.get(); }
HttpQueue* http_queue() { return m_http_queue.get(); }
CurlStack* http_stack() { return m_http_stack.get(); }
View* hashing_view() { return m_hashingView; }
void set_hashing_view(View* v);
@@ -57,10 +59,19 @@ public:
void set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles);
torrent::ThrottlePair get_address_throttle(const sockaddr* addr);
// Really should find a more descriptive name.
void initialize_second();
void cleanup();
void listen_open();
std::string bind_address() const;
void set_bind_address(const std::string& addr);
std::string local_address() const;
void set_local_address(const std::string& addr);
std::string proxy_address() const;
void set_proxy_address(const std::string& addr);
void shutdown(bool force);
@@ -98,6 +109,7 @@ private:
std::unique_ptr<DownloadStore> m_download_store;
std::unique_ptr<FileStatusCache> m_file_status_cache;
std::unique_ptr<HttpQueue> m_http_queue;
std::unique_ptr<CurlStack> m_http_stack;
View* m_hashingView{};
+8 -7
View File
@@ -16,7 +16,7 @@
namespace core {
// Also add focus thingie here?
struct view_downloads_compare {
struct view_downloads_compare : std::function<bool (Download*, Download*)> {
view_downloads_compare(const torrent::Object& cmd) :
m_command(cmd) {}
@@ -50,7 +50,7 @@ struct view_downloads_compare {
const torrent::Object& m_command;
};
struct view_downloads_filter {
struct view_downloads_filter : std::function<bool (Download*)> {
view_downloads_filter(const torrent::Object& cmd, const torrent::Object& cmd2) :
m_command(cmd), m_command2(cmd2) {}
@@ -118,8 +118,8 @@ View::emit_changed() {
void
View::emit_changed_now() {
for (auto& itr : m_signal_changed)
itr();
for (signal_void::iterator itr = m_signal_changed.begin(), last = m_signal_changed.end(); itr != last; itr++)
(*itr)();
}
View::~View() {
@@ -138,11 +138,12 @@ View::initialize(const std::string& name) {
if (name.empty())
throw torrent::internal_error("View::initialize(...) called with an empty name.");
core::DownloadList* dlist = control->core()->download_list();
m_name = name;
// Urgh, wrong. No filtering being done.
for (const auto& d : *control->core()->download_list())
push_back(d);
std::for_each(dlist->begin(), dlist->end(), [&](Download* d) { push_back(d); });
m_size = base_type::size();
m_focus = 0;
@@ -346,7 +347,7 @@ View::clear_filter_on() {
inline void
View::insert_visible(Download* d) {
auto itr = std::find_if(begin_visible(), end_visible(), [this, d](auto d2) { return view_downloads_compare(m_sortNew)(d, d2); });
iterator itr = std::find_if(begin_visible(), end_visible(), [&d, this](Download* d2) { return view_downloads_compare(m_sortNew)(d, d2); });
m_size++;
m_focus += (m_focus >= position(itr));
+3 -4
View File
@@ -18,8 +18,7 @@ namespace core {
void
ViewManager::clear() {
for (auto v : *this)
delete v;
std::for_each(begin(), end(), [](View* v) { delete v; });
base_type::clear();
}
@@ -89,8 +88,8 @@ ViewManager::set_filter_on(const std::string& name, const filter_args& args) {
// TODO: Ensure the filter keys are rlookup.
for (const auto& arg : args)
(*viewItr)->set_filter_on_event(arg);
for (filter_args::const_iterator itr = args.begin(); itr != args.end(); ++itr)
(*viewItr)->set_filter_on_event(*itr);
}
}
-1
View File
@@ -1,7 +1,6 @@
#ifndef RTORRENT_DISPLAY_CANVAS_H
#define RTORRENT_DISPLAY_CANVAS_H
#include <cstdarg>
#include <string>
#include <unordered_map>
#include <vector>
+7 -8
View File
@@ -43,8 +43,7 @@ namespace display {
void
TextElementList::clear() {
for (auto t : *this)
delete t;
std::for_each(begin(), end(), [](TextElement* t) { delete t; });
base_type::clear();
}
@@ -54,14 +53,14 @@ TextElementList::print(char* first, char* last, Canvas::attributes_list* attribu
// Call print for each element even if first == last so that any
// attributes gets added to the list.
for (auto& itr : *this)
for (iterator itr = begin(); itr != end(); ++itr)
if (column-- > 0) {
char* columnEnd = std::min(last, first + *m_columnWidth);
if (columnEnd < first || columnEnd > last)
throw torrent::internal_error("TextElementList::print(...) columnEnd < first || columnEnd > last.");
first = itr->print(first, columnEnd, attributes, target);
first = (*itr)->print(first, columnEnd, attributes, target);
if (first > columnEnd)
throw torrent::internal_error("TextElementList::print(...) first > columnEnd.");
@@ -70,7 +69,7 @@ TextElementList::print(char* first, char* last, Canvas::attributes_list* attribu
first = columnEnd;
} else {
first = itr->print(first, last, attributes, target);
first = (*itr)->print(first, last, attributes, target);
}
return first;
@@ -81,15 +80,15 @@ TextElementList::max_length() {
extent_type length = 0;
int column = m_columnWidth != NULL ? m_column : 0;
for (auto& itr : *this) {
extent_type l = column-- > 0 ? std::min(itr->max_length(), *m_columnWidth) : itr->max_length();
for (iterator itr = begin(); itr != end(); ++itr) {
extent_type l = column-- > 0 ? std::min((*itr)->max_length(), *m_columnWidth) : (*itr)->max_length();
if (l == extent_full)
return extent_full;
length += l;
}
return length;
}
+6 -6
View File
@@ -50,16 +50,16 @@ TextElementStringBase::print(char* first, char* last, Canvas::attributes_list* a
return first;
if (m_flags & flag_escape_hex) {
auto buffer = std::make_unique<char[]>(last - first);
char* bufferLast = copy_string(buffer.get(), buffer.get() + (last - first), target);
char buffer[last - first];
char* bufferLast = copy_string(buffer, buffer + (last - first), target);
first = rak::transform_hex(buffer.get(), bufferLast, first, last);
first = rak::transform_hex(buffer, bufferLast, first, last);
} else if (m_flags & flag_escape_html) {
auto buffer = std::make_unique<char[]>(last - first);
char* bufferLast = copy_string(buffer.get(), buffer.get() + (last - first), target);
char buffer[last - first];
char* bufferLast = copy_string(buffer, buffer + (last - first), target);
first = rak::copy_escape_html(buffer.get(), bufferLast, first, last);
first = rak::copy_escape_html(buffer, bufferLast, first, last);
} else {
first = copy_string(first, last, target);
-2
View File
@@ -4,8 +4,6 @@
#include <ctime>
#include <torrent/utils/chrono.h>
#include "globals.h"
namespace display {
+34 -43
View File
@@ -1,11 +1,10 @@
#include "config.h"
#include "display/utils.h"
#include <cstring>
#include <cstdio>
#include <sstream>
#include <iomanip>
#include <rak/socket_address.h>
#include <torrent/exceptions.h>
#include <torrent/connection_manager.h>
#include <torrent/rate.h>
@@ -15,23 +14,22 @@
#include <torrent/data/file_list.h>
#include <torrent/data/file_manager.h>
#include <torrent/download/resource_manager.h>
#include <torrent/net/http_stack.h>
#include <torrent/net/network_config.h>
#include <torrent/net/network_manager.h>
#include <torrent/net/socket_address.h>
#include <torrent/peer/client_info.h>
#include "control.h"
#include "globals.h"
#include "core/curl_stack.h"
#include "core/download.h"
#include "core/manager.h"
#include "rpc/parse_commands.h"
#include "ui/root.h"
#include "control.h"
#include "globals.h"
#include "utils.h"
namespace display {
char*
print_string(char* first, char* last, const char* str) {
print_string(char* first, char* last, char* str) {
if (first == last)
return first;
@@ -80,9 +78,17 @@ print_ddmmyyyy(char* first, char* last, time_t t) {
return print_buffer(first, last, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year));
}
char*
print_address(char* first, char* last, const rak::socket_address* sa) {
if (!sa->address_c_str(first, last - first))
return first;
return std::find(first, last, '\0');
}
inline char*
print_address(char* first, char* last, const sockaddr* sa) {
return print_string(first, last, torrent::sa_addr_str(sa).c_str());
return print_address(first, last, rak::socket_address::cast_from(sa));
}
char*
@@ -105,7 +111,7 @@ print_download_info_full(char* first, char* last, core::Download* d) {
first = print_buffer(first, last, "%6.1f / %6.1f MB",
(double)d->download()->bytes_done() / (double)(1 << 20),
(double)d->download()->file_list()->size_bytes() / (double)(1 << 20));
first = print_buffer(first, last, " Rate: %5.1f / %5.1f KB Uploaded: %7.1f MB",
(double)d->info()->up_rate()->rate() / (1 << 10),
(double)d->info()->down_rate()->rate() / (1 << 10),
@@ -289,14 +295,15 @@ print_status_throttle_limit(char* first, char* last, bool up, const ui::Throttle
char* firstc = throttle_str;
char* lastc = throttle_str + 40 - 1;
for (const auto& throttle_name : throttle_names) {
for (ui::ThrottleNameList::const_iterator itr = throttle_names.begin(), laste = throttle_names.end(); itr != laste; itr++) {
if (!throttle_name.empty()) {
int64_t throttle_max = control->core()->retrieve_throttle_value(throttle_name, false, up);
if (!(*itr).empty()) {
int64_t throttle_max = control->core()->retrieve_throttle_value(*itr, false, up);
if (throttle_max > 0)
firstc = print_buffer(firstc, lastc, "|%1.0f", (double)throttle_max / 1024.0);
}
}
// Add temp buffer (chop first char first) into main buffer if temp buffer isn't empty
@@ -314,10 +321,10 @@ print_status_throttle_rate(char* first, char* last, bool up, const ui::ThrottleN
char* firstc = throttle_str;
char* lastc = throttle_str + 50 - 1;
for (const auto& throttle_name : throttle_names) {
for (ui::ThrottleNameList::const_iterator itr = throttle_names.begin(), laste = throttle_names.end(); itr != laste; itr++) {
if (!throttle_name.empty() && (up ? torrent::up_throttle_global()->is_throttled() : torrent::down_throttle_global()->is_throttled())) {
int64_t throttle_rate_value = control->core()->retrieve_throttle_value(throttle_name, true, up);
if (!(*itr).empty() && (up ? torrent::up_throttle_global()->is_throttled() : torrent::down_throttle_global()->is_throttled())) {
int64_t throttle_rate_value = control->core()->retrieve_throttle_value(*itr, true, up);
if (throttle_rate_value > -1) {
double throttle_rate = (double)throttle_rate_value / 1024.0;
@@ -326,6 +333,7 @@ print_status_throttle_rate(char* first, char* last, bool up, const ui::ThrottleN
firstc = print_buffer(firstc, lastc, "|%3.1f", throttle_rate);
}
}
}
// Add temp buffer into main buffer if temp buffer isn't empty
@@ -376,37 +384,20 @@ print_status_info(char* first, char* last) {
first = print_buffer(first, last, " KB]");
first = print_buffer(first, last, " [Port: %i]", (unsigned int)torrent::runtime::network_manager()->listen_port());
first = print_buffer(first, last, " [Port: %i]", (unsigned int)torrent::connection_manager()->listen_port());
auto local_address = torrent::config::network_config()->local_address_best_match();
if (!torrent::sa_is_any(local_address.get())) {
if (!rak::socket_address::cast_from(torrent::connection_manager()->local_address())->is_address_any()) {
first = print_buffer(first, last, " [Local ");
first = print_address(first, last, local_address.get());
first = print_address(first, last, torrent::connection_manager()->local_address());
first = print_buffer(first, last, "]");
}
if (first > last)
throw torrent::internal_error("print_status_info(...) wrote past end of the buffer.");
auto bind_inet_address = torrent::config::network_config()->bind_inet_address();
auto bind_inet6_address = torrent::config::network_config()->bind_inet6_address();
bool show_bind_inet = !torrent::sa_is_any(bind_inet_address.get());
bool show_bind_inet6 = !torrent::sa_is_any(bind_inet6_address.get());
if (show_bind_inet || show_bind_inet6) {
if (!rak::socket_address::cast_from(torrent::connection_manager()->bind_address())->is_address_any()) {
first = print_buffer(first, last, " [Bind ");
if (show_bind_inet)
first = print_address(first, last, bind_inet_address.get());
if (show_bind_inet6) {
if (show_bind_inet)
first = print_buffer(first, last, " / ");
first = print_address(first, last, bind_inet6_address.get());
}
first = print_address(first, last, torrent::connection_manager()->bind_address());
first = print_buffer(first, last, "]");
}
@@ -424,14 +415,14 @@ print_status_extra(char* first, char* last) {
torrent::resource_manager()->max_download_unchoked());
first = print_buffer(first, last, " [H %u/%u]",
torrent::net_thread::http_stack()->size(),
torrent::net_thread::http_stack()->max_total_connections());
control->core()->http_stack()->active(),
control->core()->http_stack()->max_active());
first = print_buffer(first, last, " [S %i/%i/%i]",
torrent::total_handshakes(),
torrent::connection_manager()->size(),
torrent::connection_manager()->max_size());
first = print_buffer(first, last, " [F %i/%i]",
torrent::file_manager()->open_files(),
torrent::file_manager()->max_open_files());
+36 -1
View File
@@ -1,10 +1,45 @@
// 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 <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_DISPLAY_UTILS_H
#define RTORRENT_DISPLAY_UTILS_H
#include <ctime>
#include <cstdio>
#include <string>
#include <vector>
namespace core {
class Download;
-2
View File
@@ -4,8 +4,6 @@
#include <stdexcept>
#include <torrent/utils/chrono.h>
namespace display {
Window::SlotTimer Window::m_slot_schedule;
+2 -1
View File
@@ -55,8 +55,9 @@ WindowDownloadChunksSeen::redraw() {
const torrent::Bitfield* bitfield = m_download->download()->file_list()->bitfield();
const torrent::TransferList* transfers = m_download->download()->transfer_list();
std::vector<torrent::BlockList*> transferChunks(transfers->begin(), transfers->end());
std::vector<torrent::BlockList*> transferChunks(transfers->size(), 0);
std::copy(transfers->begin(), transfers->end(), transferChunks.begin());
std::sort(transferChunks.begin(), transferChunks.end());
std::vector<torrent::BlockList*>::const_iterator itrTransfer = transferChunks.begin();
+8 -8
View File
@@ -40,7 +40,7 @@ WindowDownloadTransferList::redraw() {
m_canvas->print(0, y, "%5u [P: %u F: %u]", (*itr)->index(), (*itr)->priority(), (*itr)->failed());
// Handle window size.
for (const auto& bItr : **itr) {
for (torrent::BlockList::const_iterator bItr = (*itr)->begin(), bLast = (*itr)->end(); bItr != bLast; ++bItr) {
if (m_canvas->get_x() >= m_canvas->width() - 1) {
if (++y >= m_canvas->height())
break;
@@ -51,22 +51,22 @@ WindowDownloadTransferList::redraw() {
char id;
chtype attr = A_NORMAL;
if (bItr.is_finished()) {
if (bItr->is_finished()) {
attr = A_REVERSE;
id = key_id(bItr.leader()->const_peer_info());
id = key_id(bItr->leader()->const_peer_info());
} else if (bItr.is_transfering()) {
} else if (bItr->is_transfering()) {
attr = A_BOLD;
id = key_id(bItr.leader()->const_peer_info());
id = key_id(bItr->leader()->const_peer_info());
} else if (bItr.queued()->size() >= 1) {
id = std::tolower(key_id(bItr.queued()->back()->const_peer_info()));
} else if (bItr->queued()->size() >= 1) {
id = std::tolower(key_id(bItr->queued()->back()->const_peer_info()));
} else {
id = '.';
}
if (bItr.size_all() > 1)
if (bItr->size_all() > 1)
attr |= A_UNDERLINE;
m_canvas->print_char(attr | id);
+15 -18
View File
@@ -3,8 +3,8 @@
#include "display/window_http_queue.h"
#include <stdexcept>
#include <torrent/net/http_get.h>
#include "core/curl_get.h"
#include "core/http_queue.h"
#include "display/canvas.h"
@@ -17,9 +17,8 @@ WindowHttpQueue::WindowHttpQueue(core::HttpQueue* q) :
m_queue(q) {
set_active(false);
m_conn_insert = m_queue->signal_insert().insert(m_queue->signal_insert().end(), [this](auto h) { receive_insert(h); });
m_conn_erase = m_queue->signal_erase().insert(m_queue->signal_insert().end(), [this](auto h) { receive_erase(h); });
m_conn_insert = m_queue->signal_insert().insert(m_queue->signal_insert().end(), [this](auto* h) { receive_insert(h); });
m_conn_erase = m_queue->signal_erase().insert(m_queue->signal_insert().end(), [this](auto* h) { receive_erase(h); });
m_task_deactivate.slot() = [this] {
if (!m_container.empty())
@@ -56,14 +55,14 @@ WindowHttpQueue::redraw() {
Container::iterator itr = m_container.begin();
while (itr != m_container.end() && pos + 10 < m_canvas->width()) {
if (!itr->m_http.is_valid())
if (itr->m_http == NULL)
m_canvas->print(pos, 0, "[%s done]", itr->m_name.c_str());
else if (itr->m_http.size_total() == 0)
else if (itr->m_http->size_total() == 0)
m_canvas->print(pos, 0, "[%s ---%%]", itr->m_name.c_str());
else
m_canvas->print(pos, 0, "[%s %3i%%]", itr->m_name.c_str(), (int)(100.0 * itr->m_http.size_done() / itr->m_http.size_total()));
m_canvas->print(pos, 0, "[%s %3i%%]", itr->m_name.c_str(), (int)(100.0 * itr->m_http->size_done() / itr->m_http->size_total()));
pos += itr->m_name.size() + 6;
++itr;
@@ -73,7 +72,7 @@ WindowHttpQueue::redraw() {
void
WindowHttpQueue::cleanup_list() {
for (Container::iterator itr = m_container.begin(); itr != m_container.end(); ) {
if (!itr->m_http.is_valid() && itr->m_timer < torrent::this_thread::cached_time()) {
if (itr->m_http == nullptr && itr->m_timer < torrent::this_thread::cached_time()) {
itr = m_container.erase(itr);
continue;
}
@@ -83,10 +82,10 @@ WindowHttpQueue::cleanup_list() {
}
std::string
WindowHttpQueue::create_name(torrent::net::HttpGet http_get) {
size_t p = http_get.url().rfind('/', http_get.url().size() - std::min<int>(10, http_get.url().size()));
WindowHttpQueue::create_name(core::CurlGet* h) {
size_t p = h->url().rfind('/', h->url().size() - std::min<int>(10, h->url().size()));
std::string n = p != std::string::npos ? http_get.url().substr(p) : http_get.url();
std::string n = p != std::string::npos ? h->url().substr(p) : h->url();
if (n.empty())
throw std::logic_error("WindowHttpQueue::create_name(...) made a bad string");
@@ -106,8 +105,8 @@ WindowHttpQueue::create_name(torrent::net::HttpGet http_get) {
}
void
WindowHttpQueue::receive_insert(torrent::net::HttpGet http_get) {
m_container.push_back(Node(http_get, create_name(http_get)));
WindowHttpQueue::receive_insert(core::CurlGet* h) {
m_container.push_back(Node(h, create_name(h)));
if (!is_active()) {
set_active(true);
@@ -118,15 +117,13 @@ WindowHttpQueue::receive_insert(torrent::net::HttpGet http_get) {
}
void
WindowHttpQueue::receive_erase(torrent::net::HttpGet http_get) {
auto itr = std::find_if(m_container.begin(),
m_container.end(),
[http_get](auto& n) { return http_get == n.m_http; });
WindowHttpQueue::receive_erase(core::CurlGet* h) {
Container::iterator itr = std::find_if(m_container.begin(), m_container.end(), [h](Node& n) { return h == n.m_http; });
if (itr == m_container.end())
throw std::logic_error("WindowHttpQueue::receive_erase(...) tried to remove an object we don't have");
itr->m_http = torrent::net::HttpGet();
itr->m_http = nullptr;
itr->m_timer = torrent::this_thread::cached_time() + 4s;
mark_dirty();
+9 -9
View File
@@ -3,20 +3,20 @@
#include <functional>
#include <list>
#include <torrent/net/http_get.h>
#include "window.h"
namespace core {
class HttpQueue;
class CurlGet;
class HttpQueue;
}
namespace display {
class WindowHttpQueue : public Window {
public:
typedef std::function<void (torrent::net::HttpGet)> slot_curl_get;
typedef std::list<slot_curl_get> signal_curl_get;
typedef std::function<void (core::CurlGet*)> slot_curl_get;
typedef std::list<slot_curl_get> signal_curl_get;
WindowHttpQueue(core::HttpQueue* q);
~WindowHttpQueue() override;
@@ -25,9 +25,9 @@ public:
private:
struct Node {
Node(torrent::net::HttpGet h, const std::string& n) : m_http(h), m_name(n) {}
Node(core::CurlGet* h, const std::string& n) : m_http(h), m_name(n) {}
torrent::net::HttpGet m_http{};
core::CurlGet* m_http{};
std::string m_name;
std::chrono::microseconds m_timer{};
};
@@ -36,10 +36,10 @@ private:
void cleanup_list();
void receive_insert(torrent::net::HttpGet h);
void receive_erase(torrent::net::HttpGet h);
void receive_insert(core::CurlGet* h);
void receive_erase(core::CurlGet* h);
static std::string create_name(torrent::net::HttpGet h);
static std::string create_name(core::CurlGet* h);
core::HttpQueue* m_queue;
Container m_container;
+3 -3
View File
@@ -1,10 +1,10 @@
#include "config.h"
#include <stdexcept>
#include <rak/socket_address.h>
#include <torrent/rate.h>
#include <torrent/data/block_transfer.h>
#include <torrent/data/piece.h>
#include <torrent/net/socket_address.h>
#include <torrent/peer/client_list.h>
#include <torrent/peer/peer_info.h>
@@ -63,7 +63,7 @@ WindowPeerList::redraw() {
x = 0;
auto ip_address = torrent::sa_addr_str(p->address());
std::string ip_address = rak::socket_address::cast_from(p->address())->address_str();
if (ip_address.size() >= 24) {
ip_address.replace(ip_address.begin() + 21, ip_address.end(), "...");
@@ -92,7 +92,7 @@ WindowPeerList::redraw() {
peerType = 'u';
else if (p->peer_info()->is_preferred())
peerType = 'p';
else
else
peerType = ' ';
m_canvas->print(x, y, "%c%c/%c%c/%c%c",
+1 -2
View File
@@ -16,8 +16,7 @@ WindowText::WindowText(rpc::target_type target, extent_type margin) :
void
WindowText::clear() {
for (auto t : *this)
delete t;
std::for_each(begin(), end(), [](TextElement* text) { delete text; });
base_type::clear();
delete m_errorHandler;
+16 -12
View File
@@ -56,8 +56,8 @@ PathInput::pressed(int key) {
return TextInput::pressed(key);
} else if (m_showNext) {
for (auto& itr : m_signal_show_next)
itr();
for (signal_void::iterator itr = m_signal_show_next.begin(), last = m_signal_show_next.end(); itr != last; itr++)
(*itr)();
} else {
receive_do_complete();
@@ -66,6 +66,17 @@ PathInput::pressed(int key) {
return true;
}
struct _transform_filename {
void operator () (utils::directory_entry& entry) {
#ifdef __sun__
if (entry.s_type & S_IFDIR)
#else
if (entry.s_type == DT_DIR)
#endif
entry.s_name += '/';
}
};
void
PathInput::receive_do_complete() {
lt_log_print(torrent::LOG_UI_EVENTS, "path_input: received completion");
@@ -80,14 +91,7 @@ PathInput::receive_do_complete() {
return;
}
for (auto& entry : dir) {
#ifdef __sun__
if (entry.s_type & S_IFDIR)
#else
if (entry.s_type == DT_DIR)
#endif
entry.s_name += '/';
}
std::for_each(dir.begin(), dir.end(), _transform_filename());
range_type r = find_incomplete(dir, str().substr(dirEnd, get_pos()));
@@ -112,8 +116,8 @@ PathInput::receive_do_complete() {
if (m_showNext) {
lt_log_print(torrent::LOG_UI_EVENTS, "path_input: show next page");
for (auto& itr : m_signal_show_range)
itr(r.first, r.second);
for (signal_itr_itr::iterator itr = m_signal_show_range.begin(), last = m_signal_show_range.end(); itr != last; itr++)
(*itr)(r.first, r.second);
}
}
+68 -113
View File
@@ -1,16 +1,17 @@
#include "config.h"
#define __STDC_FORMAT_MACROS
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <inttypes.h>
#include <typeinfo>
#include <unistd.h>
#include <torrent/http.h>
#include <torrent/torrent.h>
#include <torrent/exceptions.h>
#include <torrent/data/chunk_utils.h>
#include <torrent/utils/chrono.h>
#include <torrent/utils/log.h>
#include <rak/error_number.h>
@@ -81,44 +82,15 @@ parse_options(int argc, char** argv) {
}
}
void
initialize_rpc_slots() {
rpc::rpc.slot_find_download() = [](const char* hash) {
return control->core()->download_list()->find_hex_ptr(hash);
};
rpc::rpc.slot_find_file() = [](core::Download* d, uint32_t index) -> torrent::File* {
if (index >= d->file_list()->size_files())
throw torrent::input_error("invalid parameters: index not found");
return (*d->file_list())[index].get();
};
rpc::rpc.slot_find_tracker() = [](core::Download* d, uint32_t index) -> torrent::tracker::Tracker {
if (index >= d->tracker_controller().size())
throw torrent::input_error("invalid parameters: index not found");
// TODO: This should be rewritten to check if the tracker is valid and use a different
// function.
return d->tracker_controller().at(index);
};
rpc::rpc.slot_find_peer() = [](core::Download* d, const torrent::HashString& hash) -> torrent::Peer* {
auto itr = d->connection_list()->find(hash.c_str());
if (itr == d->connection_list()->end())
throw torrent::input_error("invalid parameters: hash not found");
return *itr;
};
}
void
load_session_torrents() {
utils::Directory entries = control->core()->download_store()->get_formated_entries();
for (const auto& entry : entries) {
for (utils::Directory::const_iterator first = entries.begin(), last = entries.end(); first != last; ++first) {
// We don't really support session torrents that are links. These
// would be overwritten anyway on exit, and thus not really be
// useful.
if (!entry.is_file())
if (!first->is_file())
continue;
core::DownloadFactory* f = new core::DownloadFactory(control->core());
@@ -127,7 +99,7 @@ load_session_torrents() {
f->set_session(true);
f->set_init_load(true);
f->slot_finished([f](){ delete f; });
f->load(entries.path() + entry.s_name);
f->load(entries.path() + first->s_name);
f->commit();
}
}
@@ -202,14 +174,8 @@ main(int argc, char** argv) {
if (torrent::utils::Thread::should_handle_sigusr1())
SignalHandler::set_handler(SIGUSR1, std::bind(&do_nothing));
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");
torrent::log_add_group_output(torrent::LOG_DHT_CONTROLLER, "complete");
initialize_rpc_slots();
torrent::log_add_group_output(torrent::LOG_NOTICE, "important");
torrent::log_add_group_output(torrent::LOG_INFO, "complete");
torrent::initialize();
torrent::set_main_thread_slots(std::bind(&client_perform));
@@ -279,7 +245,7 @@ main(int argc, char** argv) {
"file.prioritize_toc.first.set = {*.avi,*.mp4,*.mkv,*.gz}\n"
"file.prioritize_toc.last.set = {*.zip}\n"
// Allow setting 'group.view' as constant, so that we can't
// Allow setting 'group2.view' as constant, so that we can't
// modify the value. And look into the possibility of making
// 'const' use non-heap memory, as we know they can't be
// erased.
@@ -350,76 +316,72 @@ 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");
CMD2_REDIRECT_GENERIC("upload_rate", "throttle.global_up.max_rate.set_kb");
CMD2_REDIRECT_GENERIC("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");
CMD2_REDIRECT_GENERIC("ratio.enable", "group.seeding.ratio.enable");
CMD2_REDIRECT_GENERIC("ratio.disable", "group.seeding.ratio.disable");
CMD2_REDIRECT_GENERIC("ratio.min", "group2.seeding.ratio.min");
CMD2_REDIRECT_GENERIC("ratio.max", "group2.seeding.ratio.max");
CMD2_REDIRECT_GENERIC("ratio.upload", "group2.seeding.ratio.upload");
CMD2_REDIRECT_GENERIC("ratio.min.set", "group2.seeding.ratio.min.set");
CMD2_REDIRECT_GENERIC("ratio.max.set", "group2.seeding.ratio.max.set");
CMD2_REDIRECT_GENERIC("ratio.upload.set", "group2.seeding.ratio.upload.set");
CMD2_REDIRECT("encryption", "protocol.encryption.set");
CMD2_REDIRECT("encoding_list", "encoding.add");
CMD2_REDIRECT_GENERIC("encryption", "protocol.encryption.set");
CMD2_REDIRECT_GENERIC("encoding_list", "encoding.add");
CMD2_REDIRECT("connection_leech", "protocol.connection.leech.set");
CMD2_REDIRECT("connection_seed", "protocol.connection.seed.set");
CMD2_REDIRECT_GENERIC("connection_leech", "protocol.connection.leech.set");
CMD2_REDIRECT_GENERIC("connection_seed", "protocol.connection.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");
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");
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");
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");
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");
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");
CMD2_REDIRECT("max_memory_usage", "pieces.memory.max.set");
CMD2_REDIRECT_GENERIC("max_memory_usage", "pieces.memory.max.set");
CMD2_REDIRECT("bind", "network.bind_address.set");
CMD2_REDIRECT("ip", "network.local_address.set");
CMD2_REDIRECT("port_range", "network.port_range.set");
CMD2_REDIRECT ("bind", "network.bind_address.set");
CMD2_REDIRECT ("ip", "network.local_address.set");
CMD2_REDIRECT ("port_range", "network.port_range.set");
CMD2_REDIRECT("dht", "dht.mode.set");
CMD2_REDIRECT_GENERIC("dht", "dht.mode.set");
CMD2_REDIRECT_GENERIC("dht_port", "dht.port.set");
CMD2_REDIRECT("port_random", "network.port_random.set");
CMD2_REDIRECT("proxy_address", "network.proxy_address.set");
CMD2_REDIRECT ("port_random", "network.port_random.set");
CMD2_REDIRECT ("proxy_address", "network.proxy_address.set");
CMD2_REDIRECT("scgi_port", "network.scgi.open_port");
CMD2_REDIRECT("scgi_local", "network.scgi.open_local");
CMD2_REDIRECT ("scgi_port", "network.scgi.open_port");
CMD2_REDIRECT ("scgi_local", "network.scgi.open_local");
CMD2_REDIRECT("directory", "directory.default.set");
CMD2_REDIRECT("session", "session.path.set");
CMD2_REDIRECT_GENERIC("directory", "directory.default.set");
CMD2_REDIRECT_GENERIC("session", "session.path.set");
CMD2_REDIRECT("check_hash", "pieces.hash.on_completion.set");
CMD2_REDIRECT ("check_hash", "pieces.hash.on_completion.set");
CMD2_REDIRECT("key_layout", "keys.layout.set");
CMD2_REDIRECT ("key_layout", "keys.layout.set");
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");
CMD2_REDIRECT_GENERIC("to_gm_time", "convert.gm_time");
CMD2_REDIRECT_GENERIC("to_gm_date", "convert.gm_date");
CMD2_REDIRECT_GENERIC("to_time", "convert.time");
CMD2_REDIRECT_GENERIC("to_date", "convert.date");
CMD2_REDIRECT_GENERIC("to_elapsed_time", "convert.elapsed_time");
CMD2_REDIRECT_GENERIC("to_kb", "convert.kb");
CMD2_REDIRECT_GENERIC("to_mb", "convert.mb");
CMD2_REDIRECT_GENERIC("to_xb", "convert.xb");
CMD2_REDIRECT_GENERIC("to_throttle", "convert.throttle");
CMD2_REDIRECT("torrent_list_layout", "ui.torrent_list.layout.set");
// Deprecate:
CMD2_REDIRECT("network.http.max_open", "network.http.max_total_connections");
CMD2_REDIRECT("network.http.max_open.set", "network.http.max_total_connections.set");
CMD2_REDIRECT ("torrent_list_layout", "ui.torrent_list.layout.set");
// Deprecated commands. Don't use these anymore.
//
@@ -427,17 +389,17 @@ main(int argc, char** argv) {
// call style, where the first argument is the target.
// if (rpc::call_command_value("method.use_intermediate") == 1) {
// CMD2_REDIRECT("execute", "execute2");
// CMD2_REDIRECT_GENERIC("execute", "execute2");
// CMD2_REDIRECT("schedule", "schedule2");
// CMD2_REDIRECT("schedule_remove", "schedule_remove2");
// CMD2_REDIRECT_GENERIC("schedule", "schedule2");
// CMD2_REDIRECT_GENERIC("schedule_remove", "schedule_remove2");
// } else if (rpc::call_command_value("method.use_intermediate") == 2) {
// Allow for use in config files, etc, just don't export it.
// CMD2_REDIRECT_NO_EXPORT("execute", "execute2");
// CMD2_REDIRECT_GENERIC_NO_EXPORT("execute", "execute2");
// CMD2_REDIRECT_NO_EXPORT("schedule", "schedule2");
// CMD2_REDIRECT_NO_EXPORT("schedule_remove", "schedule_remove2");
// CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule", "schedule2");
// CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule_remove", "schedule_remove2");
// }
// if (rpc::call_command_value("method.use_deprecated") == 1) {
@@ -494,24 +456,17 @@ main(int argc, char** argv) {
} catch (torrent::internal_error& e) {
control->cleanup_exception();
std::cout << "rtorrent: caught torrent::internal_error: "
<< e.what() << std::endl
std::cout << "Caught internal_error: " << e.what() << std::endl
<< e.backtrace();
lt_log_print_dump(torrent::LOG_CRITICAL, e.backtrace().c_str(), e.backtrace().size(),
"Caught internal_error: '%s'.", e.what());
torrent::log_cleanup();
return -1;
} catch (std::exception& e) {
control->cleanup_exception();
std::cout << "rtorrent: caught" << typeid(e).name() << " : " << e.what() << std::endl;
std::cout << "rtorrent: " << e.what() << std::endl;
lt_log_print(torrent::LOG_CRITICAL, "Caught exception: '%s'.", e.what());
torrent::log_cleanup();
return -1;
}
@@ -635,7 +590,7 @@ do_panic(int signum) {
void
print_help() {
std::cout << "Rakshasa's BitTorrent client version " PACKAGE_VERSION "." << std::endl;
std::cout << "Rakshasa's BitTorrent client version " VERSION "." << std::endl;
std::cout << std::endl;
std::cout << "All value pairs (f.ex rate and queue size) will be in the UP/DOWN" << std::endl;
std::cout << "order. Use the up/down/left/right arrow keys to move between screens." << std::endl;
+4 -4
View File
@@ -86,17 +86,17 @@ bool
OptionParser::has_flag(char flag, int argc, char** argv) {
char options[3] = { '-', flag, '\0' };
return std::any_of(argv, argv + argc, [&options](char* c) { return std::strcmp(c, options) == 0; });
return std::find_if(argv, argv + argc, [&options](char* c) { return std::strcmp(c, options) == 0; }) != argv + argc;
}
std::string
OptionParser::create_optstring() {
std::string s;
for (auto& itr : m_container) {
s += itr.first;
for (Container::iterator itr = m_container.begin(); itr != m_container.end(); ++itr) {
s += itr->first;
if (itr.second.m_useOption)
if (itr->second.m_useOption)
s += ':';
}
+4 -4
View File
@@ -27,7 +27,7 @@ CommandMap::insert(const key_type& key, int flags, const char* parm, const char*
throw torrent::internal_error("CommandMap::insert(...) tried to insert an already existing key.");
// TODO: This is not honoring the public_xmlrpc flags!!!
if (rpc::rpc.is_handlers_initialized() && (flags & flag_public_rpc))
if (rpc::rpc.is_initialized() && (flags & flag_public_rpc))
rpc::rpc.insert_command(key.c_str(), parm, doc);
return base_type::insert(itr, value_type(key, command_map_data_type(flags, parm, doc)));
@@ -55,10 +55,10 @@ CommandMap::create_redirect(const key_type& key_new, const key_type& key_dest, i
if (dest_itr == base_type::end())
throw torrent::input_error("Tried to redirect to a key that doesn't exist: '" + std::string(key_dest) + "'.");
if (new_itr != base_type::end())
throw torrent::input_error("Tried to create a redirect key that already exists: '" + std::string(key_new) + "'.");
if (dest_itr->second.m_flags & flag_is_redirect)
throw torrent::input_error("Tried to redirect to a key that is not marked 'flag_is_redirect': '" +
std::string(key_dest) + "'.");
@@ -68,7 +68,7 @@ CommandMap::create_redirect(const key_type& key_new, const key_type& key_dest, i
flags |= dest_itr->second.m_flags & ~(flag_has_redirects | flag_public_rpc);
// TODO: This is not honoring the public_xmlrpc flags!!!
if (rpc::rpc.is_handlers_initialized() && (flags & flag_public_rpc))
if (rpc::rpc.is_initialized() && (flags & flag_public_rpc))
rpc::rpc.insert_command(key_new.c_str(), dest_itr->second.m_parm, dest_itr->second.m_doc);
iterator itr = base_type::insert(base_type::end(),
+3 -2
View File
@@ -53,8 +53,9 @@ public:
static const int flag_is_redirect = 0x20;
static const int flag_has_redirects = 0x40;
static const int flag_file_target = 0x100;
static const int flag_tracker_target = 0x200;
static const int flag_no_target = 0x100;
static const int flag_file_target = 0x200;
static const int flag_tracker_target = 0x400;
CommandMap() = default;
+1 -3
View File
@@ -7,7 +7,6 @@
#include <time.h>
#include <rak/string_manip.h>
#include <torrent/exceptions.h>
#include <torrent/utils/chrono.h>
#include "rpc/command_scheduler_item.h"
#include "rpc/parse_commands.h"
@@ -15,8 +14,7 @@
namespace rpc {
CommandScheduler::~CommandScheduler() {
for (auto item : *this)
delete item;
std::for_each(begin(), end(), [](CommandSchedulerItem* item) { delete item; });
}
CommandScheduler::iterator
-1
View File
@@ -3,7 +3,6 @@
#include "rpc/command_scheduler_item.h"
#include <torrent/exceptions.h>
#include <torrent/utils/chrono.h>
namespace rpc {
+15 -11
View File
@@ -70,8 +70,9 @@ object_to_json(const torrent::Object& object) noexcept {
return object.as_string();
case torrent::Object::TYPE_LIST: {
json result = json::array();
for (const auto& obj : object.as_list())
result.push_back(object_to_json(obj));
std::transform(object.as_list().cbegin(), object.as_list().cend(), std::back_inserter(result), [](const torrent::Object& element) {
return object_to_json(element);
});
return result;
}
case torrent::Object::TYPE_MAP: {
@@ -87,8 +88,9 @@ object_to_json(const torrent::Object& object) noexcept {
const auto& dict_obj = object.as_dict_obj();
if (dict_obj.is_list()) {
for (const auto& element : dict_obj.as_list())
result.push_back(object_to_json(element));
std::transform(dict_obj.as_list().cbegin(), dict_obj.as_list().cend(), std::back_inserter(result), [](const torrent::Object& element) {
return object_to_json(element);
});
} else {
result.push_back(object_to_json(dict_obj));
}
@@ -122,16 +124,18 @@ jsonrpc_call_command(const std::string& method, const json& params) {
std::function<void()> deleter = []() {};
utils::scope_guard guard([&deleter]() { deleter(); });
// Provide a blank target if none was provided
if (params_object_list.empty())
params_object_list.push_back("");
if (!(itr->second.m_flags & CommandMap::flag_no_target)) {
// Provide a blank target if none was provided
if (params_object_list.empty())
params_object_list.push_back("");
if (!params_object_list.begin()->is_string())
throw torrent::input_error("invalid parameters: target must be a string");
if (!params_object_list.begin()->is_string())
throw torrent::input_error("invalid parameters: target must be a string");
RpcManager::object_to_target(params_object_list.begin()->as_string(), itr->second.m_flags, &target, &deleter);
RpcManager::object_to_target(params_object_list.begin()->as_string(), itr->second.m_flags, &target, &deleter);
params_object_list.erase(params_object_list.begin());
params_object_list.erase(params_object_list.begin());
}
const auto& result = rpc::commands.call_command(itr, params_object, target);
+44 -37
View File
@@ -23,17 +23,15 @@
namespace rpc {
#ifdef HAVE_LUA
const int LuaEngine::flag_string;
const std::string LuaEngine::module_name = "rtorrent";
const std::string LuaEngine::local_path = LUA_DATADIR "/?.lua;" LUA_DATADIR "/?/init.lua";
#ifdef HAVE_LUA
LuaEngine::LuaEngine() {
m_luaState = luaL_newstate();
luaL_openlibs(m_luaState);
set_package_preload();
override_package_path();
}
LuaEngine::~LuaEngine() { lua_close(m_luaState); }
@@ -48,20 +46,6 @@ LuaEngine::set_package_preload() {
lua_pop(l_state, 2);
}
void
LuaEngine::override_package_path() {
auto l_state = m_luaState;
lua_getglobal(l_state, "package");
lua_getfield(l_state, -1, "path");
std::string current_path(lua_tostring(l_state, -1));
std::string new_path = local_path + ';' + current_path;
lua_pushstring(l_state, new_path.c_str());
lua_setfield(l_state, -3, "path");
lua_pop(l_state, 2);
}
void
check_lua_status(lua_State* l_state, int status) {
if (status != LUA_OK) {
@@ -84,21 +68,15 @@ LuaEngine::search_lua_path(lua_State* l_state) {
};
// Tokenize path using ';' as delimiter
for (size_t pos = 0, end = 0; end != std::string::npos; pos = end + 1) {
end = lua_path.find(';', pos);
std::string file_path((end == std::string::npos)
? lua_path.substr(pos)
: lua_path.substr(pos, end - pos));
if (!file_path.empty()) {
size_t ppos = 0;
while ((ppos = file_path.find('?')) != std::string::npos) {
file_path.replace(ppos, 1, LuaEngine::module_name);
}
if (file_exists(file_path)) {
return file_path;
}
size_t pos = 0, end;
while ((end = lua_path.find(';', pos)) != std::string::npos) {
std::string file_path(lua_path.substr(pos, end - pos));
size_t ppos = 0;
while ((ppos = file_path.find('?')) != std::string::npos) {
file_path.replace(ppos, 1, LuaEngine::module_name);
}
if (file_exists(file_path)) {
return file_path;
}
}
return "";
@@ -124,12 +102,12 @@ LuaEngine::lua_rtorrent_call(lua_State* l_state) {
const auto& result = rpc::commands.call_command(itr, object, target);
object_to_lua(l_state, result);
if (deleter) deleter();
deleter();
return 1;
} catch (torrent::base_error& e) {
if (deleter) deleter();
deleter();
throw luaL_error(l_state, e.what());
}
}
@@ -241,7 +219,7 @@ object_to_lua(lua_State* l_state, torrent::Object const& object) {
// Converts an object to a single Lua stack object
switch (object.type()) {
case torrent::Object::TYPE_VALUE:
lua_pushinteger(l_state, static_cast<int64_t>(object.as_value()));
lua_pushnumber(l_state, static_cast<double>(object.as_value()));
break;
case torrent::Object::TYPE_NONE:
lua_pushnil(l_state);
@@ -288,7 +266,7 @@ lua_to_object(lua_State* l_state) {
case LUA_TBOOLEAN:
return torrent::Object(lua_toboolean(l_state, -1));
case LUA_TNIL:
return torrent::Object(torrent::Object());
return torrent::Object((torrent::Object::value_type)0);
case LUA_TTABLE: {
lua_pushnil(l_state);
int status = lua_next(l_state, -2);
@@ -370,6 +348,35 @@ lua_callstack_to_object(lua_State* l_state, int command_flags, rpc::target_type*
return result;
}
int
lua_rtorrent_call(lua_State* l_state) {
auto method = lua_tostring(l_state, 1);
lua_remove(l_state, 1);
rpc::CommandMap::iterator itr = rpc::commands.find(method);
if (itr == rpc::commands.end()) {
throw torrent::input_error("method not found: " + std::string(method));
}
auto target = rpc::make_target();
auto deleter = std::function<void()>();
auto object = lua_callstack_to_object(l_state, itr->second.m_flags, &target, &deleter);
try {
const auto& result = rpc::commands.call_command(itr, object, target);
object_to_lua(l_state, result);
deleter();
return 1;
} catch (torrent::base_error& e) {
deleter();
throw luaL_error(l_state, e.what());
}
}
torrent::Object
execute_lua(LuaEngine* engine, rpc::target_type target_type, torrent::Object const& raw_args, int flags) {
size_t lua_argc = 1; // Target is always present, even if empty
-2
View File
@@ -14,7 +14,6 @@ class LuaEngine {
public:
static const int flag_string = 0x1;
static const std::string module_name;
static const std::string local_path;
LuaEngine();
~LuaEngine();
@@ -24,7 +23,6 @@ public:
static int lua_init_module(lua_State* l_state);
static int lua_rtorrent_call(lua_State* l_state);
void set_package_preload();
void override_package_path();
lua_State* state() { return m_luaState; }
private:
+5 -5
View File
@@ -239,7 +239,7 @@ object_storage::set_multi_key_obj(const torrent::raw_string& key, const std::str
if (r_itr == m_rlookup.end())
r_itr = m_rlookup.insert(std::make_pair(cmd_key, rlookup_type::mapped_type())).first;
if (std::none_of(r_itr->second.begin(), r_itr->second.end(), [key](auto type) { return key == type->first; }))
if (std::find_if(r_itr->second.begin(), r_itr->second.end(), [key](value_type* type) { return key == type->first; }) == r_itr->second.end())
r_itr->second.push_back(&*itr);
}
@@ -253,8 +253,8 @@ object_storage::rlookup_list(const std::string& cmd_key) {
rlookup_iterator r_itr = m_rlookup.find(cmd_key);
if (r_itr != m_rlookup.end())
for (auto pair : r_itr->second)
result.push_back(pair->first.c_str());
std::transform(r_itr->second.begin(), r_itr->second.end(), std::back_inserter(result),
std::bind(&key_type::c_str, std::bind(std::mem_fn(&value_type::first), std::placeholders::_1)));
return result;
}
@@ -266,8 +266,8 @@ object_storage::rlookup_clear(const std::string& cmd_key) {
if (r_itr == m_rlookup.end())
return;
for (auto& first : r_itr->second)
first->second.object.erase_key(cmd_key);
for (rlookup_mapped_iterator first = r_itr->second.begin(), last = r_itr->second.end(); first != last; first++)
(*first)->second.object.erase_key(cmd_key);
r_itr->second.clear();
}
+10 -10
View File
@@ -190,7 +190,7 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
}
if (depth > 3)
throw torrent::input_error("Max 3 parentheses per object allowed.");
throw torrent::input_error("Max 3 parantheses per object allowed.");
*dest = torrent::Object::create_dict_key();
dest->set_flags(torrent::Object::flag_function << (depth - 1));
@@ -214,7 +214,7 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
}
if (depth != 0)
throw torrent::input_error("Parentheses mismatch.");
throw torrent::input_error("Parantheses mismatch.");
return first;
@@ -405,12 +405,12 @@ convert_to_value_nothrow(const torrent::Object& src, int64_t* value, int base, i
case torrent::Object::TYPE_RAW_STRING: {
const torrent::raw_string& str = src.as_raw_string();
auto buffer = std::make_unique<char[]>(str.size() + 1);
std::memcpy(buffer.get(), str.data(), str.size());
char buffer[str.size() + 1];
std::memcpy(buffer, str.data(), str.size());
buffer[str.size()] = '\0';
return parse_skip_wspace(parse_value(buffer.get(), value, base, unit), buffer.get() + str.size())
== buffer.get() + str.size();
return parse_skip_wspace(parse_value(buffer, value, base, unit), buffer + str.size())
== buffer + str.size();
}
case torrent::Object::TYPE_NONE:
*value = 0;
@@ -453,8 +453,8 @@ print_object(char* first, char* last, const torrent::Object* src, int flags) {
if (first != last)
*first = '\0';
for (const auto& itr : src->as_list()) {
first = print_object(first, last, &itr, flags);
for (torrent::Object::list_const_iterator itr = src->as_list().begin(), itrEnd = src->as_list().end(); itr != itrEnd; itr++) {
first = print_object(first, last, &*itr, flags);
// Don't expand tilde after the first element in the list.
flags &= ~print_expand_tilde;
@@ -495,8 +495,8 @@ print_object_std(std::string* dest, const torrent::Object* src, int flags) {
return;
}
case torrent::Object::TYPE_LIST:
for (const auto& itr : src->as_list()) {
print_object_std(dest, &itr, flags);
for (torrent::Object::list_const_iterator itr = src->as_list().begin(), itrEnd = src->as_list().end(); itr != itrEnd; itr++) {
print_object_std(dest, &*itr, flags);
// Don't expand tilde after the first element in the list.
flags &= ~print_expand_tilde;
+7 -7
View File
@@ -43,11 +43,11 @@ parse_command_execute(target_type target, torrent::Object* object) {
if (object->is_list()) {
// For now, until we can flag the lists we want executed and those
// we can't, disable recursion completely.
for (auto& itr : object->as_list()) {
if (itr.is_list())
for (torrent::Object::list_iterator itr = object->as_list().begin(), last = object->as_list().end(); itr != last; itr++) {
if (itr->is_list())
continue;
parse_command_execute(target, &itr);
parse_command_execute(target, &*itr);
}
} else if (object->is_dict_key()) {
@@ -203,15 +203,15 @@ call_object(const torrent::Object& command, target_type target) {
{
torrent::Object result;
for (const auto& itr : command.as_list())
result = call_object(itr, target);
for (torrent::Object::list_const_iterator itr = command.as_list().begin(), last = command.as_list().end(); itr != last; itr++)
result = call_object(*itr, target);
return result;
}
case torrent::Object::TYPE_MAP:
{
for (const auto& itr : command.as_map())
call_object(itr.second, target);
for (torrent::Object::map_const_iterator itr = command.as_map().begin(), last = command.as_map().end(); itr != last; itr++)
call_object(itr->second, target);
return torrent::Object();
}
+1 -1
View File
@@ -55,7 +55,7 @@ parse_option_flag(const std::string& option, parse_option_flag_type ftor) {
if (first == next)
throw torrent::input_error(option);
if (std::any_of(next, last, [](char c) { return !std::isspace(c, std::locale::classic()); }))
if (std::find_if(next, last, [](char c) { return !std::isspace(c, std::locale::classic()); }) != last)
throw torrent::input_error(option);
return ftor(std::string(first, next));
+20 -19
View File
@@ -15,45 +15,46 @@ ExecFile execFile;
void
RpcManager::object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* target, std::function<void()>* deleter) {
if (!obj.is_string())
throw torrent::input_error("invalid parameters: target must be a string");
std::string target_string = obj.as_string();
bool require_index = (call_flags & (CommandMap::flag_tracker_target | CommandMap::flag_file_target));
if (target_string.size() == 0 && !require_index)
if (call_flags & CommandMap::flag_no_target)
return;
if (!obj.is_string()) {
throw torrent::input_error("invalid parameters: target must be a string");
}
std::string target_string = obj.as_string();
bool require_index = (call_flags & (CommandMap::flag_tracker_target | CommandMap::flag_file_target));
if (target_string.size() == 0 && !require_index) {
return;
}
// Length of SHA1 hash is 40
if (target_string.size() < 40)
if (target_string.size() < 40) {
throw torrent::input_error("invalid parameters: invalid target");
}
char type = 'd';
std::string hash;
std::string index;
const auto& delim_pos = target_string.find_first_of(':', 40);
if (delim_pos == target_string.npos ||
delim_pos + 2 >= target_string.size()) {
if (require_index) {
throw torrent::input_error("invalid parameters: no index");
}
hash = target_string;
} else {
hash = target_string.substr(0, delim_pos);
type = target_string[delim_pos + 1];
index = target_string.substr(delim_pos + 2);
}
core::Download* download = rpc.slot_find_download()(hash.c_str());
if (download == nullptr)
throw torrent::input_error("invalid parameters: info-hash not found");
try {
torrent::tracker::Tracker* tracker{};
torrent::tracker::Tracker* tracker;
switch (type) {
case 'd':
@@ -125,20 +126,15 @@ RpcManager::process(RPCType type, const char* in_buffer, uint32_t length, slot_r
}
void
RpcManager::initialize_handlers() {
if (m_handlers_initialized)
throw torrent::internal_error("handlers already initialized");
RpcManager::initialize() {
m_xmlrpc.initialize();
m_jsonrpc.initialize();
m_handlers_initialized = true;
m_initialized = true;
}
void
RpcManager::cleanup() {
m_handlers_initialized = false;
m_xmlrpc.cleanup();
m_jsonrpc.cleanup();
}
@@ -169,6 +165,11 @@ RpcManager::set_type_enabled(RPCType type, bool enabled) {
}
}
bool
RpcManager::is_initialized() const {
return m_initialized;
}
void
RpcManager::insert_command(const char* name, const char* parm, const char* doc) {
m_xmlrpc.insert_command(name, parm, doc);
+11 -13
View File
@@ -48,16 +48,14 @@ public:
RpcManager() = default;
~RpcManager() = default;
bool is_handlers_initialized() const { return m_handlers_initialized; }
void initialize_handlers();
void initialize();
void cleanup();
bool is_initialized() const;
int64_t size_limit() { return m_xmlrpc.size_limit(); };
int64_t size_limit() { return m_xmlrpc.size_limit(); };
void set_size_limit(uint64_t size) { m_xmlrpc.set_size_limit(size); };
int dialect() { return m_xmlrpc.dialect(); }
void set_dialect(int dialect) { m_xmlrpc.set_dialect(dialect); }
int dialect() { return m_xmlrpc.dialect(); }
void set_dialect(int dialect) { m_xmlrpc.set_dialect(dialect); }
bool is_type_enabled(RPCType type) const;
void set_type_enabled(RPCType type, bool enabled);
@@ -67,9 +65,9 @@ public:
void insert_command(const char* name, const char* parm, const char* doc);
slot_download& slot_find_download() { return m_slot_find_download; }
slot_file& slot_find_file() { return m_slot_find_file; }
slot_tracker& slot_find_tracker() { return m_slot_find_tracker; }
slot_peer& slot_find_peer() { return m_slot_find_peer; }
slot_file& slot_find_file() { return m_slot_find_file; }
slot_tracker& slot_find_tracker() { return m_slot_find_tracker; }
slot_peer& slot_find_peer() { return m_slot_find_peer; }
static void object_to_target(const torrent::Object& obj, int callFlags, rpc::target_type* target, std::function<void()>* deleter);
@@ -77,9 +75,9 @@ private:
XmlRpc m_xmlrpc;
JsonRpc m_jsonrpc;
bool m_handlers_initialized{};
bool m_is_jsonrpc_enabled{true};
bool m_is_xmlrpc_enabled{true};
bool m_initialized = false;
bool m_is_jsonrpc_enabled = true;
bool m_is_xmlrpc_enabled = true;
slot_download m_slot_find_download;
slot_file m_slot_find_file;
+12 -18
View File
@@ -1,13 +1,13 @@
#include "config.h"
#include <cassert>
#include <rak/error_number.h>
#include <rak/socket_address.h>
#include <sys/un.h>
#include <torrent/connection_manager.h>
#include <torrent/poll.h>
#include <torrent/torrent.h>
#include <torrent/exceptions.h>
#include <torrent/net/fd.h>
#include <torrent/net/socket_address.h>
#include "control.h"
#include "globals.h"
@@ -41,7 +41,7 @@ void
SCgi::open_port(void* sa, unsigned int length, bool dontRoute) {
if (!get_fd().open_stream() ||
(dontRoute && !get_fd().set_dont_route(true)))
throw torrent::resource_error("Could not open socket for listening: " + std::string(std::strerror(errno)));
throw torrent::resource_error("Could not open socket for listening: " + std::string(rak::error_number::current().c_str()));
open(sa, length);
}
@@ -51,8 +51,8 @@ SCgi::open_named(const std::string& filename) {
if (filename.empty() || filename.size() > 4096)
throw torrent::resource_error("Invalid filename length.");
auto buffer = std::make_unique<char[]>(sizeof(sockaddr_un) + filename.size());
sockaddr_un* sa = reinterpret_cast<sockaddr_un*>(buffer.get());
char buffer[sizeof(sockaddr_un) + filename.size()];
sockaddr_un* sa = reinterpret_cast<sockaddr_un*>(buffer);
#ifdef __sun__
sa->sun_family = AF_UNIX;
@@ -74,9 +74,9 @@ SCgi::open(void* sa, unsigned int length) {
try {
if (!get_fd().set_nonblock() ||
!get_fd().set_reuse_address(true) ||
!get_fd().bind_sa(reinterpret_cast<sockaddr*>(sa), length) ||
!get_fd().bind(*reinterpret_cast<rak::socket_address*>(sa), length) ||
!get_fd().listen(max_tasks))
throw torrent::resource_error("Could not prepare socket for listening: " + std::string(std::strerror(errno)));
throw torrent::resource_error("Could not prepare socket for listening: " + std::string(rak::error_number::current().c_str()));
torrent::connection_manager()->inc_socket_count();
@@ -108,24 +108,18 @@ SCgi::deactivate() {
void
SCgi::event_read() {
while (true) {
int fd = torrent::fd_accept(get_fd().get_fd());
if (fd == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
break;
throw torrent::resource_error("Listener port accept() failed: " + std::string(std::strerror(errno)));
}
rak::socket_address sa;
utils::SocketFd fd;
while ((fd = get_fd().accept(&sa)).is_valid()) {
SCgiTask* task = std::find_if(m_task, m_task + max_tasks, std::mem_fn(&SCgiTask::is_available));
if (task == m_task + max_tasks) {
torrent::fd_close(fd);
fd.close();
continue;
}
task->open(this, fd);
task->open(this, fd.get_fd());
}
}
+16 -11
View File
@@ -219,7 +219,7 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int call_type, rpc::targe
if (env->fault_occurred)
throw xmlrpc_error_c(env);
if (target != nullptr && target->first == XmlRpc::call_download &&
if (target->first == XmlRpc::call_download &&
(call_type == XmlRpc::call_file || call_type == XmlRpc::call_tracker)) {
// If we have a download target and the call type requires
// another contained type, then we try to use the next
@@ -295,8 +295,8 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
const std::string& str = object.as_string();
char buffer[str.size() + 1];
char* dst = buffer;
for (char itr : str)
*dst++ = ((itr < 0x20 && itr != '\r' && itr != '\n' && itr != '\t') || (itr & 0x80)) ? '?' : itr;
for (std::string::const_iterator itr = str.begin(); itr != str.end(); ++itr)
*dst++ = ((*itr < 0x20 && *itr != '\r' && *itr != '\n' && *itr != '\t') || (*itr & 0x80)) ? '?' : *itr;
*dst = 0;
result = xmlrpc_string_new(env, buffer);
@@ -309,8 +309,8 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
{
xmlrpc_value* result = xmlrpc_array_new(env);
for (const auto& itr : object.as_list()) {
xmlrpc_value* item = object_to_xmlrpc(env, itr);
for (torrent::Object::list_const_iterator itr = object.as_list().begin(), last = object.as_list().end(); itr != last; itr++) {
xmlrpc_value* item = object_to_xmlrpc(env, *itr);
xmlrpc_array_append_item(env, result, item);
xmlrpc_DECREF(item);
}
@@ -322,9 +322,9 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
{
xmlrpc_value* result = xmlrpc_struct_new(env);
for (const auto& itr : object.as_map()) {
xmlrpc_value* item = object_to_xmlrpc(env, itr.second);
xmlrpc_struct_set_value(env, result, itr.first.c_str(), item);
for (torrent::Object::map_const_iterator itr = object.as_map().begin(), last = object.as_map().end(); itr != last; itr++) {
xmlrpc_value* item = object_to_xmlrpc(env, itr->second);
xmlrpc_struct_set_value(env, result, itr->first.c_str(), item);
xmlrpc_DECREF(item);
}
@@ -340,8 +340,11 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
xmlrpc_DECREF(key_item);
if (object.as_dict_obj().is_list()) {
for (const auto& itr : object.as_dict_obj().as_list()) {
xmlrpc_value* item = object_to_xmlrpc(env, itr);
for (torrent::Object::list_const_iterator
itr = object.as_dict_obj().as_list().begin(),
last = object.as_dict_obj().as_list().end();
itr != last; itr++) {
xmlrpc_value* item = object_to_xmlrpc(env, *itr);
xmlrpc_array_append_item(env, result, item);
xmlrpc_DECREF(item);
}
@@ -375,7 +378,9 @@ xmlrpc_call_command(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo) {
torrent::Object object;
rpc::target_type target = rpc::make_target();
if (itr->second.m_flags & CommandMap::flag_file_target)
if (itr->second.m_flags & CommandMap::flag_no_target)
xmlrpc_to_object(env, args, XmlRpc::call_generic, &target, &deleter).swap(object);
else if (itr->second.m_flags & CommandMap::flag_file_target)
xmlrpc_to_object(env, args, XmlRpc::call_file, &target, &deleter).swap(object);
else if (itr->second.m_flags & CommandMap::flag_tracker_target)
xmlrpc_to_object(env, args, XmlRpc::call_tracker, &target, &deleter).swap(object);
+10 -6
View File
@@ -204,10 +204,12 @@ execute_command(std::string method_name, const tinyxml2::XMLElement* params_elem
const auto* child = params_element->FirstChildElement("param");
if (child != nullptr) {
std::function<void()> deleter = []() {};
if (!(cmd_itr->second.m_flags & CommandMap::flag_no_target)) {
std::function<void()> deleter = []() {};
RpcManager::object_to_target(xml_value_to_object(child->FirstChildElement("value")), cmd_itr->second.m_flags, &target, &deleter);
child = child->NextSiblingElement("param");
RpcManager::object_to_target(xml_value_to_object(child->FirstChildElement("value")), cmd_itr->second.m_flags, &target, &deleter);
child = child->NextSiblingElement("param");
}
// Parse out any other params
while (child != nullptr) {
@@ -221,10 +223,12 @@ execute_command(std::string method_name, const tinyxml2::XMLElement* params_elem
const auto* child = params_element->FirstChildElement("data")->FirstChildElement("value");
if (child != nullptr) {
std::function<void()> deleter = []() {};
if (!(cmd_itr->second.m_flags & CommandMap::flag_no_target)) {
std::function<void()> deleter = []() {};
RpcManager::object_to_target(xml_value_to_object(child), cmd_itr->second.m_flags, &target, &deleter);
child = child->NextSiblingElement("value");
RpcManager::object_to_target(xml_value_to_object(child), cmd_itr->second.m_flags, &target, &deleter);
child = child->NextSiblingElement("value");
}
while (child != nullptr) {
params.push_back(xml_value_to_object(child));
+4 -4
View File
@@ -179,7 +179,7 @@ DownloadList::activate_display(Display displayType) {
// Set title.
switch (displayType) {
case DISPLAY_DOWNLOAD_LIST:
control->ui()->window_title()->set_title("rTorrent " PACKAGE_VERSION "/" +
control->ui()->window_title()->set_title("rTorrent " VERSION "/" +
std::string(torrent::version()) + " - " +
rpc::call_command_string("session.name"));
break;
@@ -360,12 +360,12 @@ DownloadList::setup_keys() {
m_bindings['F'] = std::bind(&DownloadList::receive_view_input, this, INPUT_FILTER);
m_uiArray[DISPLAY_LOG]->bindings()[KEY_LEFT] =
m_uiArray[DISPLAY_LOG]->bindings()[control->ui()->navigation_key(RT_KEY_LEFT)] =
m_uiArray[DISPLAY_LOG]->bindings()['B' - '@'] =
m_uiArray[DISPLAY_LOG]->bindings()[' '] = std::bind(&DownloadList::activate_display, this, DISPLAY_DOWNLOAD_LIST);
m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()[KEY_RIGHT] =
m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()[control->ui()->navigation_key(RT_KEY_RIGHT)] = std::bind(&DownloadList::activate_display, this, DISPLAY_DOWNLOAD);
m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()[control->ui()->navigation_key(RT_KEY_DISPLAY_LOG)] = std::bind(&DownloadList::activate_display, this, DISPLAY_LOG);
m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['F' - '@'] = std::bind(&DownloadList::activate_display, this, DISPLAY_DOWNLOAD);
m_uiArray[DISPLAY_DOWNLOAD_LIST]->bindings()['l'] = std::bind(&DownloadList::activate_display, this, DISPLAY_LOG);
}
}
+3 -4
View File
@@ -42,17 +42,16 @@
#include "control.h"
#include "element_chunks_seen.h"
#include "root.h"
namespace ui {
ElementChunksSeen::ElementChunksSeen(core::Download* d) :
m_download(d) {
m_bindings[KEY_LEFT] = m_bindings[control->ui()->navigation_key(RT_KEY_LEFT)] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_DOWN] = m_bindings[control->ui()->navigation_key(RT_KEY_DOWN)] = std::bind(&ElementChunksSeen::receive_next, this);
m_bindings[KEY_UP] = m_bindings[control->ui()->navigation_key(RT_KEY_UP)] = std::bind(&ElementChunksSeen::receive_prev, this);
m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::bind(&ElementChunksSeen::receive_next, this);
m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::bind(&ElementChunksSeen::receive_prev, this);
m_bindings[KEY_NPAGE] = std::bind(&ElementChunksSeen::receive_pagenext, this);
m_bindings[KEY_PPAGE] = std::bind(&ElementChunksSeen::receive_pageprev, this);
}
+8 -9
View File
@@ -15,7 +15,6 @@
#include "control.h"
#include "element_download_list.h"
#include "root.h"
namespace ui {
@@ -26,6 +25,7 @@ ElementDownloadList::ElementDownloadList() {
throw torrent::internal_error("View \"main\" must be present to initialize the main display.");
m_bindings['\x13'] = std::bind(&ElementDownloadList::receive_command, this, "d.start=");
m_bindings['\x04'] = std::bind(&ElementDownloadList::receive_command, this, "branch=d.state=,d.stop=,d.erase=");
m_bindings['\x0B'] = std::bind(&ElementDownloadList::receive_command, this, "d.ignore_commands.set=1; d.stop=; d.close=");
m_bindings['\x12'] = std::bind(&ElementDownloadList::receive_command, this, "d.complete.set=0; d.check_hash=");
m_bindings['\x05'] = std::bind(&ElementDownloadList::receive_command, this, "f.multicall=,f.set_create_queued=0,f.set_resize_queued=0; print=\"Queued create/resize of files in torrent.\"");
@@ -54,17 +54,16 @@ ElementDownloadList::ElementDownloadList() {
m_bindings['9'] = std::bind(&ElementDownloadList::receive_change_view, this, "leeching");
m_bindings['0'] = std::bind(&ElementDownloadList::receive_change_view, this, "active");
m_bindings[KEY_UP] = m_bindings[control->ui()->navigation_key(RT_KEY_UP)] = std::bind(&ElementDownloadList::receive_prev, this);
m_bindings[KEY_DOWN] = m_bindings[control->ui()->navigation_key(RT_KEY_DOWN)] = std::bind(&ElementDownloadList::receive_next, this);
m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::bind(&ElementDownloadList::receive_prev, this);
m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::bind(&ElementDownloadList::receive_next, this);
m_bindings[KEY_PPAGE] = m_bindings[control->ui()->navigation_key(RT_KEY_PPAGE)] = [this] { receive_pageprev(); };
m_bindings[KEY_NPAGE] = m_bindings[control->ui()->navigation_key(RT_KEY_NPAGE)] = [this] { receive_pagenext(); };
m_bindings[KEY_PPAGE] = m_bindings['U' - '@'] = [this] { receive_pageprev(); };
m_bindings[KEY_NPAGE] = m_bindings['H' - '@'] = [this] { receive_pagenext(); };
m_bindings[KEY_HOME] = m_bindings[control->ui()->navigation_key(RT_KEY_HOME)] = [this] { receive_home(); };
m_bindings[KEY_END] = m_bindings[control->ui()->navigation_key(RT_KEY_END)] = [this] { receive_end(); };
m_bindings[KEY_HOME] = m_bindings['A' - '@'] = [this] { receive_home(); };
m_bindings[KEY_END] = m_bindings['E' - '@'] = [this] { receive_end(); };
m_bindings[control->ui()->navigation_key(RT_KEY_DELETE_ITEM)] = std::bind(&ElementDownloadList::receive_command, this, "branch=d.state=,d.stop=,d.erase=");
m_bindings[control->ui()->navigation_key(RT_KEY_TOGGLE_LAYOUT)] = std::bind(&ElementDownloadList::toggle_layout, this);
m_bindings['L'] = std::bind(&ElementDownloadList::toggle_layout, this);
}
void
+8 -8
View File
@@ -48,7 +48,6 @@
#include "control.h"
#include "element_file_list.h"
#include "element_text.h"
#include "root.h"
namespace ui {
@@ -56,8 +55,8 @@ ElementFileList::ElementFileList(core::Download* d) :
m_download(d),
m_selected(iterator(d->download()->file_list()->begin())) {
m_bindings[KEY_LEFT] = m_bindings[control->ui()->navigation_key(RT_KEY_LEFT)] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_RIGHT] = m_bindings[control->ui()->navigation_key(RT_KEY_RIGHT)] = std::bind(&ElementFileList::receive_select, this);
m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = std::bind(&ElementFileList::receive_select, this);
m_bindings[' '] = std::bind(&ElementFileList::receive_priority, this);
m_bindings['*'] = std::bind(&ElementFileList::receive_change_all, this);
@@ -65,8 +64,8 @@ ElementFileList::ElementFileList(core::Download* d) :
m_bindings[KEY_NPAGE] = std::bind(&ElementFileList::receive_pagenext, this);
m_bindings[KEY_PPAGE] = std::bind(&ElementFileList::receive_pageprev, this);
m_bindings[KEY_DOWN] = m_bindings[control->ui()->navigation_key(RT_KEY_DOWN)] = std::bind(&ElementFileList::receive_next, this);
m_bindings[KEY_UP] = m_bindings[control->ui()->navigation_key(RT_KEY_UP)] = std::bind(&ElementFileList::receive_prev, this);
m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::bind(&ElementFileList::receive_next, this);
m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::bind(&ElementFileList::receive_prev, this);
}
inline ElementText*
@@ -277,13 +276,14 @@ ElementFileList::receive_priority() {
void
ElementFileList::receive_change_all() {
if (m_window == nullptr)
if (m_window == NULL)
return;
torrent::FileList* fl = m_download->download()->file_list();
auto priority = torrent::priority_enum((m_selected.file()->priority() + 2) % 3);
for (const auto& file : *m_download->download()->file_list())
file->set_priority(priority);
for (torrent::FileList::iterator itr = fl->begin(), last = fl->end(); itr != last; ++itr)
(*itr)->set_priority(priority);
m_download->download()->update_priorities();
update_itr();
+37 -1
View File
@@ -1,3 +1,39 @@
// 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 <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#ifndef RTORRENT_UI_ELEMENT_LOG_COMPLETE_H
#define RTORRENT_UI_ELEMENT_LOG_COMPLETE_H
@@ -28,7 +64,7 @@ private:
void received_update();
WLogComplete* m_window{};
torrent::log_buffer* m_log;
};
+4 -5
View File
@@ -43,7 +43,6 @@
#include "control.h"
#include "element_menu.h"
#include "root.h"
namespace ui {
@@ -71,11 +70,11 @@ ElementMenu::ElementMenu() :
m_entry(entry_invalid) {
// Move bindings into a function that defines default bindings.
m_bindings[KEY_LEFT] = m_bindings[control->ui()->navigation_key(RT_KEY_LEFT)] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_RIGHT] = m_bindings[control->ui()->navigation_key(RT_KEY_RIGHT)] = std::bind(&ElementMenu::entry_select, this);
m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = std::bind(&ElementMenu::entry_select, this);
m_bindings[KEY_UP] = m_bindings[control->ui()->navigation_key(RT_KEY_UP)] = std::bind(&ElementMenu::entry_prev, this);
m_bindings[KEY_DOWN] = m_bindings[control->ui()->navigation_key(RT_KEY_DOWN)] = std::bind(&ElementMenu::entry_next, this);
m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::bind(&ElementMenu::entry_prev, this);
m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::bind(&ElementMenu::entry_next, this);
}
ElementMenu::~ElementMenu() {
+6 -8
View File
@@ -50,7 +50,6 @@
#include "control.h"
#include "element_peer_list.h"
#include "element_text.h"
#include "root.h"
namespace ui {
@@ -61,8 +60,7 @@ ElementPeerList::ElementPeerList(core::Download* d) :
torrent::ConnectionList* connection_list = m_download->download()->connection_list();
for (auto peer : *connection_list)
m_list.push_back(peer);
std::for_each(connection_list->begin(), connection_list->end(), [&](torrent::Peer* peer) { m_list.push_back(peer); });
m_peer_connected = connection_list->signal_connected().insert(connection_list->signal_connected().end(),
std::bind(&ElementPeerList::receive_peer_connected, this, std::placeholders::_1));
@@ -74,14 +72,14 @@ ElementPeerList::ElementPeerList(core::Download* d) :
m_elementInfo->slot_exit(std::bind(&ElementPeerList::activate_display, this, DISPLAY_LIST));
m_bindings[control->ui()->navigation_key(RT_KEY_DISCONNECT_PEER)] = std::bind(&ElementPeerList::receive_disconnect_peer, this);
m_bindings['k'] = std::bind(&ElementPeerList::receive_disconnect_peer, this);
m_bindings['*'] = std::bind(&ElementPeerList::receive_snub_peer, this);
m_bindings['B'] = std::bind(&ElementPeerList::receive_ban_peer, this);
m_bindings[KEY_LEFT] = m_bindings[control->ui()->navigation_key(RT_KEY_LEFT)] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_RIGHT] = m_bindings[control->ui()->navigation_key(RT_KEY_RIGHT)] = std::bind(&ElementPeerList::activate_display, this, DISPLAY_INFO);
m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = std::bind(&ElementPeerList::activate_display, this, DISPLAY_INFO);
m_bindings[KEY_UP] = m_bindings[control->ui()->navigation_key(RT_KEY_UP)] = std::bind(&ElementPeerList::receive_prev, this);
m_bindings[KEY_DOWN] = m_bindings[control->ui()->navigation_key(RT_KEY_DOWN)] = std::bind(&ElementPeerList::receive_next, this);
m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::bind(&ElementPeerList::receive_prev, this);
m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::bind(&ElementPeerList::receive_next, this);
}
ElementPeerList::~ElementPeerList() {
+4 -5
View File
@@ -43,7 +43,6 @@
#include "control.h"
#include "element_text.h"
#include "root.h"
namespace ui {
@@ -51,11 +50,11 @@ ElementText::ElementText(rpc::target_type target) :
m_window(new WindowText(target)) {
// Move bindings into a function that defines default bindings.
m_bindings[KEY_LEFT] = m_bindings[control->ui()->navigation_key(RT_KEY_LEFT)] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::bind(&slot_type::operator(), &m_slot_exit);
// m_bindings[KEY_UP] = m_bindings[control->ui()->navigation_key(RT_KEY_UP)] = std::bind(this, &ElementText::entry_prev);
// m_bindings[KEY_DOWN] = m_bindings[control->ui()->navigation_key(RT_KEY_DOWN)] = std::bind(this, &ElementText::entry_next);
// m_bindings[KEY_RIGHT] = m_bindings[control->ui()->navigation_key(RT_KEY_RIGHT)] = std::bind(this, &ElementText::entry_select);
// m_bindings[KEY_UP] = std::bind(this, &ElementText::entry_prev);
// m_bindings[KEY_DOWN] = std::bind(this, &ElementText::entry_next);
// m_bindings[KEY_RIGHT] = m_bindings['F' - '@'] = std::bind(this, &ElementText::entry_select);
}
ElementText::~ElementText() {
+3 -4
View File
@@ -9,20 +9,19 @@
#include "control.h"
#include "element_tracker_list.h"
#include "root.h"
namespace ui {
ElementTrackerList::ElementTrackerList(core::Download* d) :
m_download(d) {
m_bindings[KEY_LEFT] = m_bindings[control->ui()->navigation_key(RT_KEY_LEFT)] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[' '] = std::bind(&ElementTrackerList::receive_cycle_group, this);
m_bindings['*'] = std::bind(&ElementTrackerList::receive_disable, this);
m_bindings[KEY_DOWN] = m_bindings[control->ui()->navigation_key(RT_KEY_DOWN)] = std::bind(&ElementTrackerList::receive_next, this);
m_bindings[KEY_UP] = m_bindings[control->ui()->navigation_key(RT_KEY_UP)] = std::bind(&ElementTrackerList::receive_prev, this);
m_bindings[KEY_DOWN] = m_bindings['N' - '@'] = std::bind(&ElementTrackerList::receive_next, this);
m_bindings[KEY_UP] = m_bindings['P' - '@'] = std::bind(&ElementTrackerList::receive_prev, this);
}
void
+3 -4
View File
@@ -42,17 +42,16 @@
#include "control.h"
#include "element_transfer_list.h"
#include "root.h"
namespace ui {
ElementTransferList::ElementTransferList(core::Download* d) :
m_download(d) {
m_bindings[KEY_LEFT] = m_bindings[control->ui()->navigation_key(RT_KEY_LEFT)] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_LEFT] = m_bindings['B' - '@'] = std::bind(&slot_type::operator(), &m_slot_exit);
m_bindings[KEY_DOWN] = m_bindings[control->ui()->navigation_key(RT_KEY_DOWN)] = std::bind(&ElementTransferList::receive_next, this);
m_bindings[KEY_UP] = m_bindings[control->ui()->navigation_key(RT_KEY_UP)] = std::bind(&ElementTransferList::receive_prev, this);
m_bindings[KEY_DOWN] = std::bind(&ElementTransferList::receive_next, this);
m_bindings[KEY_UP] = std::bind(&ElementTransferList::receive_prev, this);
m_bindings[KEY_NPAGE] = std::bind(&ElementTransferList::receive_pagenext, this);
m_bindings[KEY_PPAGE] = std::bind(&ElementTransferList::receive_pageprev, this);
}
+15 -65
View File
@@ -27,36 +27,6 @@
namespace ui {
static const int emacs_keymap[RT_KEYMAP_MAX] = {
'B' - '@',
'F' - '@',
'P' - '@',
'N' - '@',
'U' - '@',
'H' - '@',
'A' - '@',
'E' - '@',
'D' - '@', // RT_KEY_DELETE_ITEM
'k', // RT_KEY_DISCONNECT_PEER
'l', // RT_KEY_DISPLAY_LOG
'L' // RT_KEY_TOGGLE_LAYOUT
};
static const int vi_keymap[RT_KEYMAP_MAX] = {
'h',
'l',
'k',
'j',
'B' - '@',
'D' - '@',
'H',
'G',
'x', // RT_KEY_DELETE_ITEM
'K', // RT_KEY_DISCONNECT_PEER
'L', // RT_KEY_DISPLAY_LOG
'L' - '@' // RT_KEY_TOGGLE_LAYOUT
};
Root::Root() {
// Initialise prefilled m_input_history and m_input_history_pointers objects.
for (int type = ui::DownloadList::INPUT_LOAD_DEFAULT; type != ui::DownloadList::INPUT_EOI; type++) {
@@ -64,9 +34,6 @@ Root::Root() {
m_input_history_pointers.insert( std::make_pair(type, 0) );
}
// set default keymap to emacs
m_keymap_style = "emacs";
m_keymap = emacs_keymap;
}
void
@@ -351,19 +318,20 @@ Root::set_input_history_size(int size) {
if (size < 1)
throw torrent::input_error("Invalid input history size.");
for (auto& [entry, category] : m_input_history) {
for (InputHistory::iterator itr = m_input_history.begin(), last = m_input_history.end(); itr != last; itr++) {
// Reserve the latest input history entries if new size is smaller than original.
if (size < m_input_history_length) {
int pointer_offset = m_input_history_length - size;
InputHistoryPointers::iterator pitr = m_input_history_pointers.find(entry);
InputHistoryPointers::iterator pitr = m_input_history_pointers.find(itr->first);
InputHistoryCategory input_history_category_tmp = itr->second;
for (int i=0; i != size; i++)
category.at(i) = category.at((pitr->second + pointer_offset + i) % m_input_history_length);
itr->second.at(i) = input_history_category_tmp.at((pitr->second + pointer_offset + i) % m_input_history_length);
m_input_history_pointers[pitr->first] = 0;
}
category.resize(size);
itr->second.resize(size);
}
m_input_history_length = size;
@@ -413,20 +381,20 @@ Root::load_input_history() {
lt_log_print(torrent::LOG_DEBUG, "input history file read (path:%s)", history_filename.c_str());
}
for (const auto& [entry, category] : input_history_tmp) {
int input_history_tmp_category_length = category.size();
InputHistory::iterator hitr = m_input_history.find(entry);
InputHistoryPointers::iterator pitr = m_input_history_pointers.find(entry);
for (InputHistory::const_iterator itr = input_history_tmp.begin(), last = input_history_tmp.end(); itr != last; itr++) {
int input_history_tmp_category_length = itr->second.size();
InputHistory::iterator hitr = m_input_history.find(itr->first);
InputHistoryPointers::iterator pitr = m_input_history_pointers.find(itr->first);
if (m_input_history_length < input_history_tmp_category_length) {
int pointer_offset = input_history_tmp_category_length - m_input_history_length;
for (int i=0; i != m_input_history_length; i++)
hitr->second.at(i) = category.at((pointer_offset + i) % input_history_tmp_category_length);
hitr->second.at(i) = itr->second.at((pointer_offset + i) % input_history_tmp_category_length);
pitr->second = 0;
} else {
hitr->second = category;
hitr->second = itr->second;
hitr->second.resize(m_input_history_length);
pitr->second = input_history_tmp_category_length % m_input_history_length;
@@ -451,12 +419,12 @@ Root::save_input_history() {
return;
}
for (const auto& [entry, category] : m_input_history) {
InputHistoryPointers::const_iterator pitr = m_input_history_pointers.find(entry);
for (InputHistory::const_iterator itr = m_input_history.begin(), last = m_input_history.end(); itr != last; itr++) {
InputHistoryPointers::const_iterator pitr = m_input_history_pointers.find(itr->first);
for (int i=0; i != m_input_history_length; i++)
if (!category.at((pitr->second + i) % m_input_history_length).empty())
history_file << entry << "|" + category.at((pitr->second + i) % m_input_history_length) + "\n";
if (!itr->second.at((pitr->second + i) % m_input_history_length).empty())
history_file << itr->first << "|" + itr->second.at((pitr->second + i) % m_input_history_length) + "\n";
}
if (!history_file.good()) {
@@ -483,22 +451,4 @@ Root::clear_input_history() {
}
}
void
Root::set_keymap_style(const std::string& style) {
if (style == "vi") {
m_keymap = vi_keymap;
} else if (style == "emacs") {
m_keymap = emacs_keymap;
} else {
throw torrent::input_error("Root::set_keymap_style() -> ui.keymap.style is configured with unknown keymap style: " + m_keymap_style);
}
m_keymap_style = style;
}
const int
Root::navigation_key(NavigationKeymap key) {
return m_keymap[key];
}
}

Some files were not shown because too many files have changed in this diff Show More