Compare commits

...

59 Commits

Author SHA1 Message Date
rakshasa 39f186e523 Tagged release 0.16.8. 2026-03-15 15:43:32 +01:00
Jari Sundell 70e6964823 Fixed various SCGI issues. 2026-03-10 23:25:28 +09:00
rakshasa 7ead88448b Removed rak/error_number.h from Makefile.am. 2026-03-04 11:39:25 +01:00
rakshasa 650f0299b5 Tagged release 0.16.7. 2026-03-04 10:47:30 +01:00
rakshasa 5dfb2ae938 Allow dht bootstrap nodes to be added when dht is off. 2026-03-02 09:45:09 +01:00
Jorge Israel Peña f05a2ae520 Re-send smkx on SIGWINCH to fix arrow keys after terminal reattach 2026-02-19 16:06:42 +01:00
Miroslav Marchev ecefdba734 dht_add_peer_node is empty, use dht_add_bootstrap_node instead
After a refactor dht_add_peer_node became empty function. Replace with dht_add_bootstrap_node to make adding bootstrap nodes work.
2026-02-14 14:32:48 +01:00
Jari Sundell 87666199b3 Added SocketManager to handle reuse of uninterested fd's by the kernel. 2026-01-29 04:00:31 +09:00
Jari Sundell 9489793dcb Created torrent/runtime include directory. 2026-01-27 08:21:05 +09:00
Jari Sundell 2fa7568165 Remove obsolete SocketFd class. 2026-01-26 19:13:03 +09:00
fffe f4b718f685 add separate commands for unbuffered logs 2026-01-16 16:10:02 +01:00
Jari Sundell b233e24465 Deprecated rak::path_expand. 2026-01-08 23:27:53 +09:00
Jari Sundell 289ab046bf Expand '~/' to $HOME in session path. 2026-01-06 20:44:40 +09:00
Jari Sundell a8b6a47054 Removed deprecated rak errno and file headers. 2026-01-04 03:22:02 +09:00
Zoltan Celedes 110591d5c1 Fix key/value pairs in Lua
Previously, the keys and values were swapped in d.custom.items()
2026-01-03 12:20:08 +01:00
rakshasa ae14baa357 Tagged release 0.16.6. 2026-01-02 15:22:29 +01:00
rakshasa 0b0c824b4b Changed magnet metadata handling and added 'magnet.path.set'. 2025-12-31 21:57:52 +01:00
Jari Sundell def6551488 Properly propagate errors from download session save. 2025-12-30 22:00:34 +09:00
Jari Sundell 787738e36a Make sure pending builds of session resume get processed. 2025-12-29 09:55:32 +09:00
Jari Sundell 40c2d90c45 Fixed dereferencing of potentially nullptr in SessionManager. 2025-12-25 23:05:08 +09:00
Jari Sundell 4a37fbde0b Session saving of resume data is added to a pre-queue. 2025-12-23 03:04:47 +09:00
Jari Sundell 4bdeb58eb6 Run multiple session save requests in parallel. 2025-12-22 06:26:35 +09:00
Jari Sundell 5dbb0020dc Replace ThreadWorker with scgi::ThreadScgi. 2025-12-18 07:43:43 +09:00
Jari Sundell 8f644e65dd Use separate thread for saving session data. 2025-12-18 06:42:44 +09:00
Jari Sundell 16ff32b88c Added missing Event::type_name() functions. 2025-12-13 19:06:02 +09:00
Jari Sundell 8806c06f9f Added timestamp helper commands. 2025-12-10 22:29:42 +09:00
rakshasa 60cfcd37c4 Release 0.16.5. 2025-12-02 17:51:26 +01:00
rakshasa a526ba58e9 Release 0.16.4. 2025-11-25 10:48:11 +01:00
rakshasa efd9507149 Release 0.16.3. 2025-11-21 14:39:27 +01:00
Jari Sundell 3d91dfdb33 Valgrind suppressions file for macos. 2025-11-20 15:57:30 +09:00
Jari Sundell 30cec98799 Moved Poll to net namespace. 2025-11-20 03:05:16 +09:00
rakshasa b825906034 Store copies of command names added to xmlrpc-c. 2025-11-17 20:30:13 +01:00
rakshasa b05ecb5c5a Push back views explicitly takes a string. 2025-11-17 09:36:32 +01:00
Jari Sundell 900be334dc Cleaned up xmlrpc-c string sanitization. 2025-11-17 02:48:32 +09:00
rakshasa 3a1da2fe34 Check if AF_INET6 is supported, or block IPv6 traffic. 2025-11-15 09:17:56 +01:00
Jari Sundell 70750a2bd3 Cleanup of DHT controller. 2025-11-13 00:01:22 +09:00
Jari Sundell 1d2c424a70 Remove throttle from DHT. 2025-11-08 17:51:00 +09:00
rakshasa 8550facf43 Tagged release 0.16.2. 2025-11-04 15:20:20 +01:00
rakshasa 184ead294a Export 'group2.*' commands. 2025-11-01 14:35:32 +01:00
Jari Sundell 84bfc491ba Added dual listening ports when both IPv4 and IPv6 are bound. 2025-11-01 07:24:31 +09:00
Khem Raj a2e0eca6e3 scripts/common.m4: Insert spaces in shell lists
$1=$(echo "$result" | tr -d '\n')

removes all newlines without inserting spaces
That usually isn’t what we want for shell lists.
It should typically be space-separated output.

Fixes a bug seen with yocto where compiler is not a single word
but a string e.g.

ccache aarch64-yoe-linux-musl-clang++  -mcpu=cortex-a72+crc+nocrypto   --dyld-prefix=/usr -fstack-protector-strong  -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/mnt/b/yoe/master/build/tmp/work/cortexa72-yoe-linux-musl/libtorrent/0.16.1/recipe-sysroot

It changes it to

ccacheaarch64-yoe-linux-musl-clang++-mcpu=cortex-a72+crc+nocrypto--dyld-prefix=/usr-fstack-protector-strong-O2-D_FORTIFY_SOURCE=2-Wformat-Wformat-security-Werror=format-security--sysroot=/mnt/b/yoe/master/build/tmp/work/cortexa72-yoe-linux-musl/libtorrent/0.16.1/recipe-sysroot

When doing c++17 checks on compiler, resulting in failure

Upstream-Status: Submitted [https://github.com/rakshasa/libtorrent/pull/583]
Signed-off-by: Khem Raj <raj.khem@gmail.com>
2025-10-25 11:30:56 +02:00
rakshasa 92eecdfd52 Updated log group documentation. 2025-10-24 15:38:01 +02:00
Jari Sundell 14219666c5 Fix syntax for appending to log files 2025-10-24 14:08:23 +02:00
Aden a79a844dac Fix typo in 'receiving' 2025-10-24 14:08:23 +02:00
Aden 59b6a013ce Document the log.append_file configuration key
This flag is extremely useful but I couldn't find any documentation
referencing it. I only found it once I started having a poke through the
source code, so hopefully this will save others a little bit of time :)
2025-10-24 14:08:23 +02:00
rakshasa b38f80e597 Release 0.16.1. 2025-10-16 10:54:05 +02:00
Auska 2d2a756a3c fix: replace VLA
Avoids -Wvla-cxx-extension warning by using standard C++ container.
VLA is not part of standard C++ and causes portability issues.
2025-10-14 11:16:35 +02:00
Jari Sundell 891a6ba69d Added local address commands for inet/inet6. 2025-10-13 19:09:20 +09:00
Jari Sundell 2be730e4b3 Reuse HTTP connections and added totale/cached connection limits. 2025-10-09 21:15:24 +09:00
Jari Sundell bf53700f97 Added 'network.bind_address.ipv{4,6}.set' commands. 2025-10-04 20:24:08 +09:00
Jari Sundell 946dc54f9b Fix libtorrent links in README.md
Updated links to point to the GitHub repository for libtorrent.
2025-10-02 16:31:53 +09:00
Jari Sundell ea2347734b Added network.block.outgoing. 2025-09-23 17:56:51 +09:00
Jari Sundell 5206e6cb88 Moved various socket options to NetworkConfig. 2025-09-22 06:01:18 +09:00
Jari Sundell 48f82c17c2 Remove deprecated no-target flags for commands. 2025-09-20 17:27:26 +09:00
rakshasa 675625255d Check if target is null in xmlrpc_to_object(). 2025-09-20 09:22:56 +02:00
Jari Sundell 658e9f7578 Use simplified fd_accept(). 2025-09-18 17:40:56 +09:00
Jari Sundell e7a80c7b18 Remove deprecated rak::socket_address. 2025-09-17 21:44:54 +09:00
Jari Sundell 677f8f45c8 Improved listen/dht port handling and added 'dht.override_port.set' command. 2025-09-13 17:51:04 +09:00
Jari Sundell ba1ba3096a Added NetworkConfig. 2025-09-12 06:09:24 +09:00
97 changed files with 2673 additions and 3184 deletions
-4
View File
@@ -9,12 +9,8 @@ nobase_dist_pkgdata_DATA = \
EXTRA_DIST= \
rak/address_info.h \
rak/algorithm.h \
rak/error_number.h \
rak/file_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://libtorrent.org/) with the same version rTorrent.
Install [libtorrent](https://github.com/rakshasa/libtorrent) 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://libtorrent.org/) closely, and thus the versions must be in sync.
RTorrent follows the development of [libtorrent](https://github.com/rakshasa/libtorrent) closely, and thus the versions must be in sync.
## USAGE
+3 -3
View File
@@ -1,6 +1,6 @@
m4_pattern_allow([PKG_CHECK_EXISTS])
AC_INIT([rtorrent],[0.16.0],[sundell.software@gmail.com])
AC_INIT([rtorrent],[0.16.8],[sundell.software@gmail.com])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIRS([scripts])
@@ -11,7 +11,7 @@ LT_INIT
AC_PROG_CXX
AC_DEFINE([API_VERSION], [16], [api version])
AC_DEFINE([API_VERSION], [19], [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)
@@ -48,7 +48,7 @@ if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
fi
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.0])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.8])
AC_LANG_PUSH(C++)
TORRENT_WITH_XMLRPC_C
+14 -4
View File
@@ -4,20 +4,30 @@
# 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_debug", "tracker.log"
log.add_output = "tracker_debug", "tracker.log"
log.add_output = "dht_all", "tracker.log"
log.add_output = "tracker_events", "tracker.log"
log.add_output = "tracker_requests", "tracker.log"
Each log handle can be added to multiple different logging events.
@@ -31,7 +41,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 reciving events from the event
displayed below, and each event also receiving events from the event
above in importance.
Thus some high-volume sub-group events such as “tracker\_debug” are not
+4 -3
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,8 +20,9 @@ Some control over formatting will be provided at a later date.
log.add_output = "info", "rtorrent.log"
log.add_output = "dht_debug", "tracker.log"
log.add_output = "tracker_debug", "tracker.log"
log.add_output = "dht_all", "tracker.log"
log.add_output = "tracker_events", "tracker.log"
log.add_output = "tracker_requests", "tracker.log"
\end{verbatim}
Each log handle can be added to multiple different logging events.
+4 -1
View File
@@ -101,8 +101,11 @@ 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_debug", "log"
#log.add_output = "tracker_events", "log"
#log.add_output = "tracker_requests", "log"
### END of rtorrent.rc ###
+2 -1
View File
@@ -136,6 +136,7 @@ rc.schedule2('watch_load', '11', '10', 'load.verbose=(cat, (cfg.watch), "load/*.
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_debug', 'log')
--rc.log.add_output('tracker_events', 'log')
--rc.log.add_output('tracker_requests', 'log')
--[[ END of rtorrent.rc.lua ]]--
+1
View File
@@ -0,0 +1 @@
valgrind --leak-check=full --track-origins=yes --show-reachable=yes --suppressions=/Users/rakshasa/projects/rtorrent/doc/valgrind.suppression --gen-suppressions=all --log-file=valgrind.log /usr/local/bin/rtorrent
+343
View File
@@ -0,0 +1,343 @@
{
<insert_a_suppression_name_here>
Memcheck:Cond
...
fun:__76-*
}
{
<insert_a_suppression_name_here>
Memcheck:Value8
...
fun:__76-*
}
{
<insert_a_suppression_name_here>
Memcheck:Value8
...
fun:__80-*
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
...
fun:__93-*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:__93-*
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
...
fun:__108-*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:__108-*
}
{
<insert_a_suppression_name_here>
Memcheck:Value8
...
fun:__108-*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:-[CFPrefsPlistSource setDomainIdentifier:]
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
...
fun:-[CFPrefsSearchListSource alreadylocked_copyValueForKey:]
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:-[CFPrefsSearchListSource alreadylocked_copyValueForKey:]
}
{
<insert_a_suppression_name_here>
Memcheck:Value8
...
fun:-[CFPrefsSearchListSource alreadylocked_copyValueForKey:]
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:-[CFPrefsSearchListSource addNamedVolatileSourceForIdentifier:]
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
...
fun:-[CFPrefsSearchListSource handleReply:toRequestNewDataMessage:onConnection:retryCount:error:]
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:-[CFPrefsSearchListSource addSourceForIdentifier:user:byHost:container:]
}
{
<insert_a_suppression_name_here>
Memcheck:Value8
...
fun:-[CFPrefsSearchListSource handleReply:toRequestNewDataMessage:onConnection:retryCount:error:]
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:-[CFPrefsSearchListSource handleReply:toRequestNewDataMessage:onConnection:retryCount:error:]
}
{
<insert_a_suppression_name_here>
Memcheck:Value8
...
fun:-[CFPrefsSearchListSource handleReply:toRequestNewDataMessage:onConnection:retryCount:error:]
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:-[_CFXPreferences copyAppValueForKey:identifier:container:configurationURL:]
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:-[_CFXPreferences withSearchListForIdentifier:container:cloudConfigurationURL:perform:]
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:-[_CFXPreferences withSearchLists:]
}
{
<insert_a_suppression_name_here>
Memcheck:Value8
...
fun:-[CFPrefsSource copyValueForKey:]
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:-[OS_xpc_object dealloc]
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_CF*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:__CF*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_NS*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:getSuperclassMetadata
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_ZN5dyld*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_ZNK5dyld*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:___ZNK5dyld*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_dyld_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:*_dyld_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:___SC_getApplicationBundleID_block_invoke
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
...
fun:xpc_*
}
{
<insert_a_suppression_name_here>
Memcheck:Value8
...
fun:xpc_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_xpc_*
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
...
fun:_xpc_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_libxpc_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:si_module_with_name
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
...
fun:_dispatch_*
}
{
<insert_a_suppression_name_here>
Memcheck:Value8
...
fun:_dispatch_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_dispatch_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:*_swift_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:libdispatch_init
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_os_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_od_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_objc_init
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_notify_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:bootstrap_*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:$ss*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:loadlocale
fun:setlocale
fun:main
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:initscr
fun:_ZN7display6Canvas10initializeEv
fun:_ZN7Control10initializeEv
fun:main
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:assume_default_colors_sp
fun:_ZN7display6Canvas10initializeEv
fun:_ZN7Control10initializeEv
fun:main
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:start_color_sp
fun:_ZN7display6Canvas10initializeEv
fun:_ZN7Control10initializeEv
fun:main
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
...
fun:_ZN7display6Canvas10initializeEv
}
+4 -39
View File
@@ -1,36 +1,3 @@
// 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.
//
@@ -41,7 +8,7 @@
#define RAK_ADDRESS_INFO_H
#include <netdb.h>
#include <rak/socket_address.h>
#include <cstring>
namespace rak {
@@ -57,13 +24,11 @@ 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); }
size_t length() const { return m_addrinfo.ai_addrlen; }
addrinfo* c_addrinfo() { return &m_addrinfo; }
const addrinfo* c_addrinfo() const { return &m_addrinfo; }
@@ -86,7 +51,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));
}
-85
View File
@@ -1,85 +0,0 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
#ifndef RAK_ERROR_NUMBER_H
#define RAK_ERROR_NUMBER_H
#include <cerrno>
#include <cstring>
namespace rak {
class error_number {
public:
static const int e_access = EACCES;
static const int e_again = EAGAIN;
static const int e_connreset = ECONNRESET;
static const int e_connaborted = ECONNABORTED;
static const int e_deadlk = EDEADLK;
static const int e_noent = ENOENT;
static const int e_nodev = ENODEV;
static const int e_nomem = ENOMEM;
static const int e_notdir = ENOTDIR;
static const int e_isdir = EISDIR;
static const int e_intr = EINTR;
error_number() : m_errno(0) {}
error_number(int e) : m_errno(e) {}
bool is_valid() const { return m_errno != 0; }
int value() const { return m_errno; }
const char* c_str() const { return std::strerror(m_errno); }
bool is_blocked_momentary() const { return m_errno == e_again || m_errno == e_intr; }
bool is_blocked_prolonged() const { return m_errno == e_deadlk; }
bool is_closed() const { return m_errno == e_connreset || m_errno == e_connaborted; }
bool is_bad_path() const { return m_errno == e_noent || m_errno == e_notdir || m_errno == e_access; }
static error_number current() { return errno; }
static void clear_global() { errno = 0; }
static void set_global(error_number err) { errno = err.m_errno; }
bool operator == (const error_number& e) const { return m_errno == e.m_errno; }
private:
int m_errno;
};
}
#endif
-75
View File
@@ -1,75 +0,0 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
#ifndef RAK_FILE_STAT_H
#define RAK_FILE_STAT_H
#include <string>
#include <cinttypes>
#include <sys/stat.h>
namespace rak {
class file_stat {
public:
// Consider storing rak::error_number.
bool update(int fd) { return fstat(fd, &m_stat) == 0; }
bool update(const char* filename) { return stat(filename, &m_stat) == 0; }
bool update(const std::string& filename) { return update(filename.c_str()); }
bool update_link(const char* filename) { return lstat(filename, &m_stat) == 0; }
bool update_link(const std::string& filename) { return update_link(filename.c_str()); }
bool is_regular() const { return S_ISREG(m_stat.st_mode); }
bool is_directory() const { return S_ISDIR(m_stat.st_mode); }
bool is_character() const { return S_ISCHR(m_stat.st_mode); }
bool is_block() const { return S_ISBLK(m_stat.st_mode); }
bool is_fifo() const { return S_ISFIFO(m_stat.st_mode); }
bool is_link() const { return S_ISLNK(m_stat.st_mode); }
bool is_socket() const { return S_ISSOCK(m_stat.st_mode); }
off_t size() const { return m_stat.st_size; }
time_t access_time() const { return m_stat.st_atime; }
time_t change_time() const { return m_stat.st_ctime; }
time_t modified_time() const { return m_stat.st_mtime; }
private:
struct stat m_stat;
};
}
#endif
-105
View File
@@ -1,105 +0,0 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
// Various functions for manipulating file paths. Also consider making
// a directory iterator.
#ifndef RAK_PATH_H
#define RAK_PATH_H
#include <cstdlib>
#include <string>
namespace rak {
inline std::string
path_expand(const std::string& path) {
if (path.empty() || path[0] != '~')
return path;
char* home = std::getenv("HOME");
if (home == NULL)
return path;
return home + path.substr(1);
}
// Don't inline this...
//
// Same strlcpy as found in *bsd.
inline size_t
strlcpy(char *dest, const char *src, size_t size) {
size_t n = size;
const char* first = src;
if (n != 0) {
while (--n != 0)
if ((*dest++ = *src++) == '\0')
break;
}
if (n == 0) {
if (size != 0)
*dest = '\0';
while (*src++)
;
}
return src - first - 1;
}
inline char*
path_expand(const char* src, char* first, char* last) {
if (*src == '~') {
char* home = std::getenv("HOME");
if (home == NULL)
return first;
first += strlcpy(first, home, std::distance(first, last));
if (first > last)
return last;
src++;
}
return std::min(first + strlcpy(first, src, std::distance(first, last)), last);
}
}
#endif
-557
View File
@@ -1,557 +0,0 @@
// rak - Rakshasa's toolbox
// Copyright (C) 2005-2007, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
// 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(static_cast<void*>(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
+2 -1
View File
@@ -30,7 +30,8 @@ AC_DEFUN([TORRENT_REMOVE_UNWANTED],
$1="$2"
else
result=`echo "${values_to_check}" | $GREP -Fvx -- "${unwanted_values}" | $GREP -v '^$'`
$1=$(echo "$result" | tr -d '\n')
# join with spaces, squeeze repeats, and trim trailing space
$1=$(printf '%s\n' "$result" | tr '\n' ' ' | sed 's/ */ /g; s/ *$//')
fi
])
+11 -7
View File
@@ -13,8 +13,6 @@ libsub_root_a_SOURCES = \
core/download_factory.h \
core/download_list.cc \
core/download_list.h \
core/download_store.cc \
core/download_store.h \
core/http_queue.cc \
core/http_queue.h \
core/manager.cc \
@@ -125,6 +123,16 @@ libsub_root_a_SOURCES = \
rpc/tinyxml2/tinyxml2.cc \
rpc/nlohmann/json.h \
\
scgi/thread_scgi.cc \
scgi/thread_scgi.h \
\
session/download_storer.cc \
session/download_storer.h \
session/session_manager.cc \
session/session_manager.h \
session/thread_session.cc \
session/thread_session.h \
\
ui/download.cc \
ui/download.h \
ui/download_list.cc \
@@ -164,8 +172,6 @@ libsub_root_a_SOURCES = \
utils/list_focus.h \
utils/lockfile.cc \
utils/lockfile.h \
utils/socket_fd.cc \
utils/socket_fd.h \
\
command_download.cc \
command_dynamic.cc \
@@ -190,9 +196,7 @@ libsub_root_a_SOURCES = \
option_parser.cc \
option_parser.h \
signal_handler.cc \
signal_handler.h \
thread_worker.cc \
thread_worker.h
signal_handler.h
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -DPACKAGE_DATADIR=\"$(pkgdatadir)\"
+43 -35
View File
@@ -5,10 +5,6 @@
#include <functional>
#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>
@@ -23,13 +19,14 @@
#include <torrent/net/types.h>
#include <torrent/peer/connection_list.h>
#include <torrent/peer/peer_list.h>
#include <torrent/utils/file_stat.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "core/download.h"
#include "core/download_store.h"
#include "core/manager.h"
#include "rpc/parse.h"
#include "session/session_manager.h"
#include "globals.h"
#include "control.h"
@@ -79,23 +76,23 @@ apply_d_change_link(core::Download* download, const torrent::Object::list_type&
if (type == "base_path") {
target = rpc::call_command_string("d.base_path", rpc::make_target(download));
link = rak::path_expand(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix);
link = expand_path(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix);
} else if (type == "base_filename") {
target = rpc::call_command_string("d.base_path", rpc::make_target(download));
link = rak::path_expand(prefix + rpc::call_command_string("d.base_filename", rpc::make_target(download)) + postfix);
link = expand_path(prefix + rpc::call_command_string("d.base_filename", rpc::make_target(download)) + postfix);
// } else if (type == "directory_path") {
// target = rpc::call_command_string("d.directory", rpc::make_target(download));
// link = rak::path_expand(prefix + rpc::call_command_string("d.base_path", rpc::make_target(download)) + postfix);
} else if (type == "tied") {
link = rak::path_expand(rpc::call_command_string("d.tied_to_file", rpc::make_target(download)));
link = expand_path(rpc::call_command_string("d.tied_to_file", rpc::make_target(download)));
if (link.empty())
return torrent::Object();
link = rak::path_expand(prefix + link + postfix);
link = expand_path(prefix + link + postfix);
target = rpc::call_command_string("d.base_path", rpc::make_target(download));
} else {
@@ -104,22 +101,19 @@ 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",
rak::error_number::current().c_str());
}
if (symlink(target.c_str(), link.c_str()) == -1)
lt_log_print(torrent::LOG_TORRENT_WARN, "create_link failed: %s", std::strerror(errno));
break;
case 1:
{
rak::file_stat fileStat;
rak::error_number::clear_global();
torrent::utils::FileStat 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));
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:
@@ -136,8 +130,8 @@ apply_d_delete_tied(core::Download* download) {
if (tie.empty())
return torrent::Object();
if (::unlink(rak::path_expand(tie).c_str()) == -1)
control->core()->push_log_std("Could not unlink tied file: " + std::string(rak::error_number::current().c_str()));
if (::unlink(expand_path(tie).c_str()) == -1)
control->core()->push_log_std("Could not unlink tied file: " + std::string(std::strerror(errno)));
rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(download));
return torrent::Object();
@@ -307,7 +301,7 @@ apply_d_add_peer(core::Download* download, const std::string& arg) {
if (port < 1 || port > 65535)
throw torrent::input_error("Invalid port number.");
assert(std::this_thread::get_id() == torrent::main_thread::thread()->thread_id());
assert(std::this_thread::get_id() == torrent::main_thread::thread_id());
// Currently discarding SOCK_STREAM.
torrent::this_thread::resolver()->resolve_preferred(NULL, host, AF_UNSPEC, AF_INET, [download, port](torrent::c_sa_shared_ptr sa, int err) {
@@ -500,6 +494,19 @@ download_get_variable(core::Download* download, const char* first_key, const cha
return download->bencode()->get_key(first_key).get_key(second_key);
}
torrent::Object
download_get_value_or_zero(core::Download* download, const char* first_key, const char* second_key = NULL) {
auto object = download_get_variable(download, first_key, second_key);
if (object.is_empty())
return int64_t(0);
if (!object.is_value())
throw torrent::bencode_error("Download variable is not a value.");
return object;
}
torrent::Object
download_set_variable(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key = NULL) {
if (second_key == NULL)
@@ -544,16 +551,13 @@ download_set_variable_string(core::Download* download, const torrent::Object::st
//
torrent::Object
d_list_push_back_string(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) {
auto& arg = rawArgs.as_string();
d_list_push_back_string(core::Download* download, const std::string& arg, const char* first_key, const char* second_key) {
download_get_variable(download, first_key, second_key).as_list().push_back(arg);
return torrent::Object();
}
torrent::Object
d_list_push_back_unique_string(core::Download* download, const torrent::Object& rawArgs, const char* first_key, const char* second_key) {
auto& arg = rawArgs.as_string();
d_list_push_back_unique_string(core::Download* download, const std::string& arg, const char* first_key, const char* second_key) {
torrent::Object::list_type& list = download_get_variable(download, first_key, second_key).as_list();
if (std::none_of(list.begin(), list.end(), [arg](const torrent::Object& obj) { return torrent::object_equal(obj, arg); }))
@@ -608,12 +612,16 @@ d_list_remove(core::Download* download, const torrent::Object& rawArgs, const ch
#define CMD2_DL_TIMESTAMP(key, first_key, second_key) \
CMD2_DL(key, std::bind(&download_get_variable, std::placeholders::_1, first_key, second_key)); \
CMD2_DL_VALUE_P(key ".set", std::bind(&download_set_variable_value, \
std::placeholders::_1, std::placeholders::_2, \
first_key, second_key)); \
CMD2_DL_VALUE_P(key ".set", std::bind(&download_set_variable_value, \
std::placeholders::_1, std::placeholders::_2, \
first_key, second_key)); \
CMD2_DL_VALUE_P(key ".set_if_z", std::bind(&download_set_variable_value_ifz, \
std::placeholders::_1, std::placeholders::_2, \
first_key, second_key)); \
CMD2_DL(key ".or_zero", [](core::Download* download, auto) { \
return download_get_value_or_zero(download, first_key, second_key); }); \
CMD2_DL_VALUE(key ".elapsed", [](core::Download* download, auto value) { \
return download_get_value_or_zero(download, first_key, second_key).as_value() > value; });
#define CMD2_DL_VAR_STRING(key, first_key, second_key) \
CMD2_DL(key, std::bind(&download_get_variable, std::placeholders::_1, first_key, second_key)); \
@@ -691,8 +699,8 @@ initialize_command_download() {
CMD2_DL_V ("d.erase", std::bind(&core::DownloadList::erase_ptr, control->core()->download_list(), std::placeholders::_1));
CMD2_DL_V ("d.check_hash", std::bind(&core::DownloadList::check_hash, control->core()->download_list(), std::placeholders::_1));
CMD2_DL ("d.save_resume", std::bind(&core::DownloadStore::save_resume, control->core()->download_store(), std::placeholders::_1));
CMD2_DL ("d.save_full_session", std::bind(&core::DownloadStore::save_full, control->core()->download_store(), std::placeholders::_1));
CMD2_DL_V ("d.save_resume", [](core::Download* download, auto) { session_thread::manager()->save_resume_download(download); });
CMD2_DL_V ("d.save_full_session", [](core::Download* download, auto) { session_thread::manager()->save_full_download(download); });
CMD2_DL_V ("d.update_priorities", CMD2_ON_DL(update_priorities));
@@ -774,8 +782,8 @@ initialize_command_download() {
CMD2_DL ("d.views", std::bind(&download_get_variable, std::placeholders::_1, "rtorrent", "views"));
CMD2_DL ("d.views.has", std::bind(&d_list_has, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
CMD2_DL ("d.views.remove", std::bind(&d_list_remove, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
CMD2_DL ("d.views.push_back", std::bind(&d_list_push_back_string, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
CMD2_DL ("d.views.push_back_unique", std::bind(&d_list_push_back_unique_string, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
CMD2_DL_STRING ("d.views.push_back", std::bind(&d_list_push_back_string, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
CMD2_DL_STRING ("d.views.push_back_unique", std::bind(&d_list_push_back_unique_string, std::placeholders::_1, std::placeholders::_2, "rtorrent", "views"));
// This command really needs to be improved, so we have proper
// logging support.
+1 -1
View File
@@ -411,7 +411,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", 0);
CMD2_VAR_VALUE ("method.use_intermediate", 3);
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));
+14 -16
View File
@@ -2,14 +2,12 @@
#include <functional>
#include <cstdio>
#include <rak/error_number.h>
#include <rak/file_stat.h>
#include <rak/path.h>
#include <rak/string_manip.h>
#include <torrent/rate.h>
#include <torrent/hash_string.h>
#include <torrent/utils/log.h>
#include <torrent/utils/directory_events.h>
#include <torrent/utils/file_stat.h>
#include "globals.h"
#include "control.h"
@@ -25,7 +23,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("group2." + group_name + ".view", rpc::make_target()).as_string());
auto view_itr = control->view_manager()->find(rpc::commands.call("group." + 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 +31,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("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();
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();
std::vector<core::Download*> downloads;
@@ -67,10 +65,10 @@ apply_start_tied() {
if (rpc::call_command_value("d.state", rpc::make_target(download)) == 1)
continue;
rak::file_stat fs;
torrent::utils::FileStat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
if (!tied_to_file.empty() && fs.update(rak::path_expand(tied_to_file)))
if (!tied_to_file.empty() && fs.update(expand_path(tied_to_file)))
rpc::parse_command_single(rpc::make_target(download), "d.try_start=");
}
@@ -83,10 +81,10 @@ apply_stop_untied() {
if (rpc::call_command_value("d.state", rpc::make_target(download)) == 0)
continue;
rak::file_stat fs;
torrent::utils::FileStat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
if (!tied_to_file.empty() && !fs.update(rak::path_expand(tied_to_file)))
if (!tied_to_file.empty() && !fs.update(expand_path(tied_to_file)))
rpc::parse_command_single(rpc::make_target(download), "d.try_stop=");
}
@@ -96,10 +94,10 @@ apply_stop_untied() {
torrent::Object
apply_close_untied() {
for (const auto& download : *control->core()->download_list()) {
rak::file_stat fs;
torrent::utils::FileStat fs;
const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(download));
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)))
if (rpc::call_command_value("d.ignore_commands", rpc::make_target(download)) == 0 && !tied_to_file.empty() && !fs.update(expand_path(tied_to_file)))
rpc::parse_command_single(rpc::make_target(download), "d.try_close=");
}
@@ -109,10 +107,10 @@ apply_close_untied() {
torrent::Object
apply_remove_untied() {
for (auto itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ) {
rak::file_stat fs;
torrent::utils::FileStat fs;
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))) {
if (!tied_to_file.empty() && !fs.update(expand_path(tied_to_file))) {
// Need to clear tied_to_file so it doesn't try to delete it.
rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(*itr));
@@ -301,7 +299,7 @@ directory_watch_added(const torrent::Object::list_type& args) {
auto& command = args.back().as_string();
if (!control->directory_events()->open())
throw torrent::input_error("Could not open inotify:" + std::string(rak::error_number::current().c_str()));
throw torrent::input_error("Could not open inotify:" + std::string(std::strerror(errno)));
control->directory_events()->notify_on(path.c_str(),
torrent::directory_events::flag_on_added | torrent::directory_events::flag_on_updated,
-36
View File
@@ -1,41 +1,5 @@
// 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 <torrent/data/file.h>
#include <torrent/data/file_list.h>
#include <torrent/data/file_list_iterator.h>
-34
View File
@@ -1,37 +1,3 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
#include "config.h"
#include <torrent/exceptions.h>
+9 -12
View File
@@ -100,24 +100,21 @@ 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_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_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_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:
+10 -46
View File
@@ -1,54 +1,18 @@
// 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 <fstream>
#include <rak/path.h>
#include <torrent/peer/peer_list.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "globals.h"
#include "command_helpers.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <torrent/peer/peer_list.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "globals.h"
#include "command_helpers.h"
bool ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end);
@@ -89,7 +53,7 @@ apply_ip_tables_get(const torrent::Object::list_type& args) {
if (table_itr == ip_tables.end())
throw torrent::input_error("Could not find ip table.");
if (!ipv4_range_parse(address.c_str(), &address_start, &address_end))
if (!ipv4_range_parse(address.c_str(), &address_start, &address_end))
throw torrent::input_error("Invalid address format.");
if(!table_itr->table.defined(address_start, address_end))
@@ -298,7 +262,7 @@ apply_ipv4_filter_get(const std::string& args) {
uint32_t address_start;
uint32_t address_end;
if (!ipv4_range_parse(args.c_str(), &address_start, &address_end))
if (!ipv4_range_parse(args.c_str(), &address_start, &address_end))
throw torrent::input_error("Invalid address format.");
if(!torrent::PeerList::ipv4_filter()->defined(address_start, address_end))
@@ -326,8 +290,8 @@ apply_ipv4_filter_load(const torrent::Object::list_type& args) {
std::string value_name = args.back().as_string();
int value = torrent::option_find_string(torrent::OPTION_IP_FILTER, value_name.c_str());
std::fstream file(rak::path_expand(filename).c_str(), std::ios::in);
std::fstream file(expand_path(filename).c_str(), std::ios::in);
if (!file.is_open())
throw torrent::input_error("Could not open ip filter file: " + filename);
+33 -43
View File
@@ -1,11 +1,10 @@
#include "config.h"
#include <cerrno>
#include <fcntl.h>
#include <functional>
#include <stdio.h>
#include <unistd.h>
#include <rak/path.h>
#include <rak/error_number.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <torrent/torrent.h>
@@ -17,11 +16,11 @@
#include "core/download.h"
#include "core/download_list.h"
#include "core/download_store.h"
#include "core/manager.h"
#include "rak/string_manip.h"
#include "rpc/parse_commands.h"
#include "rpc/scgi.h"
#include "session/session_manager.h"
#include "utils/file_status_cache.h"
#include "globals.h"
@@ -116,34 +115,22 @@ 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("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));
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));
if (rpc::call_command_value("method.use_intermediate") == 1) {
// Deprecated in 0.7.0:
if (rpc::call_command_value("method.use_intermediate") == 3) {
// Cleaned up in 0.16.1:
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");
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");
}
return name;
@@ -183,8 +170,8 @@ cmd_file_append(const torrent::Object::list_type& args) {
FILE* output = fopen(args.front().as_string().c_str(), "a");
if (output == NULL)
throw torrent::input_error("Could not append to file '" + args.front().as_string() + "': " + rak::error_number::current().c_str());
if (output == nullptr)
throw torrent::input_error("Could not append to file '" + args.front().as_string() + "': " + std::strerror(errno));
file_print_list(++args.begin(), args.end(), output, file_print_delim_space);
@@ -196,7 +183,6 @@ cmd_file_append(const torrent::Object::list_type& args) {
void
initialize_command_local() {
core::DownloadList* dList = control->core()->download_list();
core::DownloadStore* dStore = control->core()->download_store();
torrent::ChunkManager* chunkManager = torrent::chunk_manager();
torrent::FileManager* fileManager = torrent::file_manager();
@@ -224,7 +210,8 @@ initialize_command_local() {
CMD2_ANY_VALUE_V ("system.files.advise_random.set", std::bind(&FM_t::set_advise_random, fileManager, std::placeholders::_2));
CMD2_ANY ("system.files.advise_random.hashing", std::bind(&FM_t::advise_random_hashing, fileManager));
CMD2_ANY_VALUE_V ("system.files.advise_random.hashing.set", std::bind(&FM_t::set_advise_random_hashing, fileManager, std::placeholders::_2));
CMD2_VAR_BOOL ("system.files.session.fdatasync", true);
CMD2_ANY ("system.files.session.fdatasync", [](auto, auto) { return session_thread::manager()->use_fsyncdisk(); });
CMD2_ANY_VALUE_V ("system.files.session.fdatasync.set", [](auto, auto& value) { return session_thread::manager()->set_use_fsyncdisk(value); });
CMD2_ANY ("system.files.opened_counter", std::bind(&FM_t::files_opened_counter, fileManager));
CMD2_ANY ("system.files.closed_counter", std::bind(&FM_t::files_closed_counter, fileManager));
@@ -248,7 +235,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_GENERIC_NO_EXPORT("system.shutdown", "system.shutdown.normal");
CMD2_REDIRECT_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));
@@ -282,22 +269,25 @@ initialize_command_local() {
CMD2_ANY ("pieces.hash.queue_size", std::bind(&torrent::main_thread::hash_queue_size));
CMD2_VAR_BOOL ("pieces.hash.on_completion", true);
CMD2_VAR_STRING ("directory.default", "./");
CMD2_VAR_STRING ("directory.default", "./");
CMD2_VAR_STRING ("session.name", "");
CMD2_VAR_BOOL ("session.use_lock", true);
CMD2_VAR_BOOL ("session.on_completion", true);
CMD2_VAR_STRING ("session.name", "");
CMD2_ANY ("session.path", [](auto, auto) { return session_thread::manager()->path(); });
CMD2_ANY_STRING_V("session.path.set", [](auto, auto& str) { return session_thread::manager()->set_path(str); });
CMD2_ANY ("session.use_lock", [](auto, auto) { return session_thread::manager()->use_lock(); });
CMD2_ANY_VALUE_V ("session.use_lock.set", [](auto, auto& value) { return session_thread::manager()->set_use_lock(value); });
CMD2_VAR_BOOL ("session.on_completion", true);
CMD2_ANY ("session.path", std::bind(&core::DownloadStore::path, dStore));
CMD2_ANY_STRING_V("session.path.set", std::bind(&core::DownloadStore::set_path, dStore, std::placeholders::_2));
CMD2_ANY_V ("session.save", [dList](auto, auto) { return dList->session_save(); });
CMD2_ANY_V ("session.save", std::bind(&core::DownloadList::session_save, dList));
CMD2_ANY ("magnet.path", [](auto, auto) { return control->core()->magnet_path(); });
CMD2_ANY_STRING_V("magnet.path.set", [](auto, auto& str) { return control->core()->set_magnet_path(str); });
#ifdef HAVE_LUA
rpc::LuaEngine* lua_engine = control->lua_engine();
CMD2_ANY ("lua.execute", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, 0));
CMD2_ANY ("lua.execute.str", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, rpc::LuaEngine::flag_string));
CMD2_ANY ("lua.execute", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, 0));
CMD2_ANY ("lua.execute.str", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, rpc::LuaEngine::flag_string));
#endif
#define CMD2_EXECUTE(key, flags) \
+26 -23
View File
@@ -8,19 +8,18 @@
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "core/download.h"
#include "core/download_list.h"
#include "core/manager.h"
#include "rak/path.h"
#include "rpc/parse_commands.h"
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "core/download.h"
#include "core/download_list.h"
#include "core/manager.h"
#include "rpc/parse_commands.h"
static const int log_flag_use_gz = 0x1;
static const int log_flag_append_pid = 0x2;
static const int log_flag_append_file = 0x4;
static const int log_flag_flush = 0x8;
void
log_add_group_output_str(const char* group_name, const char* output_id) {
@@ -35,8 +34,8 @@ apply_log_open(int output_flags, const torrent::Object::list_type& args) {
torrent::Object::list_const_iterator itr = args.begin();
std::string output_id = (itr++)->as_string();
std::string file_name = rak::path_expand((itr++)->as_string());
auto output_id = (itr++)->as_string();
auto file_name = expand_path((itr++)->as_string());
if ((output_flags & log_flag_append_pid)) {
char buffer[32];
@@ -46,11 +45,12 @@ apply_log_open(int output_flags, const torrent::Object::list_type& args) {
}
bool append = (output_flags & log_flag_append_file);
bool flush = (output_flags & log_flag_flush);
if ((output_flags & log_flag_use_gz))
torrent::log_open_gz_file_output(output_id.c_str(), file_name.c_str(), append);
else
torrent::log_open_file_output(output_id.c_str(), file_name.c_str(), append);
torrent::log_open_file_output(output_id.c_str(), file_name.c_str(), append, flush);
while (itr != args.end())
log_add_group_output_str((itr++)->as_string().c_str(), output_id.c_str());
@@ -62,7 +62,7 @@ torrent::Object
apply_log_add_output(const torrent::Object::list_type& args) {
if (args.size() != 2)
throw torrent::input_error("Invalid number of arguments.");
log_add_group_output_str(args.front().as_string().c_str(),
args.back().as_string().c_str());
@@ -86,7 +86,7 @@ apply_log(const torrent::Object::string_type& arg, int logType) {
}
if (!arg.empty()) {
int logFd = open(rak::path_expand(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644);
int logFd = open(expand_path(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644);
if (logFd < 0)
throw torrent::input_error("Could not open execute log file.");
@@ -128,19 +128,22 @@ log_vmmap_dump(const std::string& str) {
void
initialize_command_logging() {
CMD2_ANY_LIST ("log.open_file", std::bind(&apply_log_open, 0, std::placeholders::_2));
CMD2_ANY_LIST ("log.open_gz_file", std::bind(&apply_log_open, log_flag_use_gz, std::placeholders::_2));
CMD2_ANY_LIST ("log.open_file_pid", std::bind(&apply_log_open, log_flag_append_pid, std::placeholders::_2));
CMD2_ANY_LIST ("log.open_gz_file_pid", std::bind(&apply_log_open, log_flag_append_pid | log_flag_use_gz, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_gz_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
CMD2_ANY_LIST ("log.open_file", std::bind(&apply_log_open, 0, std::placeholders::_2));
CMD2_ANY_LIST ("log.open_file.flush", std::bind(&apply_log_open, log_flag_flush, std::placeholders::_2));
CMD2_ANY_LIST ("log.open_gz_file", std::bind(&apply_log_open, log_flag_use_gz, std::placeholders::_2));
CMD2_ANY_LIST ("log.open_file_pid", std::bind(&apply_log_open, log_flag_append_pid, std::placeholders::_2));
CMD2_ANY_LIST ("log.open_gz_file_pid", std::bind(&apply_log_open, log_flag_append_pid | log_flag_use_gz, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_file.flush", std::bind(&apply_log_open, log_flag_append_file | log_flag_flush, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_gz_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
CMD2_ANY_STRING ("log.execute", std::bind(&apply_log, std::placeholders::_2, 0));
CMD2_ANY_STRING ("log.vmmap.dump", std::bind(&log_vmmap_dump, std::placeholders::_2));
CMD2_ANY_STRING_V("log.rpc", std::bind(&ThreadWorker::set_rpc_log, worker_thread, std::placeholders::_2));
CMD2_REDIRECT ("log.xmlrpc", "log.rpc"); // For backwards compatibility
CMD2_ANY_STRING ("log.execute", std::bind(&apply_log, std::placeholders::_2, 0));
CMD2_ANY_STRING ("log.vmmap.dump", std::bind(&log_vmmap_dump, std::placeholders::_2));
CMD2_ANY_STRING_V("log.rpc", [](const auto&, const auto& str) { scgi_thread::set_rpc_log(str); });
CMD2_REDIRECT ("log.xmlrpc", "log.rpc"); // For backwards compatibility
}
+90 -76
View File
@@ -4,17 +4,20 @@
#include <cstdio>
#include <unistd.h>
#include <rak/address_info.h>
#include <rak/path.h>
#include <torrent/torrent.h>
#include <torrent/rate.h>
#include <torrent/connection_manager.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/socket_address.h>
#include <torrent/tracker/tracker.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "core/download.h"
#include "core/manager.h"
#include "rpc/scgi.h"
@@ -22,24 +25,20 @@
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
torrent::Object
apply_encryption(const torrent::Object::list_type& args) {
uint32_t options_mask = torrent::ConnectionManager::encryption_none;
uint32_t options_mask = torrent::net::NetworkConfig::encryption_none;
for (const auto& arg : args) {
uint32_t opt = torrent::option_find_string(torrent::OPTION_ENCRYPTION, arg.as_string().c_str());
if (opt == torrent::ConnectionManager::encryption_none)
options_mask = torrent::ConnectionManager::encryption_none;
if (opt == torrent::net::NetworkConfig::encryption_none)
options_mask = torrent::net::NetworkConfig::encryption_none;
else
options_mask |= opt;
}
torrent::connection_manager()->set_encryption_options(options_mask);
torrent::config::network_config()->set_encryption_options(options_mask);
return torrent::Object();
}
@@ -51,7 +50,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::connection_manager()->set_priority(value);
torrent::config::network_config()->set_priority(value);
return torrent::Object();
}
@@ -77,7 +76,7 @@ initialize_rpc_handlers() {
torrent::Object
apply_scgi(const std::string& arg, int type) {
if (worker_thread->scgi() != NULL)
if (scgi_thread::scgi() != nullptr)
throw torrent::input_error("SCGI already enabled.");
initialize_rpc_handlers();
@@ -85,8 +84,7 @@ apply_scgi(const std::string& arg, int type) {
rpc::SCgi* scgi = new rpc::SCgi;
rak::address_info* ai = NULL;
rak::socket_address sa;
rak::socket_address* saPtr;
torrent::sa_unique_ptr sa;
try {
int port, err;
@@ -97,17 +95,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.sa_inet()->clear();
saPtr = &sa;
sa = torrent::sa_make_inet();
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)) + ".");
saPtr = ai->address();
sa = torrent::sa_copy(ai->c_addrinfo()->ai_addr);
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is bound to an address and might be a security risk");
@@ -118,14 +116,14 @@ apply_scgi(const std::string& arg, int type) {
if (port <= 0 || port >= (1 << 16))
throw torrent::input_error("Invalid port number.");
saPtr->set_port(port);
scgi->open_port(saPtr, saPtr->length(), rpc::call_command_value("network.scgi.dont_route"));
torrent::sap_set_port(sa, port);
scgi->open_port(sa.get(), torrent::sap_length(sa), rpc::call_command_value("network.scgi.dont_route"));
break;
case 2:
default:
path = rak::path_expand(arg);
path = expand_path(arg);
unlink(path.c_str());
scgi->open_named(path);
@@ -141,7 +139,7 @@ apply_scgi(const std::string& arg, int type) {
throw torrent::input_error(e.what());
}
worker_thread->set_scgi(scgi);
scgi_thread::set_scgi(scgi);
return torrent::Object();
}
@@ -165,8 +163,9 @@ apply_xmlrpc_dialect(const std::string& arg) {
void
initialize_command_network() {
auto cm = torrent::connection_manager();
auto fileManager = torrent::file_manager();
auto file_manager = torrent::file_manager();
auto http_stack = torrent::net_thread::http_stack();
auto nw_config = torrent::config::network_config();
CMD2_ANY_STRING ("encoding.add", std::bind(&apply_encoding_list, std::placeholders::_2));
@@ -175,76 +174,91 @@ initialize_command_network() {
CMD2_VAR_BOOL ("network.port_random", true);
CMD2_VAR_STRING ("network.port_range", "6881-6999");
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_ANY ("network.listen.port", [](auto, auto) { return torrent::runtime::listen_port(); });
CMD2_ANY ("network.listen.backlog", [nw_config](auto, auto) { return nw_config->listen_backlog(); });
CMD2_ANY_VALUE_V ("network.listen.backlog.set", [nw_config](auto, auto& value) { return nw_config->set_listen_backlog(value); });
CMD2_VAR_BOOL ("protocol.pex", true);
CMD2_ANY_LIST ("protocol.encryption.set", std::bind(&apply_encryption, std::placeholders::_2));
CMD2_VAR_BOOL ("protocol.pex", true);
CMD2_ANY_LIST ("protocol.encryption.set", [](auto, auto& args) { return apply_encryption(args); });
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->active(); });
CMD2_ANY ("network.http.max_open", [http_stack](auto, auto) { return http_stack->max_active(); });
CMD2_ANY_VALUE_V ("network.http.max_open.set", [http_stack](auto, auto& value) { return http_stack->set_max_active(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", [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.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.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.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.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.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 ("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_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", 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.block.ipv4in6", std::bind(&torrent::ConnectionManager::is_block_ipv4in6, cm));
CMD2_ANY_VALUE_V ("network.block.ipv4in6.set", std::bind(&torrent::ConnectionManager::set_block_ipv4in6, 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));
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); });
}
+8 -43
View File
@@ -1,45 +1,9 @@
// 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>
@@ -67,17 +31,18 @@ retrieve_p_id_html(torrent::Peer* peer) {
torrent::Object
retrieve_p_address(torrent::Peer* peer) {
const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address());
auto sa = peer->peer_info()->socket_address();
auto addr_str = torrent::sa_addr_str(sa);
if (addr->family() == rak::socket_address::af_inet6)
return "[" + addr->address_str() + "]";
else
return addr->address_str();
if (sa->sa_family == AF_INET6)
return "[" + addr_str + "]";
return addr_str;
}
torrent::Object
retrieve_p_port(torrent::Peer* peer) {
return rak::socket_address::cast_from(peer->peer_info()->socket_address())->port();
return torrent::sa_port(peer->peer_info()->socket_address());
}
torrent::Object
+19 -46
View File
@@ -1,47 +1,14 @@
// 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"
@@ -57,13 +24,16 @@ 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;
rak::socket_address sa;
sa.copy(*ai->address(), ai->length());
begin = end = sa.sa_inet()->address_h();
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::address_info::free_address_info(ai);
if (ret == 2) {
@@ -71,18 +41,21 @@ 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.sa_inet()->address_h() & ~netmask)
if (prefixWidth >= 32 || sa_addr & ~netmask)
throw torrent::input_error("Invalid address/prefix.");
end = sa.sa_inet()->address_h() | ~netmask;
end = sa_addr | ~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.copy(*ai->address(), ai->length());
sa = torrent::sa_copy(ai->c_addrinfo()->ai_addr);
sa_addr = htonl(reinterpret_cast<sockaddr_in*>(sa.get())->sin_addr.s_addr);
rak::address_info::free_address_info(ai);
end = sa.sa_inet()->address_h();
end = sa_addr;
}
// convert to [begin, end) making sure the end doesn't overflow
@@ -194,10 +167,10 @@ initialize_command_throttle() {
CMD2_VAR_VALUE ("throttle.max_downloads.div._val", 1);
CMD2_VAR_VALUE ("throttle.max_downloads.global._val", 0);
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_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_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));
+14 -12
View File
@@ -3,9 +3,9 @@
#include <cassert>
#include <cstdio>
#include <netdb.h>
#include <rak/address_info.h>
#include <rak/error_number.h>
#include <torrent/net/network_config.h>
#include <torrent/net/resolver.h>
#include <torrent/runtime/network_manager.h>
#include <torrent/tracker/dht_controller.h>
#include <torrent/tracker/tracker.h>
#include <torrent/utils/log.h>
@@ -28,9 +28,6 @@ tracker_set_enabled(torrent::tracker::Tracker* tracker, bool state) {
torrent::Object
apply_dht_add_node(const std::string& arg) {
if (!torrent::dht_controller()->is_valid())
throw torrent::input_error("DHT not enabled.");
int port;
char dummy;
char host[1024];
@@ -45,7 +42,7 @@ apply_dht_add_node(const std::string& arg) {
if (port < 1 || port > 65535)
throw torrent::input_error("Invalid port number.");
assert(std::this_thread::get_id() == torrent::main_thread::thread()->thread_id());
assert(std::this_thread::get_id() == torrent::main_thread::thread_id());
auto host_str = std::string(host);
@@ -59,7 +56,7 @@ apply_dht_add_node(const std::string& arg) {
}
lt_log_print(torrent::LOG_DHT_CONTROLLER, "dht.add_node : %s", host_str.c_str());
torrent::dht_controller()->add_node(sa.get(), port);
torrent::runtime::network_manager()->dht_add_bootstrap_node(host_str.c_str(), port);
});
return torrent::Object();
@@ -142,11 +139,16 @@ 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));
// TODO: This should query DhtController.
CMD2_VAR_VALUE ("dht.port", int64_t(6881));
CMD2_ANY ("dht.port", [](auto, auto) { return torrent::runtime::network_manager()->dht_controller()->port(); });
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_ANY_STRING ("dht.add_node", std::bind(&apply_dht_add_node, 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));
CMD2_ANY ("dht.statistics", std::bind(&core::DhtManager::dht_statistics, dht_manager));
}
+23 -22
View File
@@ -4,12 +4,11 @@
#include <unistd.h>
#include <sys/stat.h>
#include <torrent/connection_manager.h>
#include <torrent/net/http_stack.h>
#include <torrent/runtime/network_manager.h>
#include <torrent/utils/directory_events.h>
#include "core/dht_manager.h"
#include "core/download_store.h"
#include "core/http_queue.h"
#include "core/manager.h"
#include "core/view_manager.h"
@@ -26,6 +25,7 @@
#include "rpc/lua.h"
#include "rpc/parse_commands.h"
#include "rpc/object_storage.h"
#include "session/session_manager.h"
#include "ui/root.h"
Control::Control()
@@ -38,9 +38,9 @@ Control::Control()
m_lua_engine(new rpc::LuaEngine()),
m_directory_events(new torrent::directory_events()) {
m_core = std::make_unique<core::Manager>();
m_viewManager = std::make_unique<core::ViewManager>();
m_dhtManager = std::make_unique<core::DhtManager>();
m_core = std::make_unique<core::Manager>();
m_view_manager = std::make_unique<core::ViewManager>();
m_dht_manager = std::make_unique<core::DhtManager>();
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input.get(), std::placeholders::_1));
@@ -50,7 +50,7 @@ Control::Control()
}
Control::~Control() {
m_viewManager.reset();
m_view_manager.reset();
m_ui.reset();
m_display.reset();
@@ -58,6 +58,9 @@ Control::~Control() {
void
Control::initialize() {
session_thread::thread()->start_thread();
scgi_thread::thread()->start_thread();
display::Canvas::initialize();
display::Window::slot_schedule([this](display::Window* w, std::chrono::microseconds t) { m_display->schedule(w, t); });
display::Window::slot_unschedule([this](display::Window* w) { m_display->unschedule(w); });
@@ -66,10 +69,7 @@ Control::initialize() {
torrent::net_thread::http_stack()->set_user_agent(USER_AGENT);
m_core->listen_open();
m_core->download_store()->enable(rpc::call_command_value("session.use_lock"));
m_core->set_hashing_view(*m_viewManager->find_throw("hashing"));
m_dhtManager->set_port(torrent::connection_manager()->listen_port());
m_core->set_hashing_view(*m_view_manager->find_throw("hashing"));
m_ui->init(this);
@@ -83,11 +83,15 @@ Control::cleanup() {
torrent::this_thread::scheduler()->erase(&m_task_shutdown);
if(!display::Canvas::daemon()) {
if(!display::Canvas::daemon())
m_inputStdin->remove(torrent::this_thread::poll());
}
m_core->download_store()->disable();
if (scgi_thread::thread()->is_active())
scgi_thread::thread()->stop_thread_wait();
// Wait for all session files to be written.
session_thread::manager()->flush_all_pending_builds();
session_thread::thread()->stop_thread_wait();
m_ui->cleanup();
m_core->cleanup();
@@ -105,7 +109,7 @@ Control::cleanup_exception() {
bool
Control::is_shutdown_completed() {
if (!m_shutdownQuick || worker_thread->is_active())
if (!m_shutdownQuick)
return false;
// Tracker requests can be disowned, so wait for these to
@@ -114,7 +118,7 @@ Control::is_shutdown_completed() {
// 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()->active() != 0 || !core()->http_queue()->empty())
if (torrent::net_thread::http_stack()->size() != 0 || !core()->http_queue()->empty())
return false;
return torrent::is_inactive();
@@ -124,11 +128,11 @@ void
Control::handle_shutdown() {
rpc::commands.call_catch("event.system.shutdown", rpc::make_target(), "shutdown", "System shutdown event action failed: ");
if (!m_shutdownQuick) {
if (worker_thread->is_active())
worker_thread->stop_thread_wait();
if (scgi_thread::thread()->is_active())
scgi_thread::thread()->stop_thread_wait();
torrent::connection_manager()->listen_close();
if (!m_shutdownQuick) {
torrent::runtime::network_manager()->listen_close();
m_directory_events->close();
m_core->shutdown(false);
@@ -137,9 +141,6 @@ Control::handle_shutdown() {
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown, 5s);
} else {
if (worker_thread->is_active())
worker_thread->stop_thread_wait();
m_core->shutdown(true);
}
+4 -4
View File
@@ -57,8 +57,8 @@ public:
void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; }
core::Manager* core() { return m_core.get(); }
core::ViewManager* view_manager() { return m_viewManager.get(); }
core::DhtManager* dht_manager() { return m_dhtManager.get(); }
core::ViewManager* view_manager() { return m_view_manager.get(); }
core::DhtManager* dht_manager() { return m_dht_manager.get(); }
ui::Root* ui() { return m_ui.get(); }
display::Manager* display() { return m_display.get(); }
@@ -82,8 +82,8 @@ private:
void operator = (const Control&);
std::unique_ptr<core::Manager> m_core;
std::unique_ptr<core::ViewManager> m_viewManager;
std::unique_ptr<core::DhtManager> m_dhtManager;
std::unique_ptr<core::ViewManager> m_view_manager;
std::unique_ptr<core::DhtManager> m_dht_manager;
std::unique_ptr<ui::Root> m_ui;
std::unique_ptr<display::Manager> m_display;
+36 -66
View File
@@ -1,22 +1,22 @@
#include "config.h"
#include "dht_manager.h"
#include <fstream>
#include <sstream>
#include <torrent/object.h>
#include <torrent/object_stream.h>
#include <torrent/rate.h>
#include <torrent/runtime/network_manager.h>
#include <torrent/tracker/dht_controller.h>
#include <torrent/utils/log.h>
#include "rpc/parse_commands.h"
#include "globals.h"
#include "control.h"
#include "dht_manager.h"
#include "download.h"
#include "download_store.h"
#include "globals.h"
#include "manager.h"
#include "rpc/parse_commands.h"
#include "session/session_manager.h"
#define LT_LOG(log_fmt, ...) \
lt_log_print_subsystem(torrent::LOG_DHT_CONTROLLER, "dht_manager", log_fmt, __VA_ARGS__);
@@ -33,25 +33,15 @@ DhtManager::~DhtManager() {
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
}
void
DhtManager::set_port(uint16_t port) {
if (torrent::dht_controller()->is_active()) {
LT_LOG_ERROR("cannot change port while DHT is active", 0);
throw torrent::input_error("cannot change port while DHT is active");
}
m_port = port;
}
void
DhtManager::load_dht_cache() {
if (m_start == dht_disable || !control->core()->download_store()->is_enabled()) {
if (m_start == dht_disable || !session_thread::manager()->is_used()) {
LT_LOG("ignoring cache file", 0);
return;
}
std::string cache_filename = control->core()->download_store()->path() + "rtorrent.dht_cache";
std::fstream cache_stream(cache_filename.c_str(), std::ios::in | std::ios::binary);
auto cache_filename = session_thread::manager()->path() + "rtorrent.dht_cache";
auto cache_stream = std::fstream(cache_filename.c_str(), std::ios::in | std::ios::binary);
torrent::Object cache = torrent::Object::create_map();
@@ -71,7 +61,7 @@ DhtManager::load_dht_cache() {
LT_LOG("could not open cache file (path:%s)", cache_filename.c_str());
}
torrent::dht_controller()->initialize(cache);
torrent::runtime::network_manager()->dht_controller()->initialize(cache);
if (m_start == dht_on)
start_dht();
@@ -81,33 +71,22 @@ void
DhtManager::start_dht() {
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
if (!torrent::dht_controller()->is_valid()) {
if (!torrent::runtime::network_manager()->is_dht_valid()) {
LT_LOG("server start skipped, manager is uninitialized", 0);
return;
}
if (torrent::dht_controller()->is_active()) {
if (torrent::runtime::network_manager()->is_dht_active()) {
LT_LOG("server start skipped, already active", 0);
return;
}
torrent::ThrottlePair throttles = control->core()->get_throttle(m_throttleName);
torrent::dht_controller()->set_upload_throttle(throttles.first);
torrent::dht_controller()->set_download_throttle(throttles.second);
if (m_port <= 0) {
LT_LOG("server start skipped, port not set", 0);
return;
}
LT_LOG("starting server : port=%" PRIu16, m_port);
if (!torrent::dht_controller()->start(m_port)) {
if (!torrent::runtime::network_manager()->dht_controller()->start()) {
m_start = dht_off;
return;
}
torrent::dht_controller()->reset_statistics();
torrent::runtime::network_manager()->dht_controller()->reset_statistics();
m_update_timeout.slot() = std::bind(&DhtManager::update, this);
@@ -126,28 +105,31 @@ DhtManager::stop_dht() {
torrent::this_thread::scheduler()->erase(&m_update_timeout);
torrent::this_thread::scheduler()->erase(&m_stop_timeout);
if (torrent::dht_controller()->is_active()) {
if (torrent::runtime::network_manager()->is_dht_active()) {
LT_LOG("stopping server", 0);
log_statistics(true);
torrent::dht_controller()->stop();
torrent::runtime::network_manager()->dht_controller()->stop();
}
}
void
DhtManager::save_dht_cache() {
if (!control->core()->download_store()->is_enabled() || !torrent::dht_controller()->is_valid())
if (!session_thread::manager()->is_used())
return;
std::string filename = control->core()->download_store()->path() + "rtorrent.dht_cache";
std::string filename_tmp = filename + ".new";
std::fstream cache_file(filename_tmp.c_str(), std::ios::out | std::ios::trunc);
if (!torrent::runtime::network_manager()->is_dht_valid())
return;
auto filename = session_thread::manager()->path() + "rtorrent.dht_cache";
auto filename_tmp = filename + ".new";
auto cache_file = std::fstream(filename_tmp.c_str(), std::ios::out | std::ios::trunc);
if (!cache_file.is_open())
return;
torrent::Object cache = torrent::Object::create_map();
cache_file << *torrent::dht_controller()->store_cache(&cache);
cache_file << *torrent::runtime::network_manager()->dht_controller()->store_cache(&cache);
if (!cache_file.good())
return;
@@ -178,7 +160,7 @@ DhtManager::set_mode(const std::string& arg) {
void
DhtManager::update() {
if (!torrent::dht_controller()->is_active())
if (!torrent::runtime::network_manager()->is_dht_active())
throw torrent::internal_error("DhtManager::update called with DHT inactive.");
if (m_start == dht_auto && !m_stop_timeout.is_scheduled()) {
@@ -203,17 +185,17 @@ DhtManager::update() {
bool
DhtManager::log_statistics(bool force) {
auto stats = torrent::dht_controller()->get_statistics();
auto stats = torrent::runtime::network_manager()->dht_controller()->get_statistics();
// Check for firewall problems.
if (stats.cycle > 2 && stats.queries_sent - m_dhtPrevQueriesSent > 100 && stats.queries_received == m_dhtPrevQueriesReceived) {
// 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())
if (torrent::runtime::network_manager()->is_dht_active_and_receiving_requests())
LT_LOG("listening port appears to be unreachable, no queries received", 0);
torrent::dht_controller()->set_receive_requests(false);
torrent::runtime::network_manager()->dht_controller()->set_receive_requests(false);
}
if (stats.queries_sent - m_dhtPrevQueriesSent > stats.num_nodes * 2 + 20 && stats.replies_received == m_dhtPrevRepliesReceived) {
@@ -228,7 +210,7 @@ DhtManager::log_statistics(bool force) {
m_warned = false;
if (stats.queries_received > m_dhtPrevQueriesReceived)
torrent::dht_controller()->set_receive_requests(true);
torrent::runtime::network_manager()->dht_controller()->set_receive_requests(true);
// Nothing to log while bootstrapping, but check again every minute.
if (stats.cycle <= 1) {
@@ -250,13 +232,11 @@ DhtManager::log_statistics(bool force) {
if ((force && stats.cycle != m_dhtPrevCycle) || stats.cycle == 3 || stats.cycle > m_dhtPrevCycle + 7) {
char buffer[256];
snprintf(buffer, sizeof(buffer),
"DHT statistics: %d queries in, %d queries out, %d replies received, %lld bytes read, %lld bytes sent, "
"DHT statistics: %d queries in, %d queries out, %d replies received, "
"%d known nodes in %d buckets, %d peers (highest: %d) tracked in %d torrents.",
stats.queries_received - m_dhtPrevQueriesReceived,
stats.queries_sent - m_dhtPrevQueriesSent,
stats.replies_received - m_dhtPrevRepliesReceived,
(long long unsigned int)(stats.down_rate.total() - m_dhtPrevBytesDown),
(long long unsigned int)(stats.up_rate.total() - m_dhtPrevBytesUp),
stats.num_nodes,
stats.num_buckets,
stats.num_peers,
@@ -269,8 +249,6 @@ DhtManager::log_statistics(bool force) {
m_dhtPrevQueriesSent = stats.queries_sent;
m_dhtPrevRepliesReceived = stats.replies_received;
m_dhtPrevQueriesReceived = stats.queries_received;
m_dhtPrevBytesUp = stats.up_rate.total();
m_dhtPrevBytesDown = stats.down_rate.total();
}
return false;
@@ -281,11 +259,11 @@ DhtManager::dht_statistics() {
torrent::Object dhtStats = torrent::Object::create_map();
dhtStats.insert_key("dht", dht_settings[m_start]);
dhtStats.insert_key("active", torrent::dht_controller()->is_active());
dhtStats.insert_key("throttle", m_throttleName);
dhtStats.insert_key("active", torrent::runtime::network_manager()->is_dht_active());
dhtStats.insert_key("throttle", "");
if (torrent::dht_controller()->is_active()) {
auto stats = torrent::dht_controller()->get_statistics();
if (torrent::runtime::network_manager()->is_dht_active()) {
auto stats = torrent::runtime::network_manager()->dht_controller()->get_statistics();
dhtStats.insert_key("cycle", stats.cycle);
dhtStats.insert_key("queries_received", stats.queries_received);
@@ -293,8 +271,8 @@ DhtManager::dht_statistics() {
dhtStats.insert_key("replies_received", stats.replies_received);
dhtStats.insert_key("errors_received", stats.errors_received);
dhtStats.insert_key("errors_caught", stats.errors_caught);
dhtStats.insert_key("bytes_read", stats.down_rate.total());
dhtStats.insert_key("bytes_written", stats.up_rate.total());
dhtStats.insert_key("bytes_read", int64_t());
dhtStats.insert_key("bytes_written", int64_t());
dhtStats.insert_key("nodes", stats.num_nodes);
dhtStats.insert_key("buckets", stats.num_buckets);
dhtStats.insert_key("peers", stats.num_peers);
@@ -305,12 +283,4 @@ DhtManager::dht_statistics() {
return dhtStats;
}
void
DhtManager::set_throttle_name(const std::string& throttleName) {
if (torrent::dht_controller()->is_active())
throw torrent::input_error("Cannot set DHT throttle while active.");
m_throttleName = throttleName;
}
}
-10
View File
@@ -10,9 +10,6 @@ class DhtManager {
public:
~DhtManager();
uint16_t port() const { return m_port; }
void set_port(uint16_t port);
void load_dht_cache();
void save_dht_cache();
torrent::Object dht_statistics();
@@ -23,9 +20,6 @@ public:
void set_mode(const std::string& arg);
void set_throttle_name(const std::string& throttleName);
const std::string& throttle_name() const { return m_throttleName; }
private:
static const int dht_disable = 0;
static const int dht_off = 1;
@@ -49,11 +43,7 @@ private:
torrent::utils::SchedulerEntry m_stop_timeout;
bool m_warned{};
int m_start{dht_off};
uint16_t m_port{0};
std::string m_throttleName;
};
}
+11 -10
View File
@@ -1,25 +1,25 @@
#include "config.h"
#include "core/download.h"
#include <list>
#include <rak/file_stat.h>
#include <rak/path.h>
#include <torrent/exceptions.h>
#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 <torrent/utils/file_stat.h>
#include "rpc/parse_commands.h"
#include "control.h"
#include "download.h"
#include "manager.h"
#include "core/manager.h"
namespace core {
Download::Download(download_type d) :
m_download(d) {
Download::Download(download_type d)
: m_download(d) {
m_download.info()->signal_tracker_success().push_back(std::bind(&Download::receive_tracker_msg, this, ""));
m_download.info()->signal_tracker_failed().push_back(std::bind(&Download::receive_tracker_msg, this, std::placeholders::_1));
@@ -118,13 +118,14 @@ void
Download::set_root_directory(const std::string& path) {
// If the download is open, hashed and has completed chunks make
// sure to verify that the download files are still present.
//
//
// This should ensure that no one tries to set the destination
// directory 'after' moving files. In cases where the user wants to
// override this behavior the download must first be closed or
// 'd.directory_base.set' may be used.
rak::file_stat file_stat;
torrent::FileList* file_list = m_download.file_list();
torrent::utils::FileStat file_stat;
torrent::FileList* file_list = m_download.file_list();
if (is_hash_checked() && file_list->completed_chunks() != 0 &&
@@ -140,7 +141,7 @@ Download::set_root_directory(const std::string& path) {
}
control->core()->download_list()->close_directly(this);
file_list->set_root_dir(rak::path_expand(path));
file_list->set_root_dir(expand_path(path));
bencode()->get_key("rtorrent").insert_key("directory", path);
}
+16 -8
View File
@@ -7,7 +7,6 @@
#include <functional>
#include <sstream>
#include <stdexcept>
#include <rak/path.h>
#include <torrent/utils/log.h>
#include <torrent/utils/resume.h>
#include <torrent/object.h>
@@ -20,7 +19,6 @@
#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"
@@ -124,7 +122,7 @@ DownloadFactory::receive_load() {
receive_loaded();
} else {
std::fstream stream(rak::path_expand(m_uri).c_str(), std::ios::in | std::ios::binary);
std::fstream stream(expand_path(m_uri).c_str(), std::ios::in | std::ios::binary);
if (!stream.is_open())
return receive_failed("Could not open file");
@@ -159,8 +157,8 @@ DownloadFactory::receive_commit() {
void
DownloadFactory::receive_success() {
auto rtorrent_object = download_factory_load_stream((rak::path_expand(m_uri) + ".rtorrent").c_str());
auto libtorrent_resume_object = download_factory_load_stream((rak::path_expand(m_uri) + ".libtorrent_resume").c_str());
auto rtorrent_object = download_factory_load_stream((expand_path(m_uri) + ".rtorrent").c_str());
auto libtorrent_resume_object = download_factory_load_stream((expand_path(m_uri) + ".libtorrent_resume").c_str());
uint32_t tracker_key;
@@ -255,11 +253,21 @@ DownloadFactory::receive_success() {
rpc::call_command_value("system.file.split_size"),
rpc::call_command_string("system.file.split_suffix"));
if (!rtorrent->has_key_string("directory"))
rpc::call_command("d.directory.set", m_variables["directory"], rpc::make_target(download));
else
if (rtorrent->has_key_string("directory")) {
rpc::call_command("d.directory_base.set", rtorrent->get_key("directory"), rpc::make_target(download));
} else if (download->download()->info()->is_meta_download()) {
auto& metadata_path = control->core()->magnet_path();
if (!metadata_path.empty())
rpc::call_command("d.directory.set", metadata_path, rpc::make_target(download));
else
rpc::call_command("d.directory.set", session_thread::session_path(), rpc::make_target(download));
} else {
rpc::call_command("d.directory.set", m_variables["directory"], rpc::make_target(download));
}
if (!m_session && m_variables["tied_to_file"].as_value())
rpc::call_command("d.tied_to_file.set", m_uri.empty() ? m_variables["tied_file"] : m_uri, rpc::make_target(download));
+11 -15
View File
@@ -22,10 +22,10 @@
#include "view.h"
#include "view_manager.h"
#include "dht_manager.h"
#include "download.h"
#include "download_list.h"
#include "download_store.h"
#include "core/dht_manager.h"
#include "core/download.h"
#include "core/download_list.h"
#include "session/session_manager.h"
#include "ui/root.h"
#define DL_TRIGGER_EVENT(download, event_name) \
@@ -68,10 +68,8 @@ DownloadList::clear() {
void
DownloadList::session_save() {
unsigned int c = std::count_if(begin(), end(), [&](Download* d) { return control->core()->download_store()->save_resume(d); });
if (c != size())
lt_log_print(torrent::LOG_ERROR, "Failed to save session torrents.");
for (auto& download : *this)
session_thread::manager()->save_resume_download(download);
control->dht_manager()->save_dht_cache();
control->ui()->save_input_history();
@@ -199,10 +197,10 @@ DownloadList::erase(iterator itr) {
(*itr)->set_hash_failed(true);
close(*itr);
control->core()->download_store()->remove(*itr);
session_thread::manager()->remove_download(*itr);
DL_TRIGGER_EVENT(*itr, "event.download.erased");
for (auto v : *control->view_manager())
v->erase(*itr);
@@ -639,10 +637,8 @@ DownloadList::confirm_finished(Download* download) {
// the download.
//
// Obsolete.
if (!download->is_active() && rpc::call_command_value("session.on_completion") != 0) {
// torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume"));
control->core()->download_store()->save_resume(download);
}
if (!download->is_active() && rpc::call_command_value("session.on_completion") != 0)
session_thread::manager()->save_resume_download(download);
// Send the completed request before resuming so we don't reset the
// up/downloaded baseline.
@@ -655,7 +651,7 @@ DownloadList::confirm_finished(Download* download) {
if (find(infohash) == end())
return;
// if (download->resume_flags() != ~uint32_t())
// throw torrent::internal_error("DownloadList::confirm_finished(...) download->resume_flags() != ~uint32_t().");
-205
View File
@@ -1,205 +0,0 @@
// DownloadStore handles the saving and listing of session torrents.
#include "config.h"
#include <fstream>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <rak/error_number.h>
#include <rak/path.h>
#include <rak/string_manip.h>
#include <torrent/utils/resume.h>
#include <torrent/object.h>
#include <torrent/exceptions.h>
#include <torrent/torrent.h>
#include <torrent/rate.h>
#include <torrent/object_stream.h>
#include "utils/directory.h"
#include "download.h"
#include "download_store.h"
#include "rpc/parse_commands.h"
namespace core {
void
DownloadStore::enable(bool lock) {
if (is_enabled())
throw torrent::input_error("Session directory already enabled.");
if (m_path.empty())
return;
if (lock)
m_lockfile.set_path(m_path + "rtorrent.lock");
else
m_lockfile.set_path(std::string());
if (!m_lockfile.try_lock()) {
if (rak::error_number::current().is_bad_path())
throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", " + rak::error_number::current().c_str());
else
throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", held by \"" + m_lockfile.locked_by_as_string() + "\".");
}
}
void
DownloadStore::disable() {
if (!is_enabled())
return;
m_lockfile.unlock();
}
void
DownloadStore::set_path(const std::string& path) {
if (is_enabled())
throw torrent::input_error("Tried to change session directory while it is enabled.");
if (!path.empty() && *path.rbegin() != '/')
m_path = rak::path_expand(path + '/');
else
m_path = rak::path_expand(path);
}
bool
DownloadStore::write_bencode(const std::string& filename, const torrent::Object& obj, uint32_t skip_mask) {
int fd;
torrent::Object tmp;
std::fstream output(filename.c_str(), std::ios::out | std::ios::trunc);
if (!output.is_open())
goto download_store_save_error;
torrent::object_write_bencode(&output, &obj, skip_mask);
if (!output.good())
goto download_store_save_error;
output.close();
// Test the new file, to ensure it is a valid bencode string.
output.open(filename.c_str(), std::ios::in);
output >> tmp;
if (!output.good())
goto download_store_save_error;
output.close();
// Ensure that the new file is actually written to the disk
fd = ::open(filename.c_str(), O_WRONLY);
if (fd < 0)
goto download_store_save_error;
if (rpc::call_command_value("system.files.session.fdatasync")) {
#ifdef __APPLE__
fsync(fd);
#else
fdatasync(fd);
#endif
}
::close(fd);
return true;
download_store_save_error:
output.close();
return false;
}
bool
DownloadStore::save(Download* d, int flags) {
if (!is_enabled())
return true;
torrent::Object* resume_base = &d->download()->bencode()->get_key("libtorrent_resume");
torrent::Object* rtorrent_base = &d->download()->bencode()->get_key("rtorrent");
// Move this somewhere else?
rtorrent_base->insert_key("chunks_done", d->download()->file_list()->completed_chunks());
rtorrent_base->insert_key("chunks_wanted", d->download()->data()->wanted_chunks());
rtorrent_base->insert_key("total_uploaded", d->info()->up_rate()->total());
rtorrent_base->insert_key("total_downloaded", d->info()->down_rate()->total());
// Don't save for completed torrents when we've cleared the uncertain_pieces.
torrent::resume_save_progress(*d->download(), *resume_base);
torrent::resume_save_uncertain_pieces(*d->download(), *resume_base);
torrent::resume_save_addresses(*d->download(), *resume_base);
torrent::resume_save_file_priorities(*d->download(), *resume_base);
torrent::resume_save_tracker_settings(*d->download(), *resume_base);
// Temp fixing of all flags, move to a better place:
resume_base->set_flags(torrent::Object::flag_session_data);
rtorrent_base->set_flags(torrent::Object::flag_session_data);
std::string base_filename = create_filename(d);
if (!write_bencode(base_filename + ".libtorrent_resume.new", *resume_base, 0) ||
!write_bencode(base_filename + ".rtorrent.new", *rtorrent_base, 0))
return false;
::rename((base_filename + ".libtorrent_resume.new").c_str(), (base_filename + ".libtorrent_resume").c_str());
::rename((base_filename + ".rtorrent.new").c_str(), (base_filename + ".rtorrent").c_str());
if (!(flags & flag_skip_static) &&
write_bencode(base_filename + ".new", *d->bencode(), torrent::Object::flag_session_data))
::rename((base_filename + ".new").c_str(), base_filename.c_str());
return true;
}
void
DownloadStore::remove(Download* d) {
if (!is_enabled())
return;
::unlink((create_filename(d) + ".libtorrent_resume").c_str());
::unlink((create_filename(d) + ".rtorrent").c_str());
::unlink(create_filename(d).c_str());
}
// This also needs to check that it isn't a directory.
bool
not_correct_format(const utils::directory_entry& entry) {
return !DownloadStore::is_correct_format(entry.s_name);
}
utils::Directory
DownloadStore::get_formated_entries() {
if (!is_enabled())
return utils::Directory();
utils::Directory d(m_path);
if (!d.update(utils::Directory::update_hide_dot))
throw torrent::storage_error("core::DownloadStore::update() could not open directory \"" + m_path + "\"");
d.erase(std::remove_if(d.begin(), d.end(), [&](const utils::directory_entry& entry) { return not_correct_format(entry); }), d.end());
return d;
}
bool
DownloadStore::is_correct_format(const std::string& f) {
if (f.size() != 48 || f.substr(40) != ".torrent")
return false;
for (std::string::const_iterator itr = f.begin(); itr != f.end() - 8; ++itr)
if (!(*itr >= '0' && *itr <= '9') &&
!(*itr >= 'A' && *itr <= 'F'))
return false;
return true;
}
std::string
DownloadStore::create_filename(Download* d) {
return m_path + rak::transform_hex(d->info()->hash().begin(), d->info()->hash().end()) + ".torrent";
}
}
-49
View File
@@ -1,49 +0,0 @@
#ifndef RTORRENT_CORE_DOWNLOAD_STORE_H
#define RTORRENT_CORE_DOWNLOAD_STORE_H
#include <string>
#include "utils/lockfile.h"
namespace utils {
class Directory;
}
namespace core {
class Download;
class DownloadStore {
public:
static const int flag_skip_static = 0x1;
bool is_enabled() { return m_lockfile.is_locked(); }
void enable(bool lock);
void disable();
const std::string& path() const { return m_path; }
void set_path(const std::string& path);
bool save(Download* d, int flags);
bool save_full(Download* d) { return save(d, 0); }
bool save_resume(Download* d) { return save(d, flag_skip_static); }
void remove(Download* d);
// Currently shows all entries in the correct format.
utils::Directory get_formated_entries();
static bool is_correct_format(const std::string& f);
private:
std::string create_filename(Download* d);
bool write_bencode(const std::string& filename, const torrent::Object& obj, uint32_t skip_mask);
std::string m_path;
utils::Lockfile m_lockfile;
};
}
#endif
+30 -83
View File
@@ -1,5 +1,7 @@
#include "config.h"
#include "core/manager.h"
#include <cstdio>
#include <cstring>
#include <fstream>
@@ -7,9 +9,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>
#include <torrent/utils/resume.h>
#include <torrent/object.h>
@@ -19,6 +19,9 @@
#include <torrent/object_stream.h>
#include <torrent/throttle.h>
#include <torrent/net/http_stack.h>
#include <torrent/net/network_config.h>
#include <torrent/net/socket_address.h>
#include <torrent/runtime/network_manager.h>
#include <torrent/utils/log.h>
#include "rpc/parse_commands.h"
@@ -30,9 +33,7 @@
#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"
namespace core {
@@ -48,11 +49,10 @@ Manager::push_log(const char* msg) {
m_log_complete->lock_and_push_log(msg, strlen(msg), 0);
}
Manager::Manager() :
m_log_important(torrent::log_open_log_buffer("important")),
Manager::Manager()
: m_log_important(torrent::log_open_log_buffer("important")),
m_log_complete(torrent::log_open_log_buffer("complete")) {
m_download_store = std::make_unique<DownloadStore>();
m_download_list = std::make_unique<DownloadList>();
m_file_status_cache = std::make_unique<FileStatusCache>();
m_http_queue = std::make_unique<HttpQueue>();
@@ -97,7 +97,10 @@ Manager::set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePai
torrent::ThrottlePair
Manager::get_address_throttle(const sockaddr* addr) {
return m_addressThrottles.get(rak::socket_address::cast_from(addr)->sa_inet()->address_h(), torrent::ThrottlePair(nullptr, nullptr));
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));
}
int64_t
@@ -129,6 +132,16 @@ Manager::retrieve_throttle_value(const torrent::Object::string_type& name, bool
}
}
void
Manager::set_magnet_path(const std::string& path) {
if (path.empty())
m_magnet_path.clear();
else if (path.back() == '/')
m_magnet_path = path;
else
m_magnet_path = path + '/';
}
void
Manager::cleanup() {
// Need to disconnect log signals? Not really since we won't receive
@@ -171,84 +184,16 @@ Manager::listen_open() {
if (rpc::call_command_value("network.port_random")) {
int boundary = portFirst + random() % (portLast - portFirst + 1);
if (torrent::connection_manager()->listen_open(boundary, portLast) ||
torrent::connection_manager()->listen_open(portFirst, boundary))
if (torrent::runtime::network_manager()->listen_open(boundary, portLast) ||
torrent::runtime::network_manager()->listen_open(portFirst, boundary))
return;
} else {
if (torrent::connection_manager()->listen_open(portFirst, portLast))
if (torrent::runtime::network_manager()->listen_open(portFirst, portLast))
return;
}
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());
}
if (ai->address()->is_address_any())
torrent::net_thread::http_stack()->set_bind_address(std::string());
else
torrent::net_thread::http_stack()->set_bind_address(ai->address()->address_str());
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();
throw torrent::input_error("Could not open/bind port for listening: " + std::string(std::strerror(errno)));
}
void
@@ -271,8 +216,10 @@ Manager::set_proxy_address(const std::string& addr) {
try {
ai->address()->set_port(port);
torrent::connection_manager()->set_proxy_address(ai->address()->c_sockaddr());
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());
rak::address_info::free_address_info(ai);
@@ -310,7 +257,7 @@ Manager::try_create_download(const std::string& uri, int flags, const command_li
!is_network_uri(uri) &&
!is_magnet_uri(uri) &&
!is_data_uri(uri) &&
!file_status_cache()->insert(uri, 0))
!file_status_cache()->insert(uri))
return;
// Adding download.
+7 -10
View File
@@ -21,7 +21,6 @@ class FileStatusCache;
namespace core {
class DownloadStore;
class HttpQueue;
typedef std::map<std::string, torrent::ThrottlePair> ThrottleMap;
@@ -37,7 +36,6 @@ public:
~Manager();
DownloadList* download_list() { return m_download_list.get(); }
DownloadStore* download_store() { return m_download_store.get(); }
FileStatusCache* file_status_cache() { return m_file_status_cache.get(); }
HttpQueue* http_queue() { return m_http_queue.get(); }
@@ -61,15 +59,11 @@ public:
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);
const std::string& magnet_path();
void set_magnet_path(const std::string& path);
void shutdown(bool force);
void push_log(const char* msg);
@@ -102,7 +96,6 @@ private:
void receive_hashing_changed();
std::unique_ptr<DownloadList> m_download_list;
std::unique_ptr<DownloadStore> m_download_store;
std::unique_ptr<FileStatusCache> m_file_status_cache;
std::unique_ptr<HttpQueue> m_http_queue;
@@ -113,11 +106,15 @@ private:
torrent::log_buffer_ptr m_log_important;
torrent::log_buffer_ptr m_log_complete;
std::string m_magnet_path;
};
// Meh, cleanup.
extern void receive_tracker_dump(const std::string& url, const char* data, size_t size);
inline const std::string& Manager::magnet_path() { return m_magnet_path; }
}
#endif
+38 -30
View File
@@ -11,23 +11,31 @@
namespace display {
bool Canvas::m_isInitialized = false;
bool Canvas::m_isDaemon = false;
bool Canvas::m_initialized{};
bool Canvas::m_daemon{};
// Maps ncurses color IDs to a ncurses attribute int
std::unordered_map<int, int> Canvas::m_attr_map = {};
Canvas::Canvas(int x, int y, int width, int height) {
if (!m_isDaemon) {
if (!m_daemon) {
m_window = newwin(height, width, y, x);
if (m_window == NULL)
if (m_window == nullptr)
throw torrent::internal_error("Could not allocate ncurses canvas.");
}
}
Canvas::~Canvas() {
if (!m_daemon && m_window != nullptr) {
delwin(m_window);
m_window = nullptr;
}
}
void
Canvas::resize(int x, int y, int w, int h) {
if (!m_isDaemon) {
if (!m_daemon) {
wresize(m_window, h, w);
mvwin(m_window, y, x);
}
@@ -35,7 +43,7 @@ Canvas::resize(int x, int y, int w, int h) {
void
Canvas::print_attributes(unsigned int x, unsigned int y, const char* first, const char* last, const attributes_list* attributes) {
if (!m_isDaemon) {
if (!m_daemon) {
move(x, y);
attr_t org_attr;
@@ -68,14 +76,13 @@ Canvas::print_attributes(unsigned int x, unsigned int y, const char* first, cons
void
Canvas::initialize() {
if (m_isInitialized)
return;
if (m_initialized)
throw torrent::internal_error("Canvas::initialize() called more than once.");
m_isDaemon = rpc::call_command_value("system.daemon");
m_daemon = rpc::call_command_value("system.daemon");
m_initialized = true;
m_isInitialized = true;
if (!m_isDaemon) {
if (!m_daemon) {
initscr();
start_color();
use_default_colors();
@@ -88,6 +95,19 @@ Canvas::initialize() {
}
}
void
Canvas::cleanup() {
if (!m_initialized)
return;
m_initialized = false;
if (!m_daemon) {
noraw();
endwin();
}
}
// Function wrapper for what possibly is a macro
int
get_colors() {
@@ -102,7 +122,7 @@ Canvas::build_colors() {
// This may get called early in the start process by the config
// file, so we need to delay building until initscr() has a chance
// to run
if (!m_isInitialized || m_isDaemon)
if (!m_initialized || m_daemon)
return;
// basic color names, index maps to ncurses COLOR_*
@@ -115,7 +135,9 @@ Canvas::build_colors() {
for (int k = 1; k < RCOLOR_MAX; k++) {
init_pair(k, -1, -1);
std::string color_def = rpc::call_command_string(color_vars[k]);
if (color_def.empty())
continue; // Use terminal default if definition is empty
@@ -126,6 +148,7 @@ Canvas::build_colors() {
// Process string as space-separated words
size_t start = 0, end = 0;
while (true) {
end = color_def.find(' ', start);
std::string word = color_def.substr(start, end - start);
@@ -169,10 +192,8 @@ Canvas::build_colors() {
// Check that fg & bg color index is valid
if ((color[0] != -1 && color[0] >= get_colors()) || (color[1] != -1 && color[1] >= get_colors())) {
char buf[33];
snprintf(buf, 33, "%d", get_colors());
Canvas::cleanup();
throw torrent::input_error(color_def + ": your terminal only supports " + buf + " colors.");
throw torrent::input_error(color_def + ": your terminal only supports " + std::to_string(get_colors()) + " colors.");
}
m_attr_map[k] = attr; // overwrite or insert the value
@@ -196,24 +217,11 @@ Canvas::build_colors() {
}
}
void
Canvas::cleanup() {
if (!m_isInitialized)
return;
m_isInitialized = false;
if (!m_isDaemon) {
noraw();
endwin();
}
}
std::pair<int, int>
Canvas::term_size() {
struct winsize ws;
if (!m_isDaemon) {
if (!m_daemon) {
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0)
return std::pair<int, int>(ws.ws_col, ws.ws_row);
}
+29 -34
View File
@@ -54,9 +54,10 @@ public:
// Initialize stdscr.
static void initialize();
static void build_colors();
static void cleanup();
static void build_colors();
static int get_screen_width();
static int get_screen_height();
@@ -64,15 +65,15 @@ public:
static void do_update();
static bool daemon() { return m_isDaemon; }
static bool daemon() { return m_daemon; }
static const attributes_map& attr_map() { return m_attr_map; }
private:
Canvas(const Canvas&);
void operator=(const Canvas&);
static bool m_isInitialized;
static bool m_isDaemon;
static bool m_initialized;
static bool m_daemon;
// Maps ncurses color IDs to a ncurses attribute int
static std::unordered_map<int, int> m_attr_map;
@@ -80,57 +81,51 @@ private:
WINDOW* m_window;
};
inline Canvas::~Canvas() {
if (!m_isDaemon) {
delwin(m_window);
}
}
inline void
Canvas::refresh() {
if (!m_isDaemon) {
if (!m_daemon) {
wnoutrefresh(m_window);
}
}
inline void
Canvas::refresh_std() {
if (!m_isDaemon) {
if (!m_daemon) {
wnoutrefresh(stdscr);
}
}
inline void
Canvas::redraw() {
if (!m_isDaemon) {
if (!m_daemon) {
redrawwin(m_window);
}
}
inline void
Canvas::redraw_std() {
if (!m_isDaemon) {
if (!m_daemon) {
redrawwin(stdscr);
}
}
inline void
Canvas::resize(int w, int h) {
if (!m_isDaemon) {
if (!m_daemon) {
wresize(m_window, h, w);
}
}
inline void
Canvas::resize_term(int x, int y) {
if (!m_isDaemon) {
if (!m_daemon) {
resizeterm(y, x);
}
}
inline void
Canvas::resize_term(std::pair<int, int> dim) {
if (!m_isDaemon) {
if (!m_daemon) {
resizeterm(dim.second, dim.first);
}
}
@@ -139,7 +134,7 @@ inline unsigned int
Canvas::get_x() {
int x;
[[maybe_unused]] int y;
if (!m_isDaemon) {
if (!m_daemon) {
getyx(m_window, y, x);
} else {
x = 1;
@@ -150,7 +145,7 @@ Canvas::get_x() {
inline unsigned int
Canvas::get_y() {
int x, y;
if (!m_isDaemon) {
if (!m_daemon) {
getyx(m_window, y, x);
} else {
y = 1;
@@ -162,7 +157,7 @@ inline unsigned int
Canvas::width() {
int x;
[[maybe_unused]] int y;
if (!m_isDaemon) {
if (!m_daemon) {
getmaxyx(m_window, y, x);
} else {
x = 80;
@@ -173,7 +168,7 @@ Canvas::width() {
inline unsigned int
Canvas::height() {
int x, y;
if (!m_isDaemon) {
if (!m_daemon) {
getmaxyx(m_window, y, x);
} else {
y = 24;
@@ -183,21 +178,21 @@ Canvas::height() {
inline void
Canvas::move(unsigned int x, unsigned int y) {
if (!m_isDaemon) {
if (!m_daemon) {
wmove(m_window, y, x);
}
}
inline void
Canvas::erase() {
if (!m_isDaemon) {
if (!m_daemon) {
werase(m_window);
}
}
inline void
Canvas::erase_std() {
if (!m_isDaemon) {
if (!m_daemon) {
werase(stdscr);
}
}
@@ -206,7 +201,7 @@ inline void
Canvas::print(const char* str, ...) {
va_list arglist;
if (!m_isDaemon) {
if (!m_daemon) {
va_start(arglist, str);
vw_printw(m_window, const_cast<char*>(str), arglist);
va_end(arglist);
@@ -217,7 +212,7 @@ inline void
Canvas::print(unsigned int x, unsigned int y, const char* str, ...) {
va_list arglist;
if (!m_isDaemon) {
if (!m_daemon) {
va_start(arglist, str);
wmove(m_window, y, x);
vw_printw(m_window, const_cast<char*>(str), arglist);
@@ -227,35 +222,35 @@ Canvas::print(unsigned int x, unsigned int y, const char* str, ...) {
inline void
Canvas::print_char(const chtype ch) {
if (!m_isDaemon) {
if (!m_daemon) {
waddch(m_window, ch);
}
}
inline void
Canvas::print_char(unsigned int x, unsigned int y, const chtype ch) {
if (!m_isDaemon) {
if (!m_daemon) {
mvwaddch(m_window, y, x, ch);
}
}
inline void
Canvas::set_attr(unsigned int x, unsigned int y, unsigned int n, int attr, int color) {
if (!m_isDaemon) {
if (!m_daemon) {
mvwchgat(m_window, y, x, n, attr, color, NULL);
}
}
inline void
Canvas::set_attr(unsigned int x, unsigned int y, unsigned int n, ColorKind k) {
if (!m_isDaemon) {
if (!m_daemon) {
mvwchgat(m_window, y, x, n, m_attr_map[k], k, NULL);
}
}
inline void
Canvas::set_default_attributes(int attr) {
if (!m_isDaemon) {
if (!m_daemon) {
(void)wattrset(m_window, attr);
}
}
@@ -264,7 +259,7 @@ inline int
Canvas::get_screen_width() {
int x;
[[maybe_unused]] int y;
if (!m_isDaemon) {
if (!m_daemon) {
getmaxyx(stdscr, y, x);
} else {
x = 80;
@@ -275,7 +270,7 @@ Canvas::get_screen_width() {
inline int
Canvas::get_screen_height() {
int x, y;
if (!m_isDaemon) {
if (!m_daemon) {
getmaxyx(stdscr, y, x);
} else {
y = 24;
@@ -285,7 +280,7 @@ Canvas::get_screen_height() {
inline void
Canvas::do_update() {
if (!m_isDaemon) {
if (!m_daemon) {
doupdate();
}
}
+14 -49
View File
@@ -1,47 +1,12 @@
// 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 "display/frame.h"
#include <algorithm>
#include <functional>
#include <rak/algorithm.h>
#include <torrent/exceptions.h>
#include "frame.h"
#include "window.h"
#include "display/window.h"
namespace display {
@@ -137,7 +102,7 @@ Frame::preferred_size() const {
for (size_type i = 0; i < m_containerSize; ++i) {
bounds_type p = m_container[i]->preferred_size();
accum.minWidth += p.minWidth;
accum.minHeight += p.minHeight;
@@ -221,7 +186,7 @@ Frame::clear() {
m_window->set_offscreen(true);
break;
case TYPE_ROW:
case TYPE_COLUMN:
for (size_type i = 0; i < m_containerSize; ++i) {
@@ -335,10 +300,10 @@ Frame::balance_row(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
dynamic_type dynamicFrames[max_size];
int remaining = height;
for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) {
bounds_type bounds = (*itr)->preferred_size();
if ((*itr)->is_height_dynamic()) {
(*itr)->m_height = 0;
dynamicFrames[dynamicSize++] = std::make_pair(*itr, bounds);
@@ -367,11 +332,11 @@ Frame::balance_row(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
for (dynamic_type *itr = dynamicFrames, *last = dynamicFrames + dynamicSize; itr != last; ++itr) {
uint32_t adjust = (std::max(remaining, 0) + std::distance(itr, last) - 1) / std::distance(itr, last);
adjust += itr->first->m_height;
adjust = std::max(adjust, itr->second.minHeight);
adjust = std::min(adjust, itr->second.maxHeight);
remaining -= adjust - itr->first->m_height;
retry = retry || itr->first->m_height != adjust;
@@ -410,10 +375,10 @@ Frame::balance_column(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
dynamic_type dynamicFrames[max_size];
int remaining = width;
for (Frame **itr = m_container, **last = m_container + m_containerSize; itr != last; ++itr) {
bounds_type bounds = (*itr)->preferred_size();
if ((*itr)->is_width_dynamic()) {
(*itr)->m_width = 0;
dynamicFrames[dynamicSize++] = std::make_pair(*itr, bounds);
@@ -423,7 +388,7 @@ Frame::balance_column(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
remaining -= bounds.minWidth;
}
}
// Sort the dynamic frames by the min size in the direction we are
// interested in. Then try to satisfy the largest first, and if we
// have any remaining space we can use that to extend it and any
@@ -442,11 +407,11 @@ Frame::balance_column(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
for (dynamic_type *itr = dynamicFrames, *last = dynamicFrames + dynamicSize; itr != last; ++itr) {
uint32_t adjust = (std::max(remaining, 0) + std::distance(itr, last) - 1) / std::distance(itr, last);
adjust += itr->first->m_width;
adjust = std::max(adjust, itr->second.minWidth);
adjust = std::min(adjust, itr->second.maxWidth);
remaining -= adjust - itr->first->m_width;
retry = retry || itr->first->m_width != adjust;
+2 -35
View File
@@ -1,41 +1,8 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
#ifndef RTORRENT_DISPLAY_FRAME_H
#define RTORRENT_DISPLAY_FRAME_H
#include <cinttypes>
#include <utility>
namespace display {
@@ -121,7 +88,7 @@ private:
union {
Window* m_window;
struct {
size_type m_containerSize;
Frame* m_container[max_size];
+1
View File
@@ -55,6 +55,7 @@ Manager::receive_update() {
m_force_redraw = false;
display::Canvas::resize_term(display::Canvas::term_size());
keypad(stdscr, TRUE);
Canvas::redraw_std();
adjust_layout();
+1 -1
View File
@@ -3,7 +3,7 @@
#include <torrent/utils/scheduler.h>
#include "frame.h"
#include "display/frame.h"
namespace display {
+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) {
char buffer[last - first];
char* bufferLast = copy_string(buffer, buffer + (last - first), target);
auto buffer = std::make_unique<char[]>(last - first);
char* bufferLast = copy_string(buffer.get(), buffer.get() + (last - first), target);
first = rak::transform_hex(buffer, bufferLast, first, last);
first = rak::transform_hex(buffer.get(), bufferLast, first, last);
} else if (m_flags & flag_escape_html) {
char buffer[last - first];
char* bufferLast = copy_string(buffer, buffer + (last - first), target);
auto buffer = std::make_unique<char[]>(last - first);
char* bufferLast = copy_string(buffer.get(), buffer.get() + (last - first), target);
first = rak::copy_escape_html(buffer, bufferLast, first, last);
first = rak::copy_escape_html(buffer.get(), bufferLast, first, last);
} else {
first = copy_string(first, last, target);
+27 -18
View File
@@ -6,7 +6,6 @@
#include <cstdio>
#include <sstream>
#include <iomanip>
#include <rak/socket_address.h>
#include <torrent/exceptions.h>
#include <torrent/connection_manager.h>
#include <torrent/rate.h>
@@ -17,6 +16,8 @@
#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/socket_address.h>
#include <torrent/peer/client_info.h>
#include "control.h"
@@ -29,7 +30,7 @@
namespace display {
char*
print_string(char* first, char* last, char* str) {
print_string(char* first, char* last, const char* str) {
if (first == last)
return first;
@@ -78,17 +79,9 @@ 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_address(first, last, rak::socket_address::cast_from(sa));
return print_string(first, last, torrent::sa_addr_str(sa).c_str());
}
char*
@@ -381,21 +374,37 @@ print_status_info(char* first, char* last) {
first = print_status_throttle_rate(first, last, false, throttle_down_names, global_downrate);
first = print_buffer(first, last, " KB]");
first = print_buffer(first, last, " [Port: %i]", (unsigned int)torrent::runtime::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 (!rak::socket_address::cast_from(torrent::connection_manager()->local_address())->is_address_any()) {
if (!torrent::sa_is_any(local_address.get())) {
first = print_buffer(first, last, " [Local ");
first = print_address(first, last, torrent::connection_manager()->local_address());
first = print_address(first, last, local_address.get());
first = print_buffer(first, last, "]");
}
if (first > last)
throw torrent::internal_error("print_status_info(...) wrote past end of the buffer.");
if (!rak::socket_address::cast_from(torrent::connection_manager()->bind_address())->is_address_any()) {
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) {
first = print_buffer(first, last, " [Bind ");
first = print_address(first, last, torrent::connection_manager()->bind_address());
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_buffer(first, last, "]");
}
@@ -413,8 +422,8 @@ 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()->active(),
torrent::net_thread::http_stack()->max_active());
torrent::net_thread::http_stack()->size(),
torrent::net_thread::http_stack()->max_total_connections());
first = print_buffer(first, last, " [S %i/%i/%i]",
torrent::total_handshakes(),
-2
View File
@@ -31,8 +31,6 @@ Window::Window(Canvas* canvas, int flags, extent_type min_width, extent_type min
Window::~Window() {
if (is_active())
m_slot_unschedule(this);
delete m_canvas;
}
void
+1 -1
View File
@@ -89,7 +89,7 @@ protected:
static SlotWindow m_slot_unschedule;
static Slot m_slot_adjust;
Canvas* m_canvas;
std::unique_ptr<Canvas> m_canvas;
int m_flags;
-34
View File
@@ -1,37 +1,3 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
#include "config.h"
#include "canvas.h"
-34
View File
@@ -1,37 +1,3 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
#ifndef RTORRENT_DISPLAY_WINDOW_INPUT_H
#define RTORRENT_DISPLAY_WINDOW_INPUT_H
+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;
std::string ip_address = rak::socket_address::cast_from(p->address())->address_str();
auto ip_address = torrent::sa_addr_str(p->address());
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",
+22 -1
View File
@@ -2,7 +2,28 @@
#include "globals.h"
#include <torrent/exceptions.h>
rpc::ip_table_list ip_tables;
Control* control{};
ThreadWorker* worker_thread{};
std::string
expand_path(const std::string& path) {
if (path.empty())
return std::string();
if (path[0] == '~') {
if (path.size() < 2 || path[1] != '/')
throw torrent::input_error("Could not expand ~ in session path, only ~/<path> is supported.");
const char* home = std::getenv("HOME");
if (home == nullptr || *home == '\0')
throw torrent::input_error("Could not expand ~ in session path, HOME environment variable not set.");
return home + path.substr(1);
}
return path;
}
+43 -4
View File
@@ -1,14 +1,53 @@
#ifndef TORRENT_GLOBALS_H
#define TORRENT_GLOBALS_H
#include "thread_worker.h"
#include <torrent/common.h>
#include "rpc/ip_table_list.h"
class Control;
extern rpc::ip_table_list ip_tables;
extern rpc::ip_table_list ip_tables;
extern Control* control;
extern Control* control;
extern ThreadWorker* worker_thread;
std::string expand_path(const std::string& path);
namespace rpc {
class SCgi;
}
namespace session {
class SessionManager;
}
namespace scgi_thread {
torrent::utils::Thread* thread();
std::thread::id thread_id();
void callback(void* target, std::function<void ()>&& fn);
void cancel_callback(void* target);
void cancel_callback_and_wait(void* target);
rpc::SCgi* scgi();
void set_scgi(rpc::SCgi* scgi);
void set_rpc_log(const std::string& filename);
} // namespace torrent::scgi_thread
namespace session_thread {
torrent::utils::Thread* thread();
std::thread::id thread_id();
void callback(void* target, std::function<void ()>&& fn);
void cancel_callback(void* target);
void cancel_callback_and_wait(void* target);
session::SessionManager* manager();
std::string session_path();
} // namespace torrent::session_thread
#endif
+2 -2
View File
@@ -7,13 +7,13 @@
namespace input {
void
InputEvent::insert(torrent::Poll* p) {
InputEvent::insert(torrent::net::Poll* p) {
p->open(this);
p->insert_read(this);
}
void
InputEvent::remove(torrent::Poll* p) {
InputEvent::remove(torrent::net::Poll* p) {
p->remove_read(this);
p->close(this);
}
+8 -6
View File
@@ -4,7 +4,7 @@
#include <functional>
#include <torrent/event.h>
#include <torrent/poll.h>
#include <torrent/net/poll.h>
namespace input {
@@ -14,12 +14,14 @@ public:
InputEvent(int fd) { m_fileDesc = fd; }
void insert(torrent::Poll* p);
void remove(torrent::Poll* p);
const char* type_name() const override { return "input"; }
void event_read();
void event_write();
void event_error();
void insert(torrent::net::Poll* p);
void remove(torrent::net::Poll* p);
void event_read() override;
void event_write() override;
void event_error() override;
void slot_pressed(slot_int s) { m_slotPressed = s; }
+1 -36
View File
@@ -1,42 +1,7 @@
// 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 <functional>
#include <rak/algorithm.h>
#include <rak/path.h>
#include <dirent.h>
#include <sys/stat.h>
@@ -73,7 +38,7 @@ PathInput::receive_do_complete() {
size_type dirEnd = find_last_delim();
utils::Directory dir(dirEnd != 0 ? str().substr(0, dirEnd) : "./");
if (!dir.update(utils::Directory::update_sort | utils::Directory::update_hide_dot) || dir.empty()) {
mark_dirty();
+96 -74
View File
@@ -1,7 +1,5 @@
#include "config.h"
#define __STDC_FORMAT_MACROS
#include <cstdlib>
#include <iostream>
#include <sstream>
@@ -12,9 +10,9 @@
#include <torrent/torrent.h>
#include <torrent/exceptions.h>
#include <torrent/data/chunk_utils.h>
#include <torrent/net/fd.h>
#include <torrent/utils/chrono.h>
#include <torrent/utils/log.h>
#include <rak/error_number.h>
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
@@ -23,17 +21,19 @@
#include "core/dht_manager.h"
#include "core/download.h"
#include "core/download_factory.h"
#include "core/download_store.h"
#include "core/manager.h"
#include "display/canvas.h"
#include "display/window.h"
#include "display/manager.h"
#include "input/bindings.h"
#include "ui/root.h"
#include "rpc/command_scheduler.h"
#include "rpc/command_scheduler_item.h"
#include "rpc/parse_commands.h"
#include "scgi/thread_scgi.h"
#include "session/download_storer.h"
#include "session/thread_session.h"
#include "session/session_manager.h"
#include "ui/root.h"
#include "utils/directory.h"
#include "control.h"
@@ -42,8 +42,6 @@
#include "signal_handler.h"
#include "option_parser.h"
#include "thread_worker.h"
#define LT_LOG(log_fmt, ...) \
lt_log_print(torrent::LOG_SYSTEM, "system: " log_fmt, __VA_ARGS__);
@@ -114,7 +112,7 @@ initialize_rpc_slots() {
void
load_session_torrents() {
utils::Directory entries = control->core()->download_store()->get_formated_entries();
utils::Directory entries = session::DownloadStorer::get_formated_entries(session_thread::manager()->path());
for (const auto& entry : entries) {
// We don't really support session torrents that are links. These
@@ -216,8 +214,8 @@ main(int argc, char** argv) {
torrent::initialize();
torrent::set_main_thread_slots(std::bind(&client_perform));
worker_thread = new ThreadWorker();
worker_thread->init_thread();
scgi::ThreadScgi::create_thread();
session::ThreadSession::create_thread();
// Initialize option handlers after libtorrent to ensure
// torrent::ConnectionManager* are valid etc.
@@ -281,7 +279,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 'group2.view' as constant, so that we can't
// Allow setting 'group.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.
@@ -352,72 +350,78 @@ 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_GENERIC("upload_rate", "throttle.global_up.max_rate.set_kb");
CMD2_REDIRECT_GENERIC("download_rate", "throttle.global_down.max_rate.set_kb");
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("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("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("encryption", "protocol.encryption.set");
CMD2_REDIRECT_GENERIC("encoding_list", "encoding.add");
CMD2_REDIRECT("encryption", "protocol.encryption.set");
CMD2_REDIRECT("encoding_list", "encoding.add");
CMD2_REDIRECT_GENERIC("connection_leech", "protocol.connection.leech.set");
CMD2_REDIRECT_GENERIC("connection_seed", "protocol.connection.seed.set");
CMD2_REDIRECT("connection_leech", "protocol.connection.leech.set");
CMD2_REDIRECT("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_GENERIC("max_memory_usage", "pieces.memory.max.set");
CMD2_REDIRECT("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_GENERIC("dht", "dht.mode.set");
CMD2_REDIRECT_GENERIC("dht_port", "dht.port.set");
CMD2_REDIRECT("dht", "dht.mode.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_GENERIC("directory", "directory.default.set");
CMD2_REDIRECT_GENERIC("session", "session.path.set");
CMD2_REDIRECT("directory", "directory.default.set");
CMD2_REDIRECT("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_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("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 ("torrent_list_layout", "ui.torrent_list.layout.set");
CMD2_REDIRECT("torrent_list_layout", "ui.torrent_list.layout.set");
// Deprecate:
CMD2_VAR_STRING("dht.throttle.name", "deprecated");
CMD2_REDIRECT("network.http.max_open", "network.http.max_total_connections");
CMD2_REDIRECT("network.http.max_open.set", "network.http.max_total_connections.set");
// Deprecated commands. Don't use these anymore.
//
@@ -425,22 +429,35 @@ 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_GENERIC("execute", "execute2");
// CMD2_REDIRECT("execute", "execute2");
// CMD2_REDIRECT_GENERIC("schedule", "schedule2");
// CMD2_REDIRECT_GENERIC("schedule_remove", "schedule_remove2");
// CMD2_REDIRECT("schedule", "schedule2");
// CMD2_REDIRECT("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_GENERIC_NO_EXPORT("execute", "execute2");
// CMD2_REDIRECT_NO_EXPORT("execute", "execute2");
// CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule", "schedule2");
// CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule_remove", "schedule_remove2");
// CMD2_REDIRECT_NO_EXPORT("schedule", "schedule2");
// CMD2_REDIRECT_NO_EXPORT("schedule_remove", "schedule_remove2");
// }
// if (rpc::call_command_value("method.use_deprecated") == 1) {
// }
{
auto fd = torrent::fd_open_family(torrent::fd_flag_stream, AF_INET6);
if (fd == -1) {
if (errno == EAFNOSUPPORT) {
lt_log_print(torrent::LOG_WARN, "disabling ipv6 support, not available on system");
rpc::call_command_set_value("network.block.ipv6.set", true);
}
} else {
torrent::fd_close(fd);
}
}
int firstArg = parse_options(argc, argv);
if (OptionParser::has_flag('n', argc, argv)) {
@@ -480,8 +497,6 @@ main(int argc, char** argv) {
control->display()->adjust_layout();
control->display()->receive_update();
worker_thread->start_thread();
rpc::commands.call_catch("event.system.startup_done", rpc::make_target(), "startup_done", "System startup_done event action failed: ");
torrent::utils::Thread::self()->event_loop();
@@ -498,6 +513,8 @@ main(int argc, char** argv) {
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) {
@@ -506,13 +523,18 @@ main(int argc, char** argv) {
std::cout << "rtorrent: caught" << typeid(e).name() << " : " << e.what() << std::endl;
lt_log_print(torrent::LOG_CRITICAL, "Caught exception: '%s'.", e.what());
torrent::log_cleanup();
return -1;
}
torrent::log_cleanup();
delete control;
delete worker_thread;
control = nullptr;
scgi::ThreadScgi::destroy_thread();
session::ThreadSession::destroy_thread();
torrent::log_cleanup();
return 0;
}
@@ -541,7 +563,7 @@ handle_sigbus(int signum, siginfo_t* sa, [[maybe_unused]] void* ptr) {
#else
output << "Stack dump not enabled." << std::endl;
#endif
output << std::endl << "Error: " << rak::error_number(sa->si_errno).c_str() << std::endl;
output << std::endl << "Error: " << std::strerror(sa->si_errno) << std::endl;
const char* signal_reason;
+2 -3
View File
@@ -53,9 +53,8 @@ public:
static const int flag_is_redirect = 0x20;
static const int flag_has_redirects = 0x40;
static const int flag_no_target = 0x100;
static const int flag_file_target = 0x200;
static const int flag_tracker_target = 0x400;
static const int flag_file_target = 0x100;
static const int flag_tracker_target = 0x200;
CommandMap() = default;
-1
View File
@@ -5,7 +5,6 @@
#include <fcntl.h>
#include <string>
#include <unistd.h>
#include <rak/path.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <torrent/utils/thread.h>
+7 -9
View File
@@ -122,18 +122,16 @@ jsonrpc_call_command(const std::string& method, const json& params) {
std::function<void()> deleter = []() {};
utils::scope_guard guard([&deleter]() { deleter(); });
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("");
// 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);
+9 -4
View File
@@ -1,5 +1,6 @@
#include "config.h"
#include <cerrno>
#include <fstream>
#include <string>
#include <sys/stat.h>
@@ -10,8 +11,6 @@
#include <lua.hpp>
#endif
#include <rak/error_number.h>
#include <rak/path.h>
#include <rak/string_manip.h>
#include <torrent/object.h>
@@ -266,8 +265,10 @@ object_to_lua(lua_State* l_state, torrent::Object const& object) {
lua_createtable(l_state, 0, static_cast<int>(object_map.size()));
int table_idx = lua_gettop(l_state);
for (const auto& itr : object_map) {
object_to_lua(l_state, itr.second);
// lua_rawset requires the value to be on top of the stack, with the
// key below it.
lua_pushlstring(l_state, itr.first.c_str(), itr.first.size());
object_to_lua(l_state, itr.second);
lua_rawset(l_state, table_idx);
}
break;
@@ -417,12 +418,16 @@ execute_lua(LuaEngine* engine, rpc::target_type target_type, torrent::Object con
}
#else
torrent::Object
execute_lua(LuaEngine* engine, torrent::Object const& rawArgs, int flags) {
execute_lua([[maybe_unused]] LuaEngine* engine, [[maybe_unused]] torrent::Object const& rawArgs, [[maybe_unused]] int flags) {
throw torrent::input_error("Lua support not enabled");
return torrent::Object();
}
LuaEngine::LuaEngine() {}
LuaEngine::~LuaEngine() {}
#endif
} // namespace rpc
+28 -59
View File
@@ -1,45 +1,11 @@
// 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 <cstring>
#include <cstdio>
#include <locale>
#include <rak/path.h>
#include <torrent/exceptions.h>
#include "globals.h"
#include "parse.h"
namespace rpc {
@@ -90,7 +56,7 @@ parse_string(const char* first, const char* last, std::string* dest, bool (*deli
dest->push_back(*first++);
}
return first;
}
}
@@ -100,7 +66,7 @@ parse_whole_string(const char* first, const char* last, std::string* dest) {
first = parse_skip_wspace(first, last);
first = parse_string(first, last, dest);
first = parse_skip_wspace(first, last);
if (first != last)
throw torrent::input_error("Junk at end of input.");
}
@@ -175,7 +141,7 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
*dest = torrent::Object::create_list();
first = parse_list(first + 1, last, dest, &parse_is_delim_block);
first = parse_skip_wspace(first, last);
if (first == last || *first != '}')
throw torrent::input_error("Could not find closing '}'.");
@@ -238,7 +204,7 @@ parse_list(const char* first, const char* last, torrent::Object* dest, bool (*de
first = parse_skip_wspace(first, last);
dest->as_list().push_back(tmp);
if (first == last || !parse_is_seperator(*first))
break;
@@ -284,12 +250,12 @@ convert_to_string(const torrent::Object& rawSrc) {
if (src.as_raw_bencode().is_raw_string())
return src.as_raw_bencode().as_raw_string().as_string();
if (src.as_raw_bencode().is_value())
return src.as_raw_bencode().as_value_string();
default: throw torrent::input_error("Not a string.");
}
}
}
std::string
@@ -341,9 +307,9 @@ convert_list_to_command(torrent::Object::list_const_iterator first,
if (first == last)
throw torrent::input_error("Too few arguments.");
std::string dest = (first++)->as_string();
std::string::size_type quoteItr = dest.find('=');
auto dest = (first++)->as_string();
auto quoteItr = dest.find('=');
if (quoteItr == std::string::npos)
throw torrent::input_error("Could not find '=' in command.");
@@ -405,12 +371,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();
char buffer[str.size() + 1];
std::memcpy(buffer, str.data(), str.size());
auto buffer = std::make_unique<char[]>(str.size() + 1);
std::memcpy(buffer.get(), str.data(), str.size());
buffer[str.size()] = '\0';
return parse_skip_wspace(parse_value(buffer, value, base, unit), buffer + str.size())
== buffer + str.size();
return parse_skip_wspace(parse_value(buffer.get(), value, base, unit), buffer.get() + str.size())
== buffer.get() + str.size();
}
case torrent::Object::TYPE_NONE:
*value = 0;
@@ -419,7 +385,7 @@ convert_to_value_nothrow(const torrent::Object& src, int64_t* value, int base, i
default:
return false;
}
return true;
}
@@ -430,20 +396,23 @@ print_object(char* first, char* last, const torrent::Object* src, int flags) {
{
const std::string& str = src->as_string();
if (first == last)
return first;
if ((flags & print_expand_tilde) && *str.c_str() == '~') {
return rak::path_expand(str.c_str(), first, last);
auto expanded = expand_path(str);
} else {
if (first == last)
return first;
size_t n = std::min<size_t>(str.size(), std::distance(first, last) - 1);
std::memcpy(first, str.c_str(), n);
size_t n = std::min<size_t>(expanded.size(), std::distance(first, last) - 1);
std::memcpy(first, expanded.c_str(), n);
*(first += n) = '\0';
return first;
} else {
size_t n = std::min<size_t>(str.size(), std::distance(first, last) - 1);
std::memcpy(first, str.c_str(), n);
*(first += n) = '\0';
}
return first;
}
case torrent::Object::TYPE_VALUE:
@@ -480,7 +449,7 @@ print_object_std(std::string* dest, const torrent::Object* src, int flags) {
const std::string& str = src->as_string();
if ((flags & print_expand_tilde) && *str.c_str() == '~')
*dest += rak::path_expand(str);
*dest += expand_path(str);
else
*dest += str;
+4 -3
View File
@@ -4,9 +4,9 @@
#include <fstream>
#include <string>
#include <functional>
#include <rak/path.h>
#include <torrent/exceptions.h>
#include "globals.h"
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
#include "rpc/rpc_manager.h"
@@ -140,7 +140,7 @@ parse_command_multiple(target_type target, const char* first, const char* last)
bool
parse_command_file(const std::string& path) {
std::fstream file(rak::path_expand(path).c_str(), std::ios::in);
std::fstream file(expand_path(path).c_str(), std::ios::in);
if (!file.is_open())
return false;
@@ -156,9 +156,10 @@ parse_command_file(const std::string& path) {
if (file.gcount() == 0)
throw torrent::internal_error("parse_command_file(...) file.gcount() == 0.");
int lineLength = file.gcount() - 1;
// In case we are at the end of the file and the last character is
// not a line feed, we'll just increase the read character count so
// not a line feed, we'll just increase the read character count so
// that the last would also be included in option line.
if (file.eof() && file.get() != '\n')
lineLength++;
+3 -9
View File
@@ -15,24 +15,18 @@ ExecFile execFile;
void
RpcManager::object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* target, std::function<void()>* deleter) {
if (call_flags & CommandMap::flag_no_target)
return;
if (!obj.is_string()) {
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 (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;
+118 -58
View File
@@ -1,49 +1,56 @@
#include "config.h"
#include <algorithm>
#include <cassert>
#include <rak/error_number.h>
#include <rak/socket_address.h>
#include <unistd.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/poll.h>
#include <torrent/net/socket_address.h>
#include <torrent/runtime/socket_manager.h>
#include "control.h"
#include "globals.h"
#include "rpc/scgi_task.h"
#include "utils/socket_fd.h"
// TODO: Figure out why moving this to the top causes a build error.
#include "rpc/scgi.h"
namespace rpc {
SCgi::SCgi() {
std::generate(m_tasks.begin(), m_tasks.end(), []() { return std::make_unique<SCgiTask>(); });
m_current = m_tasks.begin();
}
SCgi::~SCgi() {
if (!get_fd().is_valid())
return;
for (SCgiTask* itr = m_task, *last = m_task + max_tasks; itr != last; ++itr)
if (itr->is_open())
itr->close();
deactivate();
torrent::connection_manager()->dec_socket_count();
get_fd().close();
get_fd().clear();
if (!m_path.empty())
::unlink(m_path.c_str());
assert(!is_open() && "SCgi::~SCgi() called while open");
}
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(rak::error_number::current().c_str()));
SCgi::open_port(sockaddr* sa, unsigned int length, bool dont_route) {
torrent::runtime::socket_manager()->open_event_or_throw(this, [&]() {
int fd = torrent::fd_open_family(torrent::fd_flag_stream | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address,
sa->sa_family);
open(sa, length);
if (fd == -1)
throw torrent::resource_error("Could not open socket for listening: " + std::string(std::strerror(errno)));
if (dont_route && !torrent::fd_set_dont_route(fd, true)) {
torrent::fd_close(fd);
throw torrent::resource_error("Could not set socket option IP_DONTROUTE: " + std::string(std::strerror(errno)));
}
set_file_descriptor(fd);
open(reinterpret_cast<sockaddr*>(sa), length);
});
torrent::connection_manager()->inc_socket_count();
}
void
@@ -51,75 +58,128 @@ SCgi::open_named(const std::string& filename) {
if (filename.empty() || filename.size() > 4096)
throw torrent::resource_error("Invalid filename length.");
char buffer[sizeof(sockaddr_un) + filename.size()];
sockaddr_un* sa = reinterpret_cast<sockaddr_un*>(buffer);
auto buffer = std::make_unique<char[]>(sizeof(sockaddr_un) + filename.size() + 1);
#ifdef __sun__
sa->sun_family = AF_UNIX;
#else
sockaddr_un* sa = reinterpret_cast<sockaddr_un*>(buffer.get());
sa->sun_family = AF_LOCAL;
#endif
std::memcpy(sa->sun_path, filename.c_str(), filename.size() + 1);
if (!get_fd().open_local())
throw torrent::resource_error("Could not open socket for listening.");
torrent::runtime::socket_manager()->open_event_or_throw(this, [&]() {
int fd = torrent::fd_open_local(torrent::fd_flag_stream | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address);
if (fd == -1)
throw torrent::resource_error("Could not open socket for listening: " + std::string(std::strerror(errno)));
set_file_descriptor(fd);
open(reinterpret_cast<sockaddr*>(sa), offsetof(struct sockaddr_un, sun_path) + filename.size() + 1);
});
torrent::connection_manager()->inc_socket_count();
open(sa, offsetof(struct sockaddr_un, sun_path) + filename.size() + 1);
m_path = filename;
}
void
SCgi::open(void* sa, unsigned int length) {
SCgi::open(sockaddr* sa, unsigned int length) {
try {
if (!get_fd().set_nonblock() ||
!get_fd().set_reuse_address(true) ||
!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(rak::error_number::current().c_str()));
if (::bind(file_descriptor(), sa, length) == -1)
throw torrent::resource_error("Could not bind socket for listening: " + std::string(std::strerror(errno)));
torrent::connection_manager()->inc_socket_count();
if (!torrent::fd_listen(file_descriptor(), max_tasks))
throw torrent::resource_error("Could not prepare socket for listening: " + std::string(std::strerror(errno)));
} catch (torrent::resource_error& e) {
get_fd().close();
get_fd().clear();
throw e;
torrent::fd_close(file_descriptor());
set_file_descriptor(-1);
throw;
}
}
// TODO: Verify this is run in correct thread, also only ever call poll methods from thread_self.
void
SCgi::activate() {
assert(std::this_thread::get_id() == worker_thread->thread_id() && "SCgi::activate() must be called from the worker thread.");
assert(torrent::this_thread::thread() == scgi_thread::thread());
torrent::this_thread::poll()->open(this);
torrent::this_thread::poll()->insert_read(this);
torrent::this_thread::poll()->insert_error(this);
}
// TODO: This should close the fd to avoid reuse.
void
SCgi::deactivate() {
assert(std::this_thread::get_id() == worker_thread->thread_id() && "SCgi::deactivate() must be called from the worker thread.");
SCgi::stop() {
assert(torrent::this_thread::thread() == scgi_thread::thread());
torrent::this_thread::poll()->remove_and_close(this);
if (!is_open())
return;
for (auto& itr : m_tasks) {
if (itr->is_open())
itr->close();
}
torrent::runtime::socket_manager()->close_event_or_throw(this, [this]() {
torrent::this_thread::poll()->remove_and_close(this);
torrent::fd_close(file_descriptor());
set_file_descriptor(-1);
});
torrent::connection_manager()->dec_socket_count();
if (!m_path.empty())
::unlink(m_path.c_str());
}
void
SCgi::event_read() {
rak::socket_address sa;
utils::SocketFd fd;
if (m_current < m_tasks.begin() || m_current >= m_tasks.end())
throw torrent::internal_error("SCgi::event_read() m_current is out of bounds");
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));
while (true) {
// TODO: Optimize this by keeping track of count.
auto prev = m_current;
m_current = std::find_if(m_current + 1, m_tasks.end(), [](const auto& task) { return !task->is_open(); });
if (m_current == m_tasks.end())
m_current = std::find_if(m_tasks.begin(), prev, [](const auto& task) { return !task->is_open(); });
if (m_current == prev) {
// TODO: Currently just close, although we should remove ourselves from read.
int fd = torrent::fd_accept(file_descriptor());
if (fd != -1)
torrent::fd_close(fd);
if (task == m_task + max_tasks) {
fd.close();
continue;
}
task->open(this, fd.get_fd());
auto open_func = [this, task = m_current->get()]() {
int fd = torrent::fd_accept(file_descriptor());
if (fd == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
return;
// Force a new event_read() call just to be sure we don't enter an infinite loop.
if (errno == ECONNABORTED)
return;
throw torrent::resource_error("Listener port accept() failed: " + std::string(std::strerror(errno)));
}
task->open(this, fd);
};
auto cleanup_func = [task = m_current->get()]() {
task->cancel_open();
};
bool result = torrent::runtime::socket_manager()->open_event_or_cleanup(m_current->get(), open_func, cleanup_func);
if (!result)
break;
}
}
+12 -11
View File
@@ -1,15 +1,12 @@
#ifndef RTORRENT_RPC_SCGI_H
#define RTORRENT_RPC_SCGI_H
#include <array>
#include <functional>
#include <memory>
#include <torrent/event.h>
#include "rpc/scgi_task.h"
#include "utils/socket_fd.h"
namespace utils {
class SocketFd;
}
namespace rpc {
@@ -17,15 +14,17 @@ class SCgi : public torrent::Event {
public:
static const int max_tasks = 100;
SCgi();
~SCgi() override;
const char* type_name() const override { return "scgi"; }
void open_port(void* sa, unsigned int length, bool dontRoute);
void open_port(sockaddr* sa, unsigned int length, bool dont_route);
void open_named(const std::string& filename);
void activate();
void deactivate();
void stop();
const std::string& path() const { return m_path; }
@@ -36,14 +35,16 @@ public:
void event_write() override;
void event_error() override;
utils::SocketFd& get_fd() { return *reinterpret_cast<utils::SocketFd*>(&m_fileDesc); }
private:
void open(void* sa, unsigned int length);
using task_list = std::array<std::unique_ptr<SCgiTask>, max_tasks>;
void open(sockaddr* sa, unsigned int length);
std::string m_path;
int m_logFd{-1};
SCgiTask m_task[max_tasks];
task_list m_tasks;
task_list::iterator m_current;
};
}
+55 -46
View File
@@ -2,14 +2,16 @@
#include "rpc/scgi_task.h"
#include <rak/error_number.h>
#include <cstdio>
#include <unistd.h>
#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <torrent/exceptions.h>
#include <torrent/poll.h>
#include <torrent/torrent.h>
#include <torrent/net/fd.h>
#include <torrent/net/poll.h>
#include <torrent/runtime/socket_manager.h>
#include <torrent/utils/log.h>
#include <torrent/utils/thread.h>
@@ -17,49 +19,62 @@
#include "globals.h"
#include "scgi.h"
#include "rpc/parse_commands.h"
#include "utils/socket_fd.h"
namespace rpc {
void
SCgiTask::open(SCgi* parent, int fd) {
set_file_descriptor(fd);
m_buffer.reset(new char[default_buffer_size + 1]);
m_parent = parent;
m_fileDesc = fd;
m_buffer = new char[default_buffer_size + 1];
m_buffer_size = default_buffer_size;
m_position = m_buffer;
m_body = NULL;
m_position = m_buffer.get();
m_body = nullptr;
torrent::this_thread::poll()->open(this);
torrent::this_thread::poll()->insert_read(this);
torrent::this_thread::poll()->insert_error(this);
}
void
SCgiTask::cancel_open() {
if (!is_open())
return;
torrent::this_thread::poll()->remove_and_close(this);
torrent::fd_close(file_descriptor());
set_file_descriptor(-1);
};
void
SCgiTask::close() {
if (!get_fd().is_valid())
if (!is_open())
return;
torrent::main_thread::thread()->cancel_callback_and_wait(this);
torrent::utils::Thread::self()->cancel_callback(this);
torrent::this_thread::poll()->remove_and_close(this);
torrent::runtime::socket_manager()->close_event_or_throw(this, [this]() {
torrent::this_thread::poll()->remove_and_close(this);
get_fd().close();
get_fd().clear();
torrent::fd_close(file_descriptor());
set_file_descriptor(-1);
});
auto lock = std::lock_guard<std::mutex>(m_result_mutex);
delete[] m_buffer;
m_buffer = NULL;
m_buffer = nullptr;
}
void
SCgiTask::event_read() {
int bytes = ::recv(m_fileDesc, m_position, m_buffer_size - (m_position - m_buffer), 0);
int bytes = ::recv(m_fileDesc, m_position, m_buffer_size - (m_position - m_buffer.get()), 0);
if (bytes <= 0) {
if (bytes == 0 || !rak::error_number::current().is_blocked_momentary())
if (bytes == 0 || !(errno == EAGAIN || errno == EINTR))
close();
return;
@@ -74,14 +89,14 @@ SCgiTask::event_read() {
// receive all the data we need the first time.
char* current;
int header_size = strtol(m_buffer, &current, 0);
int header_size = strtol(m_buffer.get(), &current, 0);
if (current == m_position)
return;
// If the request doesn't start with an integer or if it didn't
// end in ':', then close the connection.
if (current == m_buffer || *current != ':' || header_size < 17 || header_size > max_header_size)
if (current == m_buffer.get() || *current != ':' || header_size < 17 || header_size > max_header_size)
goto event_read_failed;
if (std::distance(++current, m_position) < header_size + 1)
@@ -136,7 +151,7 @@ SCgiTask::event_read() {
goto event_read_failed;
m_body = current + 1;
header_size = std::distance(m_buffer, m_body);
header_size = std::distance(m_buffer.get(), m_body);
if (!detect_content_type(content_type))
goto event_read_failed;
@@ -147,19 +162,19 @@ SCgiTask::event_read() {
} else if ((unsigned int)content_length <= default_buffer_size) {
m_buffer_size = content_length;
std::memmove(m_buffer, m_body, std::distance(m_body, m_position));
m_position = m_buffer + std::distance(m_body, m_position);
m_body = m_buffer;
std::memmove(m_buffer.get(), m_body, std::distance(m_body, m_position));
m_position = m_buffer.get() + std::distance(m_body, m_position);
m_body = m_buffer.get();
} else {
realloc_buffer((m_buffer_size = content_length) + 1, m_body, std::distance(m_body, m_position));
m_position = m_buffer + std::distance(m_body, m_position);
m_body = m_buffer;
m_position = m_buffer.get() + std::distance(m_body, m_position);
m_body = m_buffer.get();
}
}
if ((unsigned int)std::distance(m_buffer, m_position) != m_buffer_size)
if ((unsigned int)std::distance(m_buffer.get(), m_position) != m_buffer_size)
return;
torrent::this_thread::poll()->remove_read(this);
@@ -169,13 +184,13 @@ SCgiTask::event_read() {
// Clean up logging, this is just plain ugly...
// write(m_logFd, "\n---\n", sizeof("\n---\n"));
result = write(m_parent->log_fd(), m_buffer, m_buffer_size);
result = write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n"));
result = ::write(m_parent->log_fd(), m_buffer.get(), m_buffer_size);
result = ::write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n"));
}
lt_log_print_dump(torrent::LOG_RPC_DUMP, m_body, m_buffer_size - std::distance(m_buffer, m_body), "scgi", "RPC read.", 0);
lt_log_print_dump(torrent::LOG_RPC_DUMP, m_body, m_buffer_size - std::distance(m_buffer.get(), m_body), "scgi", "RPC read.", 0);
receive_call(m_body, m_buffer_size - std::distance(m_buffer, m_body));
receive_call(m_body, m_buffer_size - std::distance(m_buffer.get(), m_body));
return;
event_read_failed:
@@ -185,16 +200,10 @@ event_read_failed:
void
SCgiTask::event_write() {
// Apple and Solaris do not support MSG_NOSIGNAL,
// so disable this fix until we find a better solution
#if defined(__APPLE__) || defined(__sun__)
int bytes = ::send(m_fileDesc, m_position, m_buffer_size, 0);
#else
int bytes = ::send(m_fileDesc, m_position, m_buffer_size, MSG_NOSIGNAL);
#endif
if (bytes == -1) {
if (!rak::error_number::current().is_blocked_momentary())
if (!(errno == EAGAIN || errno == EINTR))
close();
return;
@@ -249,11 +258,11 @@ SCgiTask::detect_content_type(const std::string& content_type) {
// If bufferSize is zero then memcpy won't do anything.
void
SCgiTask::realloc_buffer(uint32_t size, const char* buffer, uint32_t bufferSize) {
char* tmp = new char[size];
auto tmp = new char[size];
std::memcpy(tmp, buffer, bufferSize);
::free(m_buffer);
m_buffer = tmp;
m_buffer.reset(tmp);
}
void
@@ -265,7 +274,7 @@ SCgiTask::receive_call(const char* buffer, uint32_t length) {
auto result_callback = [this, scgi_thread](const char* b, uint32_t l) {
receive_write(b, l);
scgi_thread->callback_interrupt_pollling(this, [this]() {
scgi_thread->callback_interrupt_polling(this, [this]() {
// Only need to lock once here as a memory barrier.
m_result_mutex.lock();
m_result_mutex.unlock();
@@ -278,7 +287,7 @@ SCgiTask::receive_call(const char* buffer, uint32_t length) {
switch (content_type()) {
case rpc::SCgiTask::ContentType::JSON:
torrent::main_thread::thread()->callback_interrupt_pollling(this, [buffer, length, result_callback]() {
torrent::main_thread::thread()->callback_interrupt_polling(this, [buffer, length, result_callback]() {
rpc.process(RpcManager::RPCType::JSON, buffer, length,
[result_callback](const char* b, uint32_t l) {
result_callback(b, l);
@@ -288,7 +297,7 @@ SCgiTask::receive_call(const char* buffer, uint32_t length) {
break;
case rpc::SCgiTask::ContentType::XML:
torrent::main_thread::thread()->callback_interrupt_pollling(this, [buffer, length, result_callback]() {
torrent::main_thread::thread()->callback_interrupt_polling(this, [buffer, length, result_callback]() {
rpc.process(RpcManager::RPCType::XML, buffer, length,
[result_callback](const char* b, uint32_t l) {
result_callback(b, l);
@@ -318,20 +327,20 @@ SCgiTask::receive_write(const char* buffer, uint32_t length) {
: "Status: 200 OK\r\nContent-Type: text/xml\r\nContent-Length: %i\r\n\r\n";
// Who ever bothers to check the return value?
int headerSize = snprintf(m_buffer, m_buffer_size, header, length);
int headerSize = snprintf(m_buffer.get(), m_buffer_size, header, length);
m_position = m_buffer;
m_position = m_buffer.get();
m_buffer_size = length + headerSize;
std::memcpy(m_buffer + headerSize, buffer, length);
std::memcpy(m_buffer.get() + headerSize, buffer, length);
if (m_parent->log_fd() >= 0) {
[[maybe_unused]] int result;
result = write(m_parent->log_fd(), m_buffer, m_buffer_size);
result = write(m_parent->log_fd(), m_buffer.get(), m_buffer_size);
result = write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n"));
}
lt_log_print_dump(torrent::LOG_RPC_DUMP, m_buffer, m_buffer_size, "scgi", "RPC write.", 0);
lt_log_print_dump(torrent::LOG_RPC_DUMP, m_buffer.get(), m_buffer_size, "scgi", "RPC write.", 0);
}
} // namespace rpc
+11 -13
View File
@@ -5,10 +5,6 @@
#include <mutex>
#include <torrent/event.h>
namespace utils {
class SocketFd;
}
namespace rpc {
class SCgi;
@@ -23,19 +19,21 @@ public:
SCgiTask() { m_fileDesc = -1; }
const char* type_name() const override { return "scgi-task"; }
bool is_open() const { return m_fileDesc != -1; }
bool is_available() const { return m_fileDesc == -1; }
void open(SCgi* parent, int fd);
void cancel_open();
void close();
ContentType content_type() const { return m_content_type; }
virtual void event_read();
virtual void event_write();
virtual void event_error();
utils::SocketFd& get_fd() { return *reinterpret_cast<utils::SocketFd*>(&m_fileDesc); }
void event_read() override;
void event_write() override;
void event_error() override;
private:
bool detect_content_type(const std::string& content_type);
@@ -44,13 +42,13 @@ private:
void receive_call(const char* buffer, uint32_t length);
void receive_write(const char* buffer, uint32_t length);
SCgi* m_parent;
SCgi* m_parent{};
std::mutex m_result_mutex;
char* m_buffer{nullptr};
char* m_position{nullptr};
char* m_body{nullptr};
std::unique_ptr<char[]> m_buffer;
char* m_position{};
char* m_body{};
unsigned int m_buffer_size{0};
+17
View File
@@ -4,10 +4,27 @@
#include "parse_commands.h"
#include <cstring>
#include <torrent/exceptions.h>
namespace rpc {
std::vector<std::unique_ptr<const char>> XmlRpc::m_command_names;
const char*
XmlRpc::store_command_name(const char* name) {
if (::strnlen(name, 8192) == 8192)
throw torrent::input_error("XMLRPC command name too long, limit is 8192 characters.");
for (const auto& itr : m_command_names) {
if (::strcmp(itr.get(), name) == 0)
return itr.get();
}
m_command_names.push_back(std::unique_ptr<const char>(::strdup(name)));
return m_command_names.back().get();
}
#ifndef HAVE_XMLRPC_C
#ifndef HAVE_XMLRPC_TINYXML2
+4 -1
View File
@@ -59,6 +59,10 @@ public:
void set_size_limit(uint64_t size);
private:
static const char* store_command_name(const char* name);
static std::vector<std::unique_ptr<const char>> m_command_names;
slot_download m_slotFindDownload;
slot_file m_slotFindFile;
slot_tracker m_slotFindTracker;
@@ -73,7 +77,6 @@ private:
// Only used by tinyxml2
bool m_isValid;
uint64_t m_sizeLimit{SCgiTask::max_content_size};
};
}
+44 -38
View File
@@ -8,9 +8,9 @@
#include <cctype>
#include <string>
#include <stdlib.h>
#include <rak/string_manip.h>
#include <torrent/object.h>
#include <torrent/exceptions.h>
#include <torrent/utils/string_manip.h>
#include <xmlrpc-c/server.h>
#include "rpc_manager.h"
@@ -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->first == XmlRpc::call_download &&
if (target != nullptr && 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
@@ -282,24 +282,20 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
// The versions that support I8 do implicit utf-8 validation.
xmlrpc_value* result = xmlrpc_string_new(env, object.as_string().c_str());
#else
xmlrpc_value* result{};
// In older versions, xmlrpc-c doesn't validate the utf-8 encoding itself.
xmlrpc_validate_utf8(env, object.as_string().c_str(), object.as_string().length());
xmlrpc_value* result = env->fault_occurred ? NULL : xmlrpc_string_new(env, object.as_string().c_str());
if (!env->fault_occurred)
result = xmlrpc_string_new(env, object.as_string().c_str());
#endif
if (env->fault_occurred) {
xmlrpc_env_clean(env);
xmlrpc_env_init(env);
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;
*dst = 0;
result = xmlrpc_string_new(env, buffer);
return xmlrpc_string_new(env, torrent::utils::string_with_escape_codes(object.as_string()).c_str());
}
return result;
@@ -361,10 +357,12 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
xmlrpc_value*
xmlrpc_call_command(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo) {
CommandMap::iterator itr = commands.find((const char*)voidServerInfo);
auto server_info = static_cast<const char*>(voidServerInfo);
CommandMap::iterator itr = commands.find(server_info);
if (itr == commands.end()) {
xmlrpc_env_set_fault(env, XMLRPC_PARSE_ERROR, ("Command \"" + std::string((const char*)voidServerInfo) + "\" does not exist.").c_str());
xmlrpc_env_set_fault(env, XMLRPC_PARSE_ERROR, ("Command \"" + std::string(server_info) + "\" does not exist.").c_str());
return NULL;
}
@@ -375,9 +373,7 @@ 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_no_target)
xmlrpc_to_object(env, args, XmlRpc::call_generic, &target, &deleter).swap(object);
else if (itr->second.m_flags & CommandMap::flag_file_target)
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);
@@ -399,6 +395,11 @@ xmlrpc_call_command(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo) {
}
}
bool
XmlRpc::is_valid() const {
return m_env != NULL;
}
void
XmlRpc::initialize() {
#ifndef XMLRPC_HAVE_I8
@@ -423,34 +424,42 @@ XmlRpc::cleanup() {
bool
XmlRpc::process(const char* inBuffer, uint32_t length, slot_write slotWrite) {
xmlrpc_env localEnv;
xmlrpc_env_init(&localEnv);
xmlrpc_env local_env;
xmlrpc_env_init(&local_env);
xmlrpc_mem_block* memblock = xmlrpc_registry_process_call(&localEnv, (xmlrpc_registry*)m_registry, NULL, inBuffer, length);
xmlrpc_mem_block* memblock = xmlrpc_registry_process_call(&local_env, (xmlrpc_registry*)m_registry, NULL, inBuffer, length);
if (localEnv.fault_occurred && localEnv.fault_code == XMLRPC_INTERNAL_ERROR)
if (local_env.fault_occurred && local_env.fault_code == XMLRPC_INTERNAL_ERROR)
throw torrent::internal_error("Internal error in XMLRPC.");
bool result = slotWrite((const char*)xmlrpc_mem_block_contents(memblock),
xmlrpc_mem_block_size(memblock));
xmlrpc_mem_block_free(memblock);
xmlrpc_env_clean(&localEnv);
xmlrpc_env_clean(&local_env);
return result;
}
void
XmlRpc::insert_command(const char* name, const char* parm, const char* doc) {
xmlrpc_env localEnv;
xmlrpc_env_init(&localEnv);
xmlrpc_env local_env;
xmlrpc_env_init(&local_env);
xmlrpc_registry_add_method_w_doc(&localEnv, (xmlrpc_registry*)m_registry, NULL, name,
&xmlrpc_call_command, const_cast<char*>(name), parm, doc);
auto stored_name = store_command_name(name);
if (localEnv.fault_occurred)
xmlrpc_registry_add_method_w_doc(&local_env,
(xmlrpc_registry*)m_registry,
nullptr,
stored_name,
&xmlrpc_call_command,
(void*)stored_name,
parm,
doc);
if (local_env.fault_occurred)
throw torrent::internal_error("Fault occured while inserting xmlrpc call.");
xmlrpc_env_clean(&localEnv);
xmlrpc_env_clean(&local_env);
}
void
@@ -458,8 +467,8 @@ XmlRpc::set_dialect(int dialect) {
if (!is_valid())
throw torrent::input_error("Cannot select XMLRPC dialect before it is initialized.");
xmlrpc_env localEnv;
xmlrpc_env_init(&localEnv);
xmlrpc_env local_env;
xmlrpc_env_init(&local_env);
switch (dialect) {
case dialect_generic:
@@ -467,25 +476,25 @@ XmlRpc::set_dialect(int dialect) {
#ifdef XMLRPC_HAVE_I8
case dialect_i8:
xmlrpc_registry_set_dialect(&localEnv, (xmlrpc_registry*)m_registry, xmlrpc_dialect_i8);
xmlrpc_registry_set_dialect(&local_env, (xmlrpc_registry*)m_registry, xmlrpc_dialect_i8);
break;
case dialect_apache:
xmlrpc_registry_set_dialect(&localEnv, (xmlrpc_registry*)m_registry, xmlrpc_dialect_apache);
xmlrpc_registry_set_dialect(&local_env, (xmlrpc_registry*)m_registry, xmlrpc_dialect_apache);
break;
#endif
default:
xmlrpc_env_clean(&localEnv);
xmlrpc_env_clean(&local_env);
throw torrent::input_error("Unsupported XMLRPC dialect selected.");
}
if (localEnv.fault_occurred) {
xmlrpc_env_clean(&localEnv);
if (local_env.fault_occurred) {
xmlrpc_env_clean(&local_env);
throw torrent::input_error("Unsupported XMLRPC dialect selected.");
}
xmlrpc_env_clean(&localEnv);
xmlrpc_env_clean(&local_env);
m_dialect = dialect;
}
@@ -502,9 +511,6 @@ XmlRpc::set_size_limit(uint64_t size) {
xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, size);
}
bool
XmlRpc::is_valid() const { return m_env != NULL; }
} // namespace rpc
#endif
+6 -10
View File
@@ -204,12 +204,10 @@ execute_command(std::string method_name, const tinyxml2::XMLElement* params_elem
const auto* child = params_element->FirstChildElement("param");
if (child != nullptr) {
if (!(cmd_itr->second.m_flags & CommandMap::flag_no_target)) {
std::function<void()> deleter = []() {};
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) {
@@ -223,12 +221,10 @@ execute_command(std::string method_name, const tinyxml2::XMLElement* params_elem
const auto* child = params_element->FirstChildElement("data")->FirstChildElement("value");
if (child != nullptr) {
if (!(cmd_itr->second.m_flags & CommandMap::flag_no_target)) {
std::function<void()> deleter = []() {};
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));
+141
View File
@@ -0,0 +1,141 @@
#include "config.h"
#include "scgi/thread_scgi.h"
#include <fcntl.h>
#include <unistd.h>
#include <torrent/exceptions.h>
#include <torrent/utils/log.h>
#include "globals.h"
#include "rpc/scgi.h"
namespace scgi {
class ThreadScgiInternal {
public:
static ThreadScgi* thread_scgi() { return ThreadScgi::internal_thread_scgi(); }
};
ThreadScgi* ThreadScgi::m_thread_scgi{};
void
ThreadScgi::create_thread() {
auto thread = new ThreadScgi;
m_thread_scgi = thread;
m_thread_scgi->m_state = STATE_INITIALIZED;
}
void
ThreadScgi::destroy_thread() {
delete m_thread_scgi;
m_thread_scgi = nullptr;
}
ThreadScgi*
ThreadScgi::thread_scgi() {
return m_thread_scgi;
}
void
ThreadScgi::cleanup_thread() {
if (m_scgi != nullptr)
m_scgi.load()->stop();
}
rpc::SCgi*
ThreadScgi::scgi() {
return m_scgi;
}
// TODO: Disable changing SCGI once set?
bool
ThreadScgi::set_scgi(rpc::SCgi* scgi) {
rpc::SCgi* expected = nullptr;
if (!m_scgi.compare_exchange_strong(expected, scgi))
return false;
change_rpc_log();
callback(nullptr, [this]() {
if (m_scgi == nullptr)
throw torrent::internal_error("Tried to start SCGI but object was not present.");
m_scgi.load()->activate();
});
return true;
}
void
ThreadScgi::set_rpc_log(const std::string& filename) {
callback(nullptr, [this, filename]() {
m_rpc_log_filename = filename;
change_rpc_log();
});
}
void
ThreadScgi::change_rpc_log() {
if (scgi() == nullptr)
return;
if (scgi()->log_fd() != -1) {
::close(scgi()->log_fd());
scgi()->set_log_fd(-1);
lt_log_print(torrent::LOG_NOTICE, "Closed RPC log.", 0);
}
if (m_rpc_log_filename.empty())
return;
scgi()->set_log_fd(open(expand_path(m_rpc_log_filename).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644));
if (scgi()->log_fd() == -1) {
lt_log_print(torrent::LOG_NOTICE, "Could not open RPC log file '%s'.", m_rpc_log_filename.c_str());
return;
}
lt_log_print(torrent::LOG_NOTICE, "Logging RPC events to '%s'.", m_rpc_log_filename.c_str());
}
void
ThreadScgi::call_events() {
if ((m_flags & flag_do_shutdown)) {
if ((m_flags & flag_did_shutdown))
throw torrent::internal_error("Already trigged shutdown.");
m_flags |= flag_did_shutdown;
throw torrent::shutdown_exception();
}
process_callbacks();
}
std::chrono::microseconds
ThreadScgi::next_timeout() {
// TODO: This leads to kqueue crash?
// return std::chrono::microseconds(1h);
return std::chrono::microseconds(10min);
}
} // namespace scgi
namespace scgi_thread {
torrent::utils::Thread* thread() { return scgi::ThreadScgiInternal::thread_scgi(); }
std::thread::id thread_id() { return scgi::ThreadScgiInternal::thread_scgi()->thread_id(); }
void callback(void* target, std::function<void ()>&& fn) { scgi::ThreadScgiInternal::thread_scgi()->callback(target, std::move(fn)); }
void cancel_callback(void* target) { scgi::ThreadScgiInternal::thread_scgi()->cancel_callback(target); }
void cancel_callback_and_wait(void* target) { scgi::ThreadScgiInternal::thread_scgi()->cancel_callback_and_wait(target); }
rpc::SCgi* scgi() { return scgi::ThreadScgiInternal::thread_scgi()->scgi(); }
void set_scgi(rpc::SCgi* scgi) { scgi::ThreadScgiInternal::thread_scgi()->set_scgi(scgi); }
void set_rpc_log(const std::string& filename) { scgi::ThreadScgiInternal::thread_scgi()->set_rpc_log(filename); }
} // namespace scgi_thread
+54
View File
@@ -0,0 +1,54 @@
#ifndef RTORRENT_SCGI_THREAD_SCGI_H
#define RTORRENT_SCGI_THREAD_SCGI_H
#include <atomic>
#include <string>
#include <torrent/utils/thread.h>
namespace rpc {
class SCgi;
}
namespace scgi {
class ThreadScgiInternal;
class ThreadScgi : public torrent::utils::Thread {
public:
static void create_thread();
static void destroy_thread();
static ThreadScgi* thread_scgi();
const char* name() const override { return "rtorrent-scgi"; }
rpc::SCgi* scgi();
bool set_scgi(rpc::SCgi* scgi);
void set_rpc_log(const std::string& filename);
protected:
friend class ThreadScgiInternal;
ThreadScgi() = default;
static auto internal_thread_scgi() { return m_thread_scgi; }
void cleanup_thread() override;
void call_events() override;
std::chrono::microseconds next_timeout() override;
private:
void task_touch_log();
void change_rpc_log();
static ThreadScgi* m_thread_scgi;
std::atomic<rpc::SCgi*> m_scgi{nullptr};
std::string m_rpc_log_filename;
};
} // namespace scgi
#endif // RTORRENT_SCGI_THREAD_SCGI_H
+193
View File
@@ -0,0 +1,193 @@
#include "config.h"
#include "download_storer.h"
#include <fcntl.h>
#include <fstream>
#include <unistd.h>
#include <torrent/exceptions.h>
#include <torrent/object.h>
#include <torrent/object_stream.h>
#include <torrent/utils/log.h>
#include <torrent/utils/resume.h>
#include "globals.h"
#include "core/download.h"
#include "utils/directory.h"
namespace session {
DownloadStorer::DownloadStorer(core::Download* download)
: m_download(download) {
}
void
DownloadStorer::build_streams(bool skip_static) {
auto* download = m_download->download();
auto& resume_base = download->bencode()->get_key("libtorrent_resume");
auto& rtorrent_base = download->bencode()->get_key("rtorrent");
rtorrent_base.insert_key("chunks_done", download->file_list()->completed_chunks());
rtorrent_base.insert_key("chunks_wanted", download->data()->wanted_chunks());
rtorrent_base.insert_key("total_uploaded", m_download->info()->up_rate()->total());
rtorrent_base.insert_key("total_downloaded", m_download->info()->down_rate()->total());
// Don't save for completed torrents when we've cleared the uncertain_pieces.
torrent::resume_save_progress(*download, resume_base);
torrent::resume_save_uncertain_pieces(*download, resume_base);
torrent::resume_save_addresses(*download, resume_base);
torrent::resume_save_file_priorities(*download, resume_base);
torrent::resume_save_tracker_settings(*download, resume_base);
// Temp fixing of all flags, move to a better place:
resume_base.set_flags(torrent::Object::flag_session_data);
rtorrent_base.set_flags(torrent::Object::flag_session_data);
auto torrent_stream = std::unique_ptr<std::stringstream>();
auto resume_stream = std::make_unique<std::stringstream>();
auto rtorrent_stream = std::make_unique<std::stringstream>();
if (!skip_static) {
torrent_stream = std::make_unique<std::stringstream>();
torrent::object_write_bencode(&*torrent_stream, m_download->bencode(), torrent::Object::flag_session_data);
if (!torrent_stream->good())
throw torrent::internal_error("DownloadStorer::build_streams() failed to write torrent stream.");
}
torrent::object_write_bencode(&*resume_stream, &resume_base, 0);
if (!resume_stream->good())
throw torrent::internal_error("DownloadStorer::build_streams() failed to write resume stream.");
torrent::object_write_bencode(&*rtorrent_stream, &rtorrent_base, 0);
if (!rtorrent_stream->good())
throw torrent::internal_error("DownloadStorer::build_streams() failed to write rtorrent stream.");
m_torrent_stream = std::move(torrent_stream);
m_rtorrent_stream = std::move(rtorrent_stream);
m_libtorrent_stream = std::move(resume_stream);
}
std::string
DownloadStorer::build_path(const std::string& session_path) {
auto info_hash = m_download->info()->info_hash();
if (session_path.empty())
throw torrent::internal_error("DownloadStorer::build_path() called with empty session path.");
if (session_path.back() != '/')
throw torrent::internal_error("DownloadStorer::build_path() session path missing trailing slash.");
return session_path + torrent::hash_string_to_hex_str(info_hash) + ".torrent";
}
void
DownloadStorer::unlink_files(const std::string& session_path) {
auto base_path = build_path(session_path);
auto torrent_path = base_path;
auto libtorrent_path = base_path + ".libtorrent_resume";
auto rtorrent_path = base_path + ".rtorrent";
auto metadata_path = base_path + ".meta";
::unlink(libtorrent_path.c_str());
::unlink(rtorrent_path.c_str());
::unlink(torrent_path.c_str());
::unlink(metadata_path.c_str());
}
namespace {
bool
is_correct_format(const std::string& f) {
if (f.size() != 48 || f.substr(40) != ".torrent")
return false;
for (std::string::const_iterator itr = f.begin(); itr != f.end() - 8; ++itr)
if (!(*itr >= '0' && *itr <= '9') &&
!(*itr >= 'A' && *itr <= 'F'))
return false;
return true;
}
void
save_stream(const std::string& path, bool use_fsyncdisk, const std::stringstream& stream) {
std::fstream output(path.c_str(), std::ios::out | std::ios::trunc);
// TODO: If we cannot open more files, wait for some to finish and try again.
if (!output.is_open())
throw torrent::storage_error("failed to open file for writing : " + path);
output << stream.rdbuf();
if (!output.good())
throw torrent::storage_error("failed to write stream to file : " + path);
output.close();
// Ensure that the new file is actually written to the disk
int fd = ::open(path.c_str(), O_WRONLY);
if (fd < 0)
throw torrent::storage_error("failed to open file descriptor for fsync : " + path);
if (use_fsyncdisk) {
#ifdef __APPLE__
::fsync(fd);
#else
::fdatasync(fd);
#endif
}
::close(fd);
}
} // namespace anonymous
void
DownloadStorer::save_and_move_streams(const std::string& path, bool use_fsyncdisk,
const std::stringstream* torrent_stream,
const std::stringstream* rtorrent_stream,
const std::stringstream* libtorrent_stream) {
auto torrent_path = path;
auto libtorrent_path = path + ".libtorrent_resume";
auto rtorrent_path = path + ".rtorrent";
if (torrent_stream)
save_stream(torrent_path + ".new", use_fsyncdisk, *torrent_stream);
save_stream(libtorrent_path + ".new", use_fsyncdisk, *libtorrent_stream);
save_stream(rtorrent_path + ".new", use_fsyncdisk, *rtorrent_stream);
if (torrent_stream) {
if (::rename((torrent_path + ".new").c_str(), torrent_path.c_str()) == -1)
throw torrent::storage_error("failed to rename torrent file : " + torrent_path);
}
if (::rename((libtorrent_path + ".new").c_str(), libtorrent_path.c_str()) == -1)
throw torrent::storage_error("failed to rename libtorrent resume file : " + libtorrent_path);
if (::rename((rtorrent_path + ".new").c_str(), rtorrent_path.c_str()) == -1)
throw torrent::storage_error("failed to rename rtorrent resume file : " + rtorrent_path);
}
utils::Directory
DownloadStorer::get_formated_entries(const std::string& session_path) {
if (session_path.empty())
return utils::Directory();
utils::Directory d(session_path);
if (!d.update(utils::Directory::update_hide_dot))
throw torrent::storage_error("session::DownloadStorer::update() could not open session directory: " + session_path);
d.erase(std::remove_if(d.begin(), d.end(), [](auto& entry) { return !is_correct_format(entry.s_name); }), d.end());
return d;
}
} // namespace session
+55
View File
@@ -0,0 +1,55 @@
#ifndef RTORRENT_SESSION_DOWNLOAD_STORER_H
#define RTORRENT_SESSION_DOWNLOAD_STORER_H
#include <memory>
#include <sstream>
#include <string>
#include <torrent/common.h>
namespace core {
class Download;
}
namespace utils {
class Directory;
}
namespace session {
class DownloadStorer {
public:
DownloadStorer(core::Download* download);
core::Download* download() const { return m_download; }
std::string build_path(const std::string& session_path);
void build_full_streams() { build_streams(false); }
void build_resume_streams() { build_streams(true); }
void unlink_files(const std::string& session_path);
auto torrent_stream() { return std::move(m_torrent_stream); }
auto rtorrent_stream() { return std::move(m_rtorrent_stream); }
auto libtorrent_stream() { return std::move(m_libtorrent_stream); }
static void save_and_move_streams(const std::string& path, bool use_fsyncdisk,
const std::stringstream* torrent_stream,
const std::stringstream* rtorrent_stream,
const std::stringstream* libtorrent_stream);
static utils::Directory get_formated_entries(const std::string& session_path);
private:
void build_streams(bool skip_static);
core::Download* m_download;
std::unique_ptr<std::stringstream> m_torrent_stream;
std::unique_ptr<std::stringstream> m_rtorrent_stream;
std::unique_ptr<std::stringstream> m_libtorrent_stream;
};
} // namespace session
#endif // RTORRENT_SESSION_DOWNLOAD_STORER_H
+502
View File
@@ -0,0 +1,502 @@
#include "config.h"
#include "session/session_manager.h"
#include <cassert>
#include <cstdlib>
#include <torrent/exceptions.h>
#include <torrent/utils/log.h>
#include "globals.h"
#include "session/download_storer.h"
#include "utils/lockfile.h"
#define LT_LOG(log_fmt, ...) \
lt_log_print(torrent::LOG_SESSION_EVENTS, "session-events: " log_fmt, __VA_ARGS__);
namespace session {
SessionManager::SessionManager(torrent::utils::Thread* thread)
: m_thread(thread),
m_lockfile(std::make_unique<utils::Lockfile>()) {
}
SessionManager::~SessionManager() = default;
void
SessionManager::set_path(std::string path) {
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
if (m_freeze_info)
throw torrent::input_error("Session path cannot be changed after startup.");
path = expand_path(path);
if (path.empty() || path.back() == '/')
m_path = path;
else
m_path = path + '/';
}
void
SessionManager::set_use_fsyncdisk(bool use_fsyncdisk) {
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
if (m_freeze_info)
throw torrent::input_error("Session fsyncdisk option cannot be changed after startup.");
m_use_fsyncdisk = use_fsyncdisk;
}
void
SessionManager::set_use_lock(bool use_lock) {
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
if (m_freeze_info)
throw torrent::input_error("Session lock option cannot be changed after startup.");
m_use_lock = use_lock;
}
void
SessionManager::save_resume_download(core::Download* download) {
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
if (m_path.empty())
return;
{
std::unique_lock<std::mutex> lock(m_pending_builds_mutex);
if (!m_active)
throw torrent::internal_error("SessionManager::save_resume_download() called while not active.");
if (std::find(m_pending_builds.begin(), m_pending_builds.end(), download) != m_pending_builds.end()) {
LT_LOG("download already in pending build of resume save : download:%p", download);
return;
}
if (m_pending_builds.empty())
torrent::main_thread::callback(this, [this]() { process_pending_resume_builds(false); });
m_pending_builds.push_back(download);
LT_LOG("build of resume save data queued : download:%p", download);
}
}
void
SessionManager::save_full_download(core::Download* download) {
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
if (m_path.empty())
return;
DownloadStorer storer(download);
storer.build_full_streams();
auto save_request = SaveRequest{
download,
storer.build_path(m_path),
storer.torrent_stream(),
storer.rtorrent_stream(),
storer.libtorrent_stream()
};
{
std::unique_lock<std::mutex> lock(m_mutex);
LT_LOG("requesting save : download:%p path:%s", download, save_request.path.c_str());
if (!m_active)
throw torrent::internal_error("SessionManager::save_download() called while not active.");
if (replace_save_request_unsafe(save_request))
throw torrent::internal_error("SessionManager::save_full_download() replacing existing save request, not supported?");
m_save_requests.push_back(std::move(save_request));
m_save_request_counter = m_save_requests.size();
LT_LOG("queued new full save request : download:%p", download);
}
if (!m_processing_saves_callback_scheduled.exchange(true))
session_thread::callback(this, [this]() { process_save_request(); });
}
void
SessionManager::remove_download(core::Download* download) {
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
if (m_path.empty())
return;
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_active)
throw torrent::internal_error("SessionManager::remove_download() called while not active.");
if (remove_completely_unsafe(download, lock))
LT_LOG("canceled pending save request : download:%p", download);
DownloadStorer(download).unlink_files(m_path);
LT_LOG("removed session files : download:%p", download);
}
void
SessionManager::start() {
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
std::unique_lock<std::mutex> lock(m_mutex);
if (m_active || m_freeze_info)
throw torrent::internal_error("SessionManager::start() called while already started.");
m_active = true;
m_freeze_info = true;
if (m_path.empty()) {
LT_LOG("session manager started with empty path, disabling session management", 0);
return;
}
LT_LOG("starting session manager with path: %s", m_path.c_str());
if (m_use_lock) {
m_lockfile->set_path(m_path + "rtorrent.lock");
if (!m_lockfile->try_lock()) {
if (errno == ENOENT || errno == ENOTDIR || errno == EACCES)
throw torrent::input_error("Could not lock session directory: " + std::string(std::strerror(errno)) + " : " + m_path);
else
throw torrent::input_error("Could not lock session directory, held by: " + m_lockfile->locked_by_as_string() + " : " + m_path);
}
LT_LOG("locked session directory: %s", m_path.c_str());
}
}
void
SessionManager::cleanup() {
assert(m_thread == torrent::this_thread::thread());
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_active)
throw torrent::internal_error("SessionManager::cleanup() called while not active.");
{
std::unique_lock<std::mutex> pending_lock(m_pending_builds_mutex);
if (!m_pending_builds.empty())
throw torrent::internal_error("SessionManager::cleanup() called with pending builds.");
}
m_active = false;
if (m_path.empty()) {
LT_LOG("session manager cleanup called with empty path, skipping", 0);
return;
}
LT_LOG("cleaning up session manager with path: %s", m_path.c_str());
flush_all_and_wait_unsafe(lock);
if (m_use_lock) {
if (!m_lockfile->unlock())
LT_LOG("could not unlock session directory: %s", m_path.c_str());
LT_LOG("unlocked session directory: %s", m_path.c_str());
}
LT_LOG("session manager cleaned up", 0);
session_thread::cancel_callback(this);
torrent::main_thread::cancel_callback(this);
}
void
SessionManager::process_pending_resume_builds(bool is_flushing) {
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
std::vector<SaveRequest> requests;
// Only main thread is allowed to process pending builds or remove downloads, as such it is safe
// to unlock before adding them to save requests.
{
std::unique_lock<std::mutex> lock(m_pending_builds_mutex);
while (!m_pending_builds.empty()) {
if (!is_flushing && m_save_request_counter + requests.size() >= max_concurrent_requests)
break;
auto* download = m_pending_builds.front();
m_pending_builds.pop_front();
LT_LOG("processing pending resume save : download:%p", download);
DownloadStorer storer(download);
storer.build_resume_streams();
auto save_request = SaveRequest{
download,
storer.build_path(m_path),
nullptr,
storer.rtorrent_stream(),
storer.libtorrent_stream()
};
requests.push_back(std::move(save_request));
}
}
if (requests.empty())
return;
{
std::unique_lock<std::mutex> save_lock(m_mutex);
if (!m_active)
throw torrent::internal_error("SessionManager::process_pending_builds() called while not active.");
for (auto& save_request : requests) {
if (replace_save_request_unsafe(save_request)) {
LT_LOG("updated pending resume save request : download:%p", save_request.download);
continue;
}
m_save_requests.push_back(std::move(save_request));
LT_LOG("queued new resume save request : download:%p", save_request.download);
}
m_save_request_counter = m_save_requests.size();
}
if (!is_flushing && !m_processing_saves_callback_scheduled.exchange(true))
session_thread::callback(this, [this]() { process_save_request_with_pending_callback(); });
}
void
SessionManager::process_save_request() {
assert(m_thread == torrent::this_thread::thread());
if (m_path.empty())
throw torrent::internal_error("SessionManager::process_save_request() called with empty path.");
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_active)
throw torrent::internal_error("SessionManager::process_save_request() called while not active.");
while (!m_save_requests.empty() && m_processing_saves.size() < max_concurrent_requests)
process_next_save_request_unsafe();
m_processing_saves_callback_scheduled = false;
}
void
SessionManager::process_save_request_with_pending_callback() {
process_save_request();
std::unique_lock<std::mutex> lock(m_pending_builds_mutex);
if (!m_pending_builds.empty())
torrent::main_thread::callback(this, [this]() { process_pending_resume_builds(false); });
}
void
SessionManager::process_next_save_request_unsafe() {
auto request = std::move(m_save_requests.front());
m_save_requests.pop_front();
m_save_request_counter = m_save_requests.size();
auto itr = m_processing_saves.insert(m_processing_saves.end(), ProcessingSave{});
itr->second = std::move(request);
itr->first = std::async(std::launch::async, [this, itr]() {
auto cleanup_fn = [this, itr]() {
std::unique_lock<std::mutex> lock(m_mutex);
if (m_finished_saves.empty())
session_thread::callback(this, [this]() { process_finished_saves(); });
m_finished_saves.push_back(std::move(*itr));
m_finished_condition.notify_all();
m_processing_saves.erase(itr);
};
try {
DownloadStorer::save_and_move_streams(itr->second.path, m_use_fsyncdisk,
itr->second.torrent_stream.get(),
itr->second.rtorrent_stream.get(),
itr->second.libtorrent_stream.get());
} catch (...) {
cleanup_fn();
throw;
}
cleanup_fn();
});
}
void
SessionManager::process_finished_saves() {
assert(m_thread == torrent::this_thread::thread());
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_active)
throw torrent::internal_error("SessionManager::process_finished_saves() called while not active.");
for (auto& request : m_finished_saves) {
try {
request.first.get();
} catch (torrent::storage_error& e) {
LT_LOG("error saving download : storage error :download:%p path:%s : %s", request.second.download, request.second.path.c_str(), e.what());
if (m_last_storage_error_message + std::chrono::minutes(5) > torrent::this_thread::cached_time()) {
m_ignored_storage_error_count++;
continue;
}
lt_log_print(torrent::LOG_ERROR, "Storage errors saving session data for download: ignored:%u : %s", m_ignored_storage_error_count, e.what());
m_last_storage_error_message = torrent::this_thread::cached_time();
m_ignored_storage_error_count = 0;
continue;
} catch (torrent::internal_error& e) {
LT_LOG("error saving download : internal error : download:%p path:%s : %s", request.second.download, request.second.path.c_str(), e.what());
throw;
} catch (...) {
LT_LOG("error saving download : unknown error : download:%p path:%s", request.second.download, request.second.path.c_str());
throw;
}
LT_LOG("finished saving download : download:%p path:%s", request.second.download, request.second.path.c_str());
}
m_finished_saves.clear();
}
void
SessionManager::flush_all_and_wait_unsafe(std::unique_lock<std::mutex>& lock) {
LT_LOG("flushing all pending saves", 0);
while (!m_save_requests.empty()) {
if (m_processing_saves.size() >= max_cleanup_processing) {
m_finished_condition.wait(lock);
continue;
}
process_next_save_request_unsafe();
}
while (!m_processing_saves.empty())
m_finished_condition.wait(lock);
for (auto& request : m_finished_saves)
LT_LOG("finished saving download : download:%p path:%s", request.second.download, request.second.path.c_str());
m_finished_saves.clear();
LT_LOG("flushed all pending saves", 0);
}
bool
SessionManager::replace_save_request_unsafe(SaveRequest& save_request) {
// Can be run in any thread.
auto itr = std::find_if(m_save_requests.begin(), m_save_requests.end(), [download = save_request.download](auto& req) {
return req.download == download;
});
if (itr == m_save_requests.end())
return false;
if (itr->path != save_request.path)
throw torrent::internal_error("SessionManager::replace_save_request_unsafe() path mismatch on replace: " + itr->path + " != " + save_request.path);
if (save_request.torrent_stream != nullptr)
throw torrent::internal_error("SessionManager::replace_save_request_unsafe() cannot replace full save requests.");
itr->rtorrent_stream = std::move(save_request.rtorrent_stream);
itr->libtorrent_stream = std::move(save_request.libtorrent_stream);
return true;
}
bool
SessionManager::remove_completely_unsafe(core::Download* download, std::unique_lock<std::mutex>& lock) {
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
auto remove_requests = [this, download]() {
auto itr = std::remove_if(m_save_requests.begin(), m_save_requests.end(), [download](auto& req) {
return req.download == download;
});
if (itr == m_save_requests.end())
return false;
m_save_requests.erase(itr, m_save_requests.end());
return true;
};
auto remove_pending = [this, download]() {
std::unique_lock<std::mutex> pending_lock(m_pending_builds_mutex);
auto itr = std::remove_if(m_pending_builds.begin(), m_pending_builds.end(), [download](auto* req) {
return req == download;
});
if (itr == m_pending_builds.end())
return false;
m_pending_builds.erase(itr, m_pending_builds.end());
return true;
};
bool removed_something = false;
if (remove_pending())
removed_something = true;
if (remove_requests())
removed_something = true;
// This may block for a relatively long time if fdatasync is in use, however this is necessary.
while (true) {
auto itr = std::find_if(m_processing_saves.begin(), m_processing_saves.end(), [download](auto& req) {
return req.second.download == download;
});
if (itr == m_processing_saves.end())
break;
m_finished_condition.wait(lock);
}
// Since we're the main thread, no more requests for this download can be added.
// Checking active after remove_save_request_unsafe to ensure we're calling this after shutdown.
if (!m_active)
throw torrent::internal_error("SessionManager::remove_completely_unsafe() called while not active.");
return removed_something;
}
// TODO: Properly handle errors.
// TODO: If no more sockets can be opened, wait for a job to finish. if all is finished, use a
// timeout and try again.
} // namespace session
+126
View File
@@ -0,0 +1,126 @@
#ifndef RTORRENT_SESSION_SESSION_MANAGER_H
#define RTORRENT_SESSION_SESSION_MANAGER_H
#include <condition_variable>
#include <deque>
#include <future>
#include <list>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <vector>
#include <torrent/common.h>
class Control;
namespace core {
class Download;
}
namespace utils {
class Lockfile;
}
namespace session {
class ThreadSession;
struct SaveRequest {
core::Download* download;
std::string path;
std::unique_ptr<std::stringstream> torrent_stream;
std::unique_ptr<std::stringstream> rtorrent_stream;
std::unique_ptr<std::stringstream> libtorrent_stream;
};
class SessionManager {
public:
typedef std::unique_ptr<std::stringstream> stream_ptr;
// TODO: This should depend on max open sockets / be configurable.
constexpr static int max_concurrent_requests = 16;
constexpr static int max_concurrent_processing = 16;
constexpr static int max_cleanup_processing = 64;
SessionManager(torrent::utils::Thread* thread);
~SessionManager();
bool is_used() const;
std::string path() const;
void set_path(std::string path);
bool use_fsyncdisk() const;
void set_use_fsyncdisk(bool use_fsyncdisk);
bool use_lock() const;
void set_use_lock(bool use_lock);
void save_full_download(core::Download* download);
void save_resume_download(core::Download* download);
void remove_download(core::Download* download);
protected:
friend class ::Control;
friend class ThreadSession;
void save_download(core::Download* download, bool skip_static);
void start();
void cleanup();
void flush_all_pending_builds();
private:
void process_pending_resume_builds(bool is_flushing);
void process_save_request();
void process_save_request_with_pending_callback();
void process_next_save_request_unsafe();
void process_finished_saves();
// Requires a higher number of open sockets, and should only be used during shutdown.
void flush_all_and_wait_unsafe(std::unique_lock<std::mutex>& lock);
bool replace_save_request_unsafe(SaveRequest& download);
bool remove_completely_unsafe(core::Download* download, std::unique_lock<std::mutex>& lock);
torrent::utils::Thread* m_thread;
bool m_freeze_info{};
std::string m_path;
bool m_use_fsyncdisk{true};
bool m_use_lock{true};
std::mutex m_mutex;
bool m_active{};
typedef std::pair<std::future<void>, SaveRequest> ProcessingSave;
std::deque<SaveRequest> m_save_requests;
std::atomic<size_t> m_save_request_counter{};
std::list<ProcessingSave> m_processing_saves;
std::atomic<bool> m_processing_saves_callback_scheduled{};
std::condition_variable m_finished_condition;
std::vector<ProcessingSave> m_finished_saves;
std::unique_ptr<utils::Lockfile> m_lockfile;
std::chrono::microseconds m_last_storage_error_message{};
unsigned int m_ignored_storage_error_count{};
// Pending builds are only ever locked by main thread.
std::mutex m_pending_builds_mutex;
std::deque<core::Download*> m_pending_builds;
};
inline bool SessionManager::is_used() const { return !m_path.empty(); }
inline std::string SessionManager::path() const { return m_path; }
inline bool SessionManager::use_fsyncdisk() const { return true; }
inline bool SessionManager::use_lock() const { return m_use_lock; }
inline void SessionManager::flush_all_pending_builds() { process_pending_resume_builds(true); }
} // namespace session
#endif // RTORRENT_SESSION_SESSION_MANAGER_H
+87
View File
@@ -0,0 +1,87 @@
#include "config.h"
#include "thread_session.h"
#include <torrent/exceptions.h>
#include "session/session_manager.h"
namespace session {
class ThreadSessionInternal {
public:
static ThreadSession* thread_session() { return ThreadSession::internal_thread_session(); }
};
ThreadSession* ThreadSession::m_thread_session{nullptr};
void
ThreadSession::create_thread() {
auto thread = new ThreadSession;
thread->m_manager = std::make_unique<SessionManager>(thread);
m_thread_session = thread;
m_thread_session->m_state = STATE_INITIALIZED;
}
void
ThreadSession::destroy_thread() {
delete m_thread_session;
m_thread_session = nullptr;
}
ThreadSession*
ThreadSession::thread_session() {
return m_thread_session;
}
void
ThreadSession::init_thread_pre_start() {
m_manager->start();
}
// TODO: Make sure we trigger session save before main thread exits, that it adds all required
// downloads to the queue.
void
ThreadSession::cleanup_thread() {
m_manager->cleanup();
}
void
ThreadSession::call_events() {
// lt_log_print_locked(torrent::LOG_THREAD_NOTICE, "Got thread_disk tick.");
process_callbacks();
if ((m_flags & flag_do_shutdown)) {
if ((m_flags & flag_did_shutdown))
throw torrent::internal_error("Already trigged shutdown.");
m_flags |= flag_did_shutdown;
throw torrent::shutdown_exception();
}
}
std::chrono::microseconds
ThreadSession::next_timeout() {
// TODO: This leads to kqueue crash?
// return std::chrono::microseconds(1h);
return std::chrono::microseconds(10min);
}
} // namespace session
namespace session_thread {
torrent::utils::Thread* thread() { return session::ThreadSessionInternal::thread_session(); }
std::thread::id thread_id() { return session::ThreadSessionInternal::thread_session()->thread_id(); }
void callback(void* target, std::function<void ()>&& fn) { session::ThreadSessionInternal::thread_session()->callback(target, std::move(fn)); }
void cancel_callback(void* target) { session::ThreadSessionInternal::thread_session()->cancel_callback(target); }
void cancel_callback_and_wait(void* target) { session::ThreadSessionInternal::thread_session()->cancel_callback_and_wait(target); }
session::SessionManager* manager() { return session::ThreadSessionInternal::thread_session()->manager(); }
std::string session_path() { return session::ThreadSessionInternal::thread_session()->manager()->path(); }
} // namespace session_thread
+43
View File
@@ -0,0 +1,43 @@
#ifndef RTORRENT_SESSION_THREAD_SESSION_H
#define RTORRENT_SESSION_THREAD_SESSION_H
#include <torrent/utils/thread.h>
namespace session {
class SessionManager;
class ThreadSessionInternal;
class ThreadSession : public torrent::utils::Thread {
public:
static void create_thread();
static void destroy_thread();
static ThreadSession* thread_session();
const char* name() const override { return "rtorrent-session"; }
SessionManager* manager() const { return m_manager.get(); }
protected:
friend class ThreadSessionInternal;
ThreadSession() = default;
static auto internal_thread_session() { return m_thread_session; }
void init_thread_pre_start() override;
void cleanup_thread() override;
void call_events() override;
std::chrono::microseconds next_timeout() override;
private:
static ThreadSession* m_thread_session;
std::unique_ptr<SessionManager> m_manager;
};
} // namespace session
#endif // RTORRENT_SESSION_THREAD_SESSION_H
+4 -37
View File
@@ -1,44 +1,11 @@
// 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 <cerrno>
#include <cstring>
#include <signal.h>
#include <stdexcept>
#include <string>
#include "rak/error_number.h"
#include "signal_handler.h"
#ifdef __sun__
@@ -80,7 +47,7 @@ SignalHandler::set_handler(unsigned int signum, slot_void slot) {
sa.sa_handler = &SignalHandler::caught;
if (sigaction(signum, &sa, NULL) == -1)
throw std::logic_error("Could not set sigaction: " + std::string(rak::error_number::current().c_str()));
throw std::logic_error("Could not set sigaction: " + std::string(std::strerror(errno)));
else
m_handlers[signum] = slot;
}
@@ -97,7 +64,7 @@ SignalHandler::set_sigaction_handler(unsigned int signum, handler_slot slot) {
sigemptyset(&sa.sa_mask);
if (sigaction(signum, &sa, NULL) == -1)
throw std::logic_error("Could not set sigaction: " + std::string(rak::error_number::current().c_str()));
throw std::logic_error("Could not set sigaction: " + std::string(std::strerror(errno)));
}
void
-97
View File
@@ -1,97 +0,0 @@
#include "config.h"
#include "thread_worker.h"
#include <fcntl.h>
#include <unistd.h>
#include <cassert>
#include <rak/path.h>
#include <torrent/exceptions.h>
#include "globals.h"
#include "control.h"
#include "core/manager.h"
#include "rpc/scgi.h"
#include "rpc/parse_commands.h"
ThreadWorker::~ThreadWorker() = default;
void
ThreadWorker::init_thread() {
m_state = STATE_INITIALIZED;
}
void
ThreadWorker::cleanup_thread() {
if (m_scgi != nullptr)
m_scgi.load()->deactivate();
}
bool
ThreadWorker::set_scgi(rpc::SCgi* scgi) {
rpc::SCgi* expected = nullptr;
if (!m_scgi.compare_exchange_strong(expected, scgi))
return false;
change_rpc_log();
callback(nullptr, [this]() {
if (m_scgi == NULL)
throw torrent::internal_error("Tried to start SCGI but object was not present.");
m_scgi.load()->activate();
});
return true;
}
void
ThreadWorker::set_rpc_log(const std::string& filename) {
callback(nullptr, [this, filename]() {
m_rpc_log_filename = filename;
change_rpc_log();
});
}
void
ThreadWorker::change_rpc_log() {
if (scgi() == NULL)
return;
if (scgi()->log_fd() != -1) {
::close(scgi()->log_fd());
scgi()->set_log_fd(-1);
control->core()->push_log("Closed RPC log.");
}
if (m_rpc_log_filename.empty())
return;
scgi()->set_log_fd(open(rak::path_expand(m_rpc_log_filename).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644));
if (scgi()->log_fd() == -1) {
control->core()->push_log_std("Could not open RPC log file '" + m_rpc_log_filename + "'.");
return;
}
control->core()->push_log_std("Logging RPC events to '" + m_rpc_log_filename + "'.");
}
void
ThreadWorker::call_events() {
if ((m_flags & flag_do_shutdown)) {
if ((m_flags & flag_did_shutdown))
throw torrent::internal_error("Already trigged shutdown.");
m_flags |= flag_did_shutdown;
throw torrent::shutdown_exception();
}
process_callbacks();
}
std::chrono::microseconds
ThreadWorker::next_timeout() {
return std::chrono::microseconds(10min);
}
-38
View File
@@ -1,38 +0,0 @@
#ifndef RTORRENT_THREAD_WORKER_H
#define RTORRENT_THREAD_WORKER_H
#include <atomic>
#include <string>
#include <torrent/utils/thread.h>
namespace rpc {
class SCgi;
}
class ThreadWorker : public torrent::utils::Thread {
public:
ThreadWorker() = default;
~ThreadWorker();
const char* name() const override { return "rtorrent scgi"; }
void init_thread() override;
void cleanup_thread() override;
rpc::SCgi* scgi() { return m_scgi; }
bool set_scgi(rpc::SCgi* scgi);
void set_rpc_log(const std::string& filename);
private:
void task_touch_log();
void change_rpc_log();
void call_events() override;
std::chrono::microseconds next_timeout() override;
std::atomic<rpc::SCgi*> m_scgi{nullptr};
std::string m_rpc_log_filename;
};
#endif
+4 -4
View File
@@ -116,7 +116,7 @@ DownloadList::activate_display(Display displayType) {
m_uiArray[m_state] = NULL;
break;
case DISPLAY_DOWNLOAD_LIST:
m_uiArray[DISPLAY_DOWNLOAD_LIST]->disable();
@@ -130,7 +130,7 @@ DownloadList::activate_display(Display displayType) {
case DISPLAY_STRING_LIST:
m_uiArray[m_state]->disable();
break;
default:
break;
}
@@ -152,7 +152,7 @@ DownloadList::activate_display(Display displayType) {
download->activate(m_frame);
download->slot_exit(std::bind(&DownloadList::activate_display, this, DISPLAY_DOWNLOAD_LIST));
m_uiArray[DISPLAY_DOWNLOAD] = download;
break;
}
@@ -273,7 +273,7 @@ DownloadList::receive_exit_input(Input type) {
set_escdelay(1000);
input::TextInput* input = control->ui()->current_input();
// We should check that this object is the one holding the input.
if (input == NULL)
return;
-34
View File
@@ -1,37 +1,3 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
#ifndef RTORRENT_UI_DOWNLOAD_LIST_H
#define RTORRENT_UI_DOWNLOAD_LIST_H
+28 -22
View File
@@ -1,5 +1,7 @@
#include "config.h"
#include "ui/root.h"
#include <fstream>
#include <stdexcept>
#include <string.h>
@@ -9,6 +11,8 @@
#include <torrent/download/resource_manager.h>
#include <torrent/utils/log.h>
#include "control.h"
#include "core/download_list.h"
#include "core/manager.h"
#include "display/frame.h"
#include "display/window_http_queue.h"
@@ -18,12 +22,7 @@
#include "input/manager.h"
#include "input/text_input.h"
#include "rpc/parse_commands.h"
#include "control.h"
#include "download_list.h"
#include "core/download_store.h"
#include "root.h"
#include "session/session_manager.h"
namespace ui {
@@ -83,13 +82,13 @@ Root::init(Control* c) {
m_downloadList = std::make_unique<DownloadList>();
display::Frame* rootFrame = m_control->display()->root_frame();
auto root_frame = m_control->display()->root_frame();
rootFrame->initialize_row(5);
rootFrame->frame(0)->initialize_window(m_windowTitle.get());
rootFrame->frame(2)->initialize_window(m_windowHttpQueue.get());
rootFrame->frame(3)->initialize_window(m_windowInput.get());
rootFrame->frame(4)->initialize_window(m_windowStatusbar.get());
root_frame->initialize_row(5);
root_frame->frame(0)->initialize_window(m_windowTitle.get());
root_frame->frame(2)->initialize_window(m_windowHttpQueue.get());
root_frame->frame(3)->initialize_window(m_windowInput.get());
root_frame->frame(4)->initialize_window(m_windowStatusbar.get());
m_windowTitle->set_active(true);
m_windowStatusbar->set_active(true);
@@ -97,7 +96,7 @@ Root::init(Control* c) {
setup_keys();
m_downloadList->activate(rootFrame->frame(1));
m_downloadList->activate(root_frame->frame(1));
}
void
@@ -111,7 +110,14 @@ Root::cleanup() {
m_control->display()->root_frame()->clear();
m_control->input()->erase(&m_bindings);
m_control = NULL;
// Destroy windows in reverse order of creation.
m_windowStatusbar = nullptr;
m_windowInput = nullptr;
m_windowHttpQueue = nullptr;
m_windowTitle = nullptr;
m_downloadList = nullptr;
m_control = nullptr;
}
const char*
@@ -371,13 +377,13 @@ Root::set_input_history_size(int size) {
void
Root::load_input_history() {
if (m_control == nullptr || !m_control->core()->download_store()->is_enabled()) {
if (m_control == nullptr || !session_thread::manager()->is_used()) {
lt_log_print(torrent::LOG_DEBUG, "ignoring input history file");
return;
}
std::string history_filename = m_control->core()->download_store()->path() + "rtorrent.input_history";
std::fstream history_file(history_filename.c_str(), std::ios::in);
auto history_filename = session_thread::manager()->path() + "rtorrent.input_history";
auto history_file = std::fstream(history_filename.c_str(), std::ios::in);
if (history_file.is_open()) {
// Create a temp object of the content since size of history categories can be smaller than this.
@@ -439,12 +445,12 @@ Root::load_input_history() {
void
Root::save_input_history() {
if (m_control == nullptr || !m_control->core()->download_store()->is_enabled())
if (m_control == nullptr || !session_thread::manager()->is_used())
return;
std::string history_filename = m_control->core()->download_store()->path() + "rtorrent.input_history";
std::string history_filename_tmp = history_filename + ".new";
std::fstream history_file(history_filename_tmp.c_str(), std::ios::out | std::ios::trunc);
auto history_filename = session_thread::manager()->path() + "rtorrent.input_history";
auto history_filename_tmp = history_filename + ".new";
auto history_file = std::fstream(history_filename_tmp.c_str(), std::ios::out | std::ios::trunc);
if (!history_file.is_open()) {
lt_log_print(torrent::LOG_DEBUG, "could not open input history file for writing (path:%s)", history_filename.c_str());
@@ -496,7 +502,7 @@ Root::set_keymap_style(const std::string& style) {
m_keymap_style = style;
}
const int
int
Root::navigation_key(NavigationKeymap key) {
return m_keymap[key];
}
+2 -1
View File
@@ -98,7 +98,8 @@ public:
const std::string& keymap_style() { return m_keymap_style; }
void set_keymap_style(const std::string& style);
const int navigation_key(NavigationKeymap key);
int navigation_key(NavigationKeymap key);
private:
void setup_keys();
+6 -40
View File
@@ -1,48 +1,14 @@
// 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 <algorithm>
#include <functional>
#include "utils/directory.h"
#include <algorithm>
#include <dirent.h>
#include <functional>
#include <sys/stat.h>
#include <rak/path.h>
#include <torrent/exceptions.h>
#include "directory.h"
#include "globals.h"
namespace utils {
@@ -52,7 +18,7 @@ Directory::is_valid() const {
if (m_path.empty())
return false;
DIR* d = opendir(rak::path_expand(m_path).c_str());
DIR* d = opendir(expand_path(m_path).c_str());
closedir(d);
return d;
@@ -63,7 +29,7 @@ Directory::update(int flags) {
if (m_path.empty())
throw torrent::input_error("Directory::update() tried to open an empty path.");
DIR* d = opendir(rak::path_expand(m_path).c_str());
DIR* d = opendir(expand_path(m_path).c_str());
if (d == NULL)
return false;
+10 -43
View File
@@ -1,55 +1,22 @@
// 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/file_stat.h>
#include <rak/path.h>
#include <torrent/exceptions.h>
#include "utils/file_status_cache.h"
#include "file_status_cache.h"
#include <torrent/exceptions.h>
#include <torrent/utils/file_stat.h>
#include "globals.h"
namespace utils {
bool
FileStatusCache::insert(const std::string& path, int flags) {
rak::file_stat fs;
FileStatusCache::insert(const std::string& path) {
torrent::utils::FileStat fs;
// Should we expand somewhere else? Problem is it adds a lot of junk
// to the start of the paths added to the cache, causing more work
// during search, etc.
if (!fs.update(rak::path_expand(path)))
if (!fs.update(expand_path(path)))
return false;
std::pair<iterator, bool> result = base_type::insert(value_type(path, file_status()));
@@ -71,10 +38,10 @@ FileStatusCache::prune() {
iterator itr = begin();
while (itr != end()) {
rak::file_stat fs;
torrent::utils::FileStat fs;
iterator tmp = itr++;
if (!fs.update(rak::path_expand(tmp->first)) || tmp->second.m_mtime != (uint32_t)fs.modified_time())
if (!fs.update(expand_path(tmp->first)) || tmp->second.m_mtime != (uint32_t)fs.modified_time())
base_type::erase(tmp);
}
}
+2 -37
View File
@@ -1,42 +1,9 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
#ifndef RTORRENT_UTILS_FILE_STATUS_CACHE_H
#define RTORRENT_UTILS_FILE_STATUS_CACHE_H
#include <map>
#include <string>
#include <cinttypes>
namespace utils {
@@ -65,11 +32,9 @@ public:
using base_type::erase;
// static int flag_
// Insert and return true if the entry does not exist or the new
// file's mtime is more recent.
bool insert(const std::string& path, int flags);
bool insert(const std::string& path);
// Add a function for pruning a sorted list of paths.
-34
View File
@@ -1,37 +1,3 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
// A simple, and not guaranteed atomic, lockfile implementation. It
// saves the hostname and pid in the lock file, which may be accessed
// by Lockfile::locked_by(). If the path is an empty string then no
-265
View File
@@ -1,265 +0,0 @@
// libTorrent - BitTorrent library
// 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 <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <rak/socket_address.h>
#include <torrent/exceptions.h>
#include "socket_fd.h"
namespace utils {
inline void
SocketFd::check_valid() const {
if (!is_valid())
throw torrent::internal_error("SocketFd function called on an invalid fd.");
}
bool
SocketFd::set_nonblock() {
check_valid();
return fcntl(m_fd, F_SETFL, O_NONBLOCK) == 0;
}
bool
SocketFd::set_priority(priority_type p) {
check_valid();
int opt = p;
if (m_ipv6_socket)
return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
else
return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
}
bool
SocketFd::set_reuse_address(bool state) {
check_valid();
int opt = state;
return setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == 0;
}
bool
SocketFd::set_dont_route(bool state) {
check_valid();
int opt = state;
return setsockopt(m_fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof(opt)) == 0;
}
// bool
// SocketFd::set_bind_to_device(const char* device) {
// check_valid();
// struct ifreq ifr;
// strlcpy(ifr.ifr_name, device, IFNAMSIZ);
// return setsockopt(m_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == 0;
// }
bool
SocketFd::set_send_buffer_size(uint32_t s) {
check_valid();
int opt = s;
return setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) == 0;
}
bool
SocketFd::set_receive_buffer_size(uint32_t s) {
check_valid();
int opt = s;
return setsockopt(m_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) == 0;
}
int
SocketFd::get_error() const {
check_valid();
int err;
socklen_t length = sizeof(err);
if (getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &err, &length) == -1)
throw torrent::internal_error("SocketFd::get_error() could not get error");
return err;
}
bool
SocketFd::open_stream() {
m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP);
if (m_fd == -1) {
m_ipv6_socket = false;
return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
}
m_ipv6_socket = true;
int zero = 0;
return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
}
bool
SocketFd::open_datagram() {
m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0);
if (m_fd == -1) {
m_ipv6_socket = false;
return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
}
m_ipv6_socket = true;
int zero = 0;
return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
}
bool
SocketFd::open_local() {
return (m_fd = socket(rak::socket_address::pf_local, SOCK_STREAM, 0)) != -1;
}
void
SocketFd::close() {
if (::close(m_fd) && errno == EBADF)
throw torrent::internal_error("SocketFd::close() called on an invalid file descriptor");
}
bool
SocketFd::bind(const rak::socket_address& sa) {
check_valid();
if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
}
return !::bind(m_fd, sa.c_sockaddr(), sa.length());
}
bool
SocketFd::bind(const rak::socket_address& sa, unsigned int length) {
check_valid();
if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
}
return !::bind(m_fd, sa.c_sockaddr(), length);
}
bool
SocketFd::connect(const rak::socket_address& sa) {
check_valid();
if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
return !::connect(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)) || errno == EINPROGRESS;
}
return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS;
}
bool
SocketFd::getsockname(rak::socket_address *sa) {
check_valid();
socklen_t len = sizeof(rak::socket_address);
if (::getsockname(m_fd, sa->c_sockaddr(), &len)) {
return false;
}
if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
*sa = sa->sa_inet6()->normalize_address();
}
return true;
}
bool
SocketFd::listen(int size) {
check_valid();
return !::listen(m_fd, size);
}
SocketFd
SocketFd::accept(rak::socket_address* sa) {
check_valid();
socklen_t len = sizeof(rak::socket_address);
if (sa == NULL) {
return SocketFd(::accept(m_fd, NULL, &len));
}
int fd = ::accept(m_fd, sa->c_sockaddr(), &len);
if (fd != -1 && m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
*sa = sa->sa_inet6()->normalize_address();
}
return SocketFd(fd);
}
// unsigned int
// SocketFd::get_read_queue_size() const {
// unsigned int v;
// if (!is_valid() || ioctl(m_fd, SIOCINQ, &v) < 0)
// throw internal_error("SocketFd::get_read_queue_size() could not be performed");
// return v;
// }
// unsigned int
// SocketFd::get_write_queue_size() const {
// unsigned int v;
// if (!is_valid() || ioctl(m_fd, SIOCOUTQ, &v) < 0)
// throw internal_error("SocketFd::get_write_queue_size() could not be performed");
// return v;
// }
}
-98
View File
@@ -1,98 +0,0 @@
// libTorrent - BitTorrent library
// Copyright (C) 2005-2011, Jari Sundell
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// In addition, as a special exception, the copyright holders give
// permission to link the code of portions of this program with the
// OpenSSL library under certain conditions as described in each
// individual source file, and distribute linked combinations
// including the two.
//
// You must obey the GNU General Public License in all respects for
// all of the code used other than OpenSSL. If you modify file(s)
// with this exception, you may extend this exception to your version
// of the file(s), but you are not obligated to do so. If you do not
// wish to do so, delete this exception statement from your version.
// If you delete this exception statement from all source files in the
// program, then also delete it here.
//
// Contact: Jari Sundell <sundell.software@gmail.com>
#ifndef RTORRENT_UTILS_SOCKET_FD_H
#define RTORRENT_UTILS_SOCKET_FD_H
#include <unistd.h>
namespace rak {
class socket_address;
}
namespace utils {
class SocketFd {
public:
typedef uint8_t priority_type;
SocketFd() : m_fd(-1) {}
explicit SocketFd(int fd) : m_fd(fd) {}
bool is_valid() const { return m_fd >= 0; }
int get_fd() const { return m_fd; }
void set_fd(int fd) { m_fd = fd; }
bool set_nonblock();
bool set_reuse_address(bool state);
bool set_dont_route(bool state);
bool set_bind_to_device(const char* device);
bool set_priority(priority_type p);
bool set_send_buffer_size(uint32_t s);
bool set_receive_buffer_size(uint32_t s);
int get_error() const;
bool open_stream();
bool open_datagram();
bool open_local();
void close();
void clear() { m_fd = -1; }
bool bind(const rak::socket_address& sa);
bool bind(const rak::socket_address& sa, unsigned int length);
bool connect(const rak::socket_address& sa);
bool getsockname(rak::socket_address* sa);
bool listen(int size);
SocketFd accept(rak::socket_address* sa);
// unsigned int get_read_queue_size() const;
// unsigned int get_write_queue_size() const;
private:
inline void check_valid() const;
int m_fd;
bool m_ipv6_socket;
};
}
#endif
+1 -1
View File
@@ -6,7 +6,7 @@
#include "test/helpers/mock_function.h"
#include "torrent/exceptions.h"
#include "torrent/poll.h"
#include "torrent/net/poll.h"
const int test_thread::test_flag_pre_stop;
const int test_thread::test_flag_long_timeout;
+6 -6
View File
@@ -3,8 +3,8 @@
#include "test/rpc/test_parse_options.h"
#include <array>
#include <torrent/connection_manager.h>
#include <torrent/exceptions.h>
#include <torrent/net/network_config.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
@@ -178,11 +178,11 @@ TestParseOptions::test_flag_libtorrent() {
void
TestParseOptions::test_flags_libtorrent() {
FLAGS_LT_ENCRYPTION_ASSERT("", torrent::ConnectionManager::encryption_none);
FLAGS_LT_ENCRYPTION_ASSERT("none", torrent::ConnectionManager::encryption_none);
FLAGS_LT_ENCRYPTION_ASSERT("require_rc4", torrent::ConnectionManager::encryption_require_RC4);
FLAGS_LT_ENCRYPTION_ASSERT("require_RC4", torrent::ConnectionManager::encryption_require_RC4);
FLAGS_LT_ENCRYPTION_ASSERT("require_RC4 | enable_retry", torrent::ConnectionManager::encryption_require_RC4 | torrent::ConnectionManager::encryption_enable_retry);
FLAGS_LT_ENCRYPTION_ASSERT("", torrent::net::NetworkConfig::encryption_none);
FLAGS_LT_ENCRYPTION_ASSERT("none", torrent::net::NetworkConfig::encryption_none);
FLAGS_LT_ENCRYPTION_ASSERT("require_rc4", torrent::net::NetworkConfig::encryption_require_RC4);
FLAGS_LT_ENCRYPTION_ASSERT("require_RC4", torrent::net::NetworkConfig::encryption_require_RC4);
FLAGS_LT_ENCRYPTION_ASSERT("require_RC4 | enable_retry", torrent::net::NetworkConfig::encryption_require_RC4 | torrent::net::NetworkConfig::encryption_enable_retry);
FLAGS_LT_ENCRYPTION_ASSERT_ERROR("require_");
}