Compare commits

...

116 Commits

Author SHA1 Message Date
Xirvik Support 49625ab5e5 rpc: close SCGI task on EPIPE to stop event_write() busy-loop
When an SCGI client closes the connection before rtorrent finishes sending
the response, send() in SCgiTask::event_write() returns -1 with errno EPIPE.
EPIPE was grouped with EAGAIN/EINTR as a non-fatal retry-later condition, so
the task was not closed and its descriptor stayed registered for EPOLLOUT. A
broken socket is reported writable immediately, so epoll_wait() returns it on
every iteration and the SCGI thread spins at 100% CPU on one core
indefinitely. The dead connection fd is also leaked (stays ESTAB).

EPIPE is terminal here, not retryable: the peer is gone and the response can
never be delivered. Close the task on EPIPE, matching event_read(), which
already closes on any recv() error other than EAGAIN/EINTR.

Reproduction: open the SCGI socket, send a complete RPC request, then
shutdown(SHUT_RDWR)/close before reading the reply. Stock: the rtorrent-scgi
thread goes to 100% CPU and the connection leaks. With this change: CPU stays
at 0% and the descriptor is closed.
2026-06-04 10:41:19 +02:00
Jari Sundell cc15e9308a Fixed xmlrpc-c build errors and added better github workflow for unit-tests. 2026-06-04 17:16:47 +09:00
Jari Sundell a5a96236df Moved base64 transform and validation functions. 2026-06-04 06:37:01 +09:00
Jari Sundell f1cfe8ad72 Added hex to Object and string_utf8. 2026-06-04 04:22:16 +09:00
rakshasa d0fc48cf7b Tagged release 0.16.13. 2026-06-03 10:18:25 +02:00
trim21 5725eb3773 fix: move --without-ncurses logic to scripts/checks.m4 per review
- Add TORRENT_WITHOUT_NCURSES macro in scripts/checks.m4
- Clear CURSES_LIBS/CFLAGS in the macro instead of if/else in configure.ac
- Restore simple LIBS/CFLAGS lines in configure.ac
- Add missing set_escdelay stub
2026-06-01 20:33:39 +02:00
trim21 ca706c21c0 feat: add --without-ncurses option for daemon-only builds
Add a dummy curses stub header that provides all ncurses types, macros,
and no-op function stubs. When configured with --without-ncurses, the
build uses this stub instead of linking to the real ncurses library.

This allows rtorrent to be built for daemon-only usage (e.g. with
ruTorrent or Flood) without requiring ncurses to be installed.

Closes #1613
2026-06-01 20:33:39 +02:00
Jari Sundell 14edd68653 Removed SignalBitfield and replaced it with callbacks. 2026-06-01 22:40:22 +09:00
Jari Sundell 50a609ade9 Fixed cacheline size check. 2026-06-01 20:11:02 +09:00
Jari Sundell 2cf8f2351b Fixed github workflow. 2026-05-31 00:37:22 +09:00
Jari Sundell add305f90c Added support base64 support for non-UTF8 strings. 2026-05-30 00:25:16 +09:00
Jari Sundell 880510073a Updated LUA autoconf script. 2026-05-27 21:37:09 +09:00
rakshasa 0989b2218d Various cleanup and fixes to SocketManager categories. 2026-05-27 12:38:52 +02:00
Trim21 3d7e6cb077 Added per-category allocation limits to SocketManager by @trim21 2026-05-27 18:16:02 +09:00
Jari Sundell 64881317c6 Fix RPC/SCGI security and crash bugs by @sirus20x6 2026-05-26 17:27:10 +09:00
rakshasa a5ecd89a54 Removed unnessesary configure check from PR. 2026-05-25 18:21:31 +02:00
tonimelisma 84229a85be Add directory.watch.ready for safe torrent watch folders 2026-05-25 18:21:31 +02:00
Jari Sundell e03ab27cf0 Added intermediate requesting flag for trackers to prevent premature deletion. 2026-05-26 00:43:15 +09:00
Jari Sundell e41b066555 Converted callbacks to new interface. 2026-05-25 20:13:45 +09:00
Jari Sundell 8318133c79 Added a new callback mechanism and use it for trackers. 2026-05-23 23:43:45 +09:00
rakshasa 088bf40bdf Removed obsolete use of trackers.use_udp. 2026-05-18 16:35:20 +02:00
rakshasa 2f7a984992 Tagged release 0.16.12. 2026-05-18 15:25:56 +02:00
Jari Sundell 840a57915e Deprecate trackers.use_udp as it is no longer needed. 2026-05-17 00:59:03 +09:00
Jari Sundell 5e211c3a28 Allow for quick shutdown after sending the first UDP announce packet. 2026-05-15 20:58:17 +09:00
Jari Sundell 797a194abc Cleaned up torrent header files. 2026-05-14 19:24:38 +09:00
Trim21 501853cfbc Delete repro-scgi-content-type.py 2026-05-11 11:42:36 +02:00
trim21 b0ef95592b fix SCGI parse_headers: defer content-type body peek until body received
detect_content_type() peeked at m_buffer[m_body] to infer JSON vs XML
when no CONTENT_TYPE header was provided.  When the TCP header segment
arrives without any body bytes, m_body equals m_position and the peek
reads the null terminator padding byte — not the actual '{' or '[' —
causing JSON requests to be incorrectly classified as XML and fail.

Fix:
 - Remove the body peek from detect_content_type(); defer it to after
   the full body is confirmed present in event_read().
 - Add a m_content_type_set flag to distinguish header-provided type
   from auto-detected type.
2026-05-11 11:42:36 +02:00
Miroslav Marchev 26a7e9f545 Update to version 11.0.0 2026-05-10 09:25:02 +02:00
Miroslav Marchev 0ed10984b3 Update to version 11.0.0 2026-05-10 09:25:02 +02:00
Miroslav Marchev 5f09bb74de Updated to version 3.12.0 2026-05-10 09:25:02 +02:00
Jari Sundell c368b2de1e Fix SCGI event_read: return on partial header read instead of closing connection @trim21 2026-05-10 16:01:45 +09:00
Jari Sundell 71ac256cb5 Moved socket counter to runtime::SocketManager. 2026-05-10 02:11:35 +09:00
rakshasa b05b65bd65 Enable SCGI compression by default and set min size to 1000. 2026-05-09 12:24:24 +02:00
Jari Sundell f05b48e228 Moved NetworkConfig to runtime. 2026-05-05 16:17:24 +09:00
Xirvik 1279bd9f7a Move d.save_full_session to run after user-registered inserted_new handlers
Previously d.save_full_session was inside the 1_prepare handler for
event.download.inserted_new. Since 0.16.6 moved session saving to a
separate thread, save_full_download() snapshots the bencode synchronously
when called and queues the prebuilt streams for async write.

If user-registered handlers (e.g. seedingtime plugin's addtime setter
running d.set_custom=addtime) sort lexicographically AFTER 1_prepare, they
modify the bencode AFTER the snapshot has already been taken. The first
on-disk .rtorrent then lacks those custom fields. The next periodic
resume save catches up, but if rtorrent restarts before that, the data
is lost — manifesting as blank Finished/SeedingTime columns in ruTorrent.

Fix: split the inserted_new key into two — 1_prepare keeps view
visibility setup, ~_save_full runs d.save_full_session last (~ prefix
is ASCII 0x7E, sorts after all alphanumerics, matching the existing
~_delete_tied precedent on event.download.erased). The snapshot then
includes any custom fields written by user handlers.
2026-05-05 08:40:13 +02:00
Xirvik 981184574d Reset SCgiTask m_trusted on connection reuse
SCgiTask objects are pre-allocated in a pool (scgi.cc) and reused across
SCGI connections. SCgiTask::open() did not reset m_trusted, so when a
task that had handled an untrusted connection (m_trusted=false) was
reused for a new connection, m_trusted stayed false unless the new
connection explicitly sent UNTRUSTED_CONNECTION=1.

The header parser only set m_trusted=false on value 1 and was a no-op
on value 0 (the comment said "default is trusted, so do nothing") —
which is wrong for a reused task that is no longer in default state.

This caused intermittent rejection of trusted commands (e.g. ruTorrent
calling execute.capture for UID detection) with "Command X is not allowed
for untrusted connections", producing cascading plugin failures and
"ruTorrent cannot determine the UID of rTorrent user" in the web UI.

Fix:
- SCgiTask::open() resets m_trusted=true to default.
- parse_headers explicitly sets m_trusted=true on UNTRUSTED_CONNECTION=0,
  so the value sent on the wire is authoritative regardless of pool
  reuse semantics.

Verified on gb4 with rtorrent 0.16.11 + this fix: 30/30 trusted calls
succeed, 30/30 untrusted correctly blocked, 30/30 trusted-after-untrusted
batch all succeed (previously 70%+ would fail in the same scenario).
2026-05-04 10:06:48 +02:00
rakshasa 2700b3141f Tagged release 0.16.11. 2026-05-01 11:29:09 +02:00
fffe 4fec56a243 assert valid read_length 2026-04-24 12:22:34 +02:00
fffe dcf24711ef refactor 2026-04-24 12:22:34 +02:00
fffe 4e3ad1ab62 fix off-by-one in SCgiTask::event_read 2026-04-24 12:22:34 +02:00
rakshasa b5a606649a Tagged release 0.16.10. 2026-04-23 10:31:51 +02:00
Jari Sundell eb96876eb2 Moved Thread header to torrent/system directory. 2026-04-22 23:02:05 +09:00
Jari Sundell a964b0a350 Added special syntax to config files to enable log categories early. 2026-04-20 01:07:38 +09:00
Jari Sundell 1adcf230d2 Fix core subsystem logic and safety bugs @Sirus20x6 2026-04-18 01:54:46 +09:00
rakshasa 4235507292 Fixed path expand when doing a single '~' when expanding directory entries. 2026-04-17 12:13:27 +02:00
Jari Sundell b7a21b1e9d Added support for gzip accepted_encoding in scgi headers. 2026-04-12 22:19:49 +09:00
Jari Sundell bd53959b40 Fixed session save getting stuck. 2026-04-11 16:50:58 +09:00
Jari Sundell 5a4ba8bc32 Removed deprecated rak header files. 2026-04-10 22:04:02 +09:00
Jari Sundell e64ec358fa Removed deprecated rak headers. 2026-04-10 03:49:38 +09:00
rakshasa b78fd9aef5 Tagged release 0.16.9. 2026-04-06 15:19:27 +02:00
rakshasa 21e399d099 Remove unneeded MSG_NOSIGNAL. 2026-04-06 10:48:35 +02:00
Xirvik 08a907b547 Whitelist additional read-only getters for untrusted connections
ruTorrent queries these commands for its settings and status pages.
They are all read-only getters with no side effects, safe to expose
for untrusted SCGI connections.

Tested against ruTorrent with both httprpc and multirpc plugins on
servers with active torrents — all modes (list, settings, totals,
open connections) work with zero blocked commands.
2026-03-30 11:55:24 +02:00
zqmfb a0b8702895 Address additional review feedback 2026-03-27 17:48:13 +01:00
zqmfb ad3c31862e Further clarify systemd socket selection 2026-03-27 17:48:13 +01:00
zqmfb 2711e4c044 Use libtorrent's fd_set_nonblock helper 2026-03-27 17:48:13 +01:00
zqmfb 8d50aee96f Add network.scgi.open_systemd command unconditionally 2026-03-27 17:48:13 +01:00
zqmfb 71bb51c3fd Clarify systemd socket selection logic 2026-03-27 17:48:13 +01:00
zqmfb 63ea08bde6 Add support for SCGI systemd socket activation
Add a new command, `network.scgi.open_systemd`, that binds to a file
descriptor passed in via systemd socket activation.
2026-03-27 17:48:13 +01:00
Xirvik Support a82bdf22ac Review fix: remove method.use_deprecated.set from untrusted whitelist 2026-03-23 15:11:07 +01:00
Xirvik 9f6731b4e2 Address review: tighten untrusted safelist and remove set_trusted 2026-03-23 15:11:07 +01:00
Xirvik d935e0ffe9 Address review feedback: explicit mark_safe whitelist and rpc trust flow 2026-03-23 15:11:07 +01:00
Xirvik ba239bc8c5 Address code review: fix setter exposure and narrow catch blocks
1. network.rpc.use_xmlrpc and network.rpc.use_jsonrpc: change from
   CMD2_VAR_BOOL_U (getter+setter both safe) to CMD2_VAR_BOOL_U_GET
   (getter safe, setter trusted-only). Untrusted callers could
   previously disable RPC transports entirely.

2. Remove broad catch(std::exception&) and catch(...) from xmlrpc_c.cc
   that masked real defects and altered fault semantics.

3. Revert SCGI callback catch-all to re-throw instead of swallowing
   exceptions with a generic error response.
2026-03-23 15:11:07 +01:00
Xirvik ea16276773 Fix crash on untrusted XMLRPC connections
Root cause: network.rpc.use_xmlrpc and network.rpc.use_jsonrpc were not
marked as untrusted-safe, but RpcManager::process() calls them before
dispatching to the protocol handler. When an untrusted request arrived,
call_command() threw untrusted_error for these gatekeepers, which escaped
the callback_interrupt_pollling callback and crashed rtorrent.

Fix: Mark network.rpc.use_xmlrpc/jsonrpc as safe (CMD2_VAR_BOOL_U).

Also harden exception safety:
- SCGI callback catch-all now sends a generic error response instead of
  re-throwing, since the callback infrastructure may not support
  exception propagation.
- xmlrpc_c.cc now has catch(std::exception&) and catch(...) safety nets
  after the specific exception handlers.
2026-03-23 15:11:07 +01:00
Xirvik f767053297 Mark safe commands with flag_untrusted_safe for whitelist enforcement
Annotate all commands that web UIs (ruTorrent) need for normal torrent
management with _U macro variants, which set flag_untrusted_safe.
Commands not marked are blocked by default for untrusted connections.

Safe commands include:
- d.* download getters, state, priorities, custom fields, start/stop
- f.* file getters, priority control
- p.* peer getters, disconnect, ban/snub
- t.* tracker getters, enable/disable
- throttle.* rate getters/setters, peer limits
- network.* read-only queries (getters safe, setters blocked)
- view.list, view.size, view.filter_all, ui.current_view
- load.*, download_list, d.multicall2, d.multicall.filtered
- convert.*, branch/if/and/or/not/cat/value/print
- system.* version/time/status queries (read-only)
- choke_group.* read-only queries
- method.has_key, method.const, method.list_keys, method.get, strings.*
- group.*.view, group.*.ratio.min/max/upload (dynamic, via flag propagation)

Blocked by default (not marked):
- execute*, method.insert/set/redirect, schedule*, import
- log.*, file.append, network.scgi.open_*, view.filter/sort/event_*
- system.shutdown, system.env, group.insert, choke_group.insert
- All user-defined commands (via method.insert)
2026-03-23 15:11:07 +01:00
Xirvik 598914908f Add untrusted connection security infrastructure (v3)
Replace the v2 blacklist approach with a per-command flag system.
Commands must opt in to being available for untrusted connections
via flag_untrusted_safe (0x400), checked in call_command() which
catches all execution paths including nested commands.

Infrastructure changes:
- Add flag_untrusted_safe to CommandMap
- Add untrusted_error exception type for proper error codes
- Enforce trust check in both call_command() overloads
- Add catch blocks in xmlrpc_c, xmlrpc_tinyxml2, and jsonrpc handlers
- Port SCGI trust state management from v2 (thread_local, header parsing)
- Add _U macro variants in command_helpers.h for safe command registration
- Add CMD2_VAR_*_U and CMD2_VAR_*_U_GET variants for variables
2026-03-23 15:11:07 +01:00
rakshasa 38fc815d52 Fix display/UI crash and correctness bugs (@sirus20x6) 2026-03-16 16:08:52 +01:00
Jari Sundell 674ae767aa Validate parsed int pair arguments for positivity 2026-03-16 13:56:43 +01:00
sirus20x6 0aaa470053 Fix resource leaks and minor issues
- Close pipe fds on fork failure in ExecFile::execute
- Add exception-safe fclose in cmd_file_append via try/catch
- Add overflow guards before K/M/G bit shifts in parse_whole_value
- Fix %u format for int* in sscanf (change to %d)
- Fix typo "atter"→"after" in error message
2026-03-16 13:56:43 +01:00
PiloUnk 6f27159627 Refactor full save scheduling with early return 2026-03-16 13:29:33 +01:00
PiloUnk de163293ab Avoid missing save scheduling after full save update 2026-03-16 13:29:33 +01:00
PiloUnk fb4e775689 Fix coalescing resume saves with pending full save 2026-03-16 13:29:33 +01:00
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
160 changed files with 5976 additions and 4567 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
permissions:
pull-requests: write
# OPTIONAL: auto-closing conversations requires the `contents` permission
contents: write
contents: read
steps:
- name: Sleep for 30 seconds
run: sleep 30s
+2 -1
View File
@@ -16,7 +16,8 @@ jobs:
sudo apt-get install -y \
bear \
clang-tidy \
libcurl4-openssl-dev
libcurl4-openssl-dev \
zlib1g-dev
- name: Fetch libtorrent
run: |
git clone https://github.com/rakshasa/libtorrent
+64 -27
View File
@@ -4,9 +4,8 @@ on: pull_request
jobs:
unit-tests:
ubuntu-base:
runs-on: ubuntu-22.04
steps:
- name: Update Packages
run: |
@@ -15,6 +14,7 @@ jobs:
run: |
sudo apt-get install -y \
libcppunit-dev \
zlib1g-dev \
libcurl4-openssl-dev
- name: Fetch libtorrent
run: |
@@ -22,43 +22,80 @@ jobs:
- name: Build libtorrent
run: |
cd libtorrent
libtoolize
aclocal -I scripts
autoconf -i
autoheader
automake --add-missing
autoreconf -fiv
./configure
make
sudo make install
cd ..
rm -rf libtorrent
- uses: actions/checkout@v4
sudo make install DESTDIR=$GITHUB_WORKSPACE/libtorrent-dist
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Fetch base branch
name: installed-libtorrent
path: libtorrent-dist/
unit-tests-default:
runs-on: ubuntu-22.04
needs: ubuntu-base
steps:
- name: Install Dependencies
run: |
git remote add upstream "https://github.com/${{ github.event.pull_request.base.repo.full_name }}"
git fetch --no-tags --no-recurse-submodules upstream "${{ github.event.pull_request.base.ref }}"
sudo apt-get install -y \
libcppunit-dev \
zlib1g-dev \
libcurl4-openssl-dev
- name: Download Libtorrent Artifacts
uses: actions/download-artifact@v4
with:
name: installed-libtorrent
path: ./libtorrent-dist
- name: Move Artifacts to System Path
run: |
# Elevate permissions with sudo to safely place the files
sudo cp -r ./libtorrent-dist/usr/local/* /usr/local/
rm -rf ./libtorrent-dist
- uses: actions/checkout@v4
- name: Configure Project
run: |
libtoolize
aclocal -I scripts
autoconf -i
autoheader
automake --add-missing
autoreconf -fiv
./configure
- name: Build Project
run: |
make
- name: Run Unit Tests
run: |
ls /usr/local/lib/
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
make check
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib" make check
- name: Archive test/test-suite.log
if: success() || failure()
uses: actions/upload-artifact@v4
with:
name: test-suite.log
path: test/test-suite.log
unit-tests-variants:
runs-on: ubuntu-22.04
needs: unit-tests-default
strategy:
matrix:
config_flag: ["--with-xmlrpc-c", "--with-xmlrpc-tinyxml2"]
steps:
- name: Install Dependencies
run: |
sudo apt-get install -y \
libcppunit-dev \
zlib1g-dev \
libcurl4-openssl-dev \
libxmlrpc-c++8-dev
- name: Download Libtorrent Artifacts
uses: actions/download-artifact@v4
with:
name: installed-libtorrent
path: ./libtorrent-dist
- name: Move Artifacts to System Path
run: |
sudo cp -r ./libtorrent-dist/usr/local/* /usr/local/
rm -rf ./libtorrent-dist
- uses: actions/checkout@v4
- name: Configure Project
run: |
autoreconf -fiv
./configure ${{ matrix.config_flag }}
make
ls /usr/local/lib/
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib" make check
+2
View File
@@ -18,6 +18,7 @@
.libs
Makefile
aclocal.m4
actmp.*
ar-lib
autom4te.cache
compile
@@ -69,4 +70,5 @@ TAGS
###########################
src/rtorrent
test/rtorrent_Test*
test/test-suite.log.tmp
test-driver
-8
View File
@@ -7,15 +7,7 @@ nobase_dist_pkgdata_DATA = \
lua/rtorrent.lua
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/string_manip.h \
rak/unordered_vector.h \
scripts/checks.m4 \
scripts/common.m4 \
scripts/attributes.m4
+23 -12
View File
@@ -1,6 +1,6 @@
m4_pattern_allow([PKG_CHECK_EXISTS])
AC_INIT([rtorrent],[0.16.1],[sundell.software@gmail.com])
AC_INIT([rtorrent],[0.16.13],[sundell.software@gmail.com])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIRS([scripts])
@@ -11,12 +11,12 @@ LT_INIT
AC_PROG_CXX
AC_DEFINE([API_VERSION], [17], [api version])
AC_DEFINE([API_VERSION], [21], [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)
AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory])
AX_CXX_COMPILE_STDCXX(20, noext, mandatory)
AC_SYS_LARGEFILE
@@ -41,35 +41,46 @@ AC_ARG_ENABLE(execinfo,
])
AX_PTHREAD([], AC_MSG_ERROR([requires pthread]))
AX_WITH_CURSES
if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
TORRENT_WITHOUT_NCURSES
if test "x$with_ncurses" != xno; then
AX_WITH_CURSES
if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
AC_MSG_ERROR([requires either NcursesW or Ncurses library])
fi
fi
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.1])
PKG_CHECK_MODULES([ZLIB], [zlib])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.13])
AC_LANG_PUSH(C++)
TORRENT_WITH_XMLRPC_C
AC_LANG_POP(C++)
dnl We don't have LuaJIT support, and the script breaks if not disabled.
AM_CONDITIONAL([LUAJIT], [false])
TORRENT_WITH_LUA
TORRENT_WITH_TINYXML2
TORRENT_WITH_SYSTEMD
if test ${with_xmlrpc_c+y} && test ${with_xmlrpc_tinyxml2+y}; then
AC_MSG_ERROR([--with-xmlrpc-c and --with-xmlrpc-tinyxml2 cannot be used together. Please choose only one])
fi
AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION "/") + torrent::version()], Http user agent)
AC_DEFINE(USER_AGENT, [std::string(PACKAGE "/" VERSION)], Http user agent)
dnl Only update global build variables immediately before generating the output,
dnl to avoid affecting the global build environment for other autoconf checks.
LIBS="$PTHREAD_LIBS $CURSES_LIB $CURSES_LIBS $DEPENDENCIES_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
LIBS="$PTHREAD_LIBS $CURSES_LIB $CURSES_LIBS $ZLIB_LIBS $DEPENDENCIES_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS $ZLIB_CFLAGS $DEPENDENCIES_CFLAGS"
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $CURSES_CFLAGS $ZLIB_CFLAGS $DEPENDENCIES_CFLAGS"
TORRENT_CHECK_POPCOUNT()
TORRENT_CHECK_CACHELINE
TORRENT_CHECK_POPCOUNT
AC_CONFIG_FILES([
Makefile
+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.
+5 -1
View File
@@ -46,8 +46,12 @@
#session.path.set = ./session
# Watch a directory for new torrents, and stop those that have been
# deleted.
# deleted. Use directory.watch.ready for network shares or other watch
# directories where files may be copied or written directly into place.
# Do not mix directory.watch.ready and directory.watch.added on the same
# watch directory.
#
#directory.watch.ready = ./watch, load.start
#schedule2 = watch_directory,5,5,load.start=./watch/*.torrent
# Close torrents when disk-space is low.
+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
}
-60
View File
@@ -1,60 +0,0 @@
// Wrapper for addrinfo with focus on zero-copy conversion to and from
// the c-type and wrapper.
//
// Do use the wrapper on a pre-existing struct addrinfo, cast the
// pointer rather than the base type.
#ifndef RAK_ADDRESS_INFO_H
#define RAK_ADDRESS_INFO_H
#include <netdb.h>
#include <cstring>
namespace rak {
class address_info {
public:
void clear() { std::memset(this, 0, sizeof(address_info)); }
int flags() const { return m_addrinfo.ai_flags; }
void set_flags(int f) { m_addrinfo.ai_flags = f; }
int family() const { return m_addrinfo.ai_family; }
void set_family(int f) { m_addrinfo.ai_family = f; }
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; }
addrinfo* c_addrinfo() { return &m_addrinfo; }
const addrinfo* c_addrinfo() const { return &m_addrinfo; }
address_info* next() { return reinterpret_cast<address_info*>(m_addrinfo.ai_next); }
static int get_address_info(const char* node, int domain, int type, address_info** ai);
static void free_address_info(address_info* ai) { ::freeaddrinfo(ai->c_addrinfo()); }
static const char* strerror(int err) { return gai_strerror(err); }
private:
addrinfo m_addrinfo;
};
inline int
address_info::get_address_info(const char* node, int pfamily, int stype, address_info** ai) {
address_info hints;
hints.clear();
hints.set_family(pfamily);
hints.set_socket_type(stype);
return ::getaddrinfo(node, NULL, hints.c_addrinfo(), reinterpret_cast<addrinfo**>(ai));
}
}
#endif
-195
View File
@@ -1,195 +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_ALGORITHM_H
#define RAK_ALGORITHM_H
#include <algorithm>
#include <limits>
namespace rak {
template <typename _InputIter, typename _Function>
_Function
for_each_pre(_InputIter __first, _InputIter __last, _Function __f) {
_InputIter __tmp;
while (__first != __last) {
__tmp = __first++;
__f(*__tmp);
}
return __f;
}
// Return a range with a distance of no more than __distance and
// between __first and __last, centered on __middle1.
template <typename _InputIter, typename _Distance>
std::pair<_InputIter, _InputIter>
advance_bidirectional(_InputIter __first, _InputIter __middle1, _InputIter __last, _Distance __distance) {
_InputIter __middle2 = __middle1;
do {
if (!__distance)
break;
if (__middle2 != __last) {
++__middle2;
--__distance;
} else if (__middle1 == __first) {
break;
}
if (!__distance)
break;
if (__middle1 != __first) {
--__middle1;
--__distance;
} else if (__middle2 == __last) {
break;
}
} while (true);
return std::make_pair(__middle1, __middle2);
}
template <typename _InputIter, typename _Distance>
_InputIter
advance_forward(_InputIter __first, _InputIter __last, _Distance __distance) {
while (__first != __last && __distance != 0) {
__first++;
__distance--;
}
return __first;
}
template <typename _InputIter, typename _Distance>
_InputIter
advance_backward(_InputIter __first, _InputIter __last, _Distance __distance) {
while (__first != __last && __distance != 0) {
__first--;
__distance--;
}
return __first;
}
template <typename _Value>
struct compare_base {
bool operator () (const _Value& complete, const _Value& base) const {
return !complete.compare(0, base.size(), base);
}
};
// Count the number of elements from the start of the containers to
// the first inequal element.
template <typename _InputIter1, typename _InputIter2>
typename std::iterator_traits<_InputIter1>::difference_type
count_base(_InputIter1 __first1, _InputIter1 __last1,
_InputIter2 __first2, _InputIter2 __last2) {
typename std::iterator_traits<_InputIter1>::difference_type __n = 0;
for ( ;__first1 != __last1 && __first2 != __last2; ++__first1, ++__first2, ++__n)
if (*__first1 != *__first2)
return __n;
return __n;
}
template <typename _Return, typename _InputIter, typename _Ftor>
_Return
make_base(_InputIter __first, _InputIter __last, _Ftor __ftor) {
if (__first == __last)
return "";
_Return __base = __ftor(*__first++);
for ( ;__first != __last; ++__first) {
typename std::iterator_traits<_InputIter>::difference_type __pos = count_base(__base.begin(), __base.end(),
__ftor(*__first).begin(), __ftor(*__first).end());
if (__pos < (typename std::iterator_traits<_InputIter>::difference_type)__base.size())
__base.resize(__pos);
}
return __base;
}
template<typename T>
inline int popcount_wrapper(T t) {
#if USE_BUILTIN_POPCOUNT
return __builtin_popcountll(t);
#else
#error __builtin_popcount not found.
unsigned int count = 0;
while (t) {
count += t & 0x1;
t >> 1;
}
return count;
#endif
}
// Get the median of an unordered set of numbers of arbitrary
// type by modifing the underlying dataset
template <typename T = double, typename _InputIter>
T median(_InputIter __first, _InputIter __last) {
T __med;
unsigned int __size = __last - __first;
unsigned int __middle = __size / 2;
_InputIter __target1 = __first + __middle;
std::nth_element(__first, __target1, __last);
__med = *__target1;
if (__size % 2 == 0) {
_InputIter __target2 = std::max_element(__first, __target1);
__med = (__med + *__target2) / 2.0;
}
return __med;
}
}
#endif
-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
-197
View File
@@ -1,197 +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_PARTIAL_QUEUE_H
#define RAK_PARTIAL_QUEUE_H
#include <array>
#include <cstring>
#include <stdexcept>
#include <cinttypes>
namespace rak {
// First step, don't allow overflowing to the next layer. Only disable
// the above layers for now.
// We also include 0 in a single layer as some chunk may be available
// only through seeders.
class partial_queue {
public:
typedef uint8_t key_type;
typedef uint32_t mapped_type;
typedef uint16_t size_type;
typedef std::pair<size_type, size_type> size_pair_type;
static const size_type num_layers = 8;
partial_queue() : m_data(NULL), m_maxLayerSize(0) {}
~partial_queue() { disable(); }
bool is_full() const { return m_ceiling == 0; }
bool is_layer_full(size_type l) const { return m_layers[l].second >= m_maxLayerSize; }
bool is_enabled() const { return m_data != NULL; }
// Add check to see if we can add more. Also make it possible to
// check how full we are in the lower parts so the caller knows when
// he can stop searching.
//
// Though propably not needed, as we must continue til the first
// layer is full.
size_type max_size() const { return m_maxLayerSize * num_layers; }
size_type max_layer_size() const { return m_maxLayerSize; }
// Must be less that or equal to (max size_type) / num_layers.
void enable(size_type ls);
void disable();
void clear();
// Safe to call while pop'ing and it will not reuse pop'ed indices
// so it is guaranteed to reach max_size at some point. This will
// ensure that the user needs to refill with new data at regular
// intervals.
bool insert(key_type key, mapped_type value);
// Only call this when pop'ing as it moves the index.
bool prepare_pop();
mapped_type pop();
private:
partial_queue(const partial_queue&);
void operator = (const partial_queue&);
static size_type ceiling(size_type layer) { return (2 << layer) - 1; }
void find_non_empty();
mapped_type* m_data;
size_type m_maxLayerSize;
size_type m_index;
size_type m_ceiling;
std::array<size_pair_type, num_layers> m_layers;
};
inline void
partial_queue::enable(size_type ls) {
if (ls == 0)
throw std::logic_error("partial_queue::enable(...) ls == 0.");
delete [] m_data;
m_data = new mapped_type[ls * num_layers];
m_maxLayerSize = ls;
}
inline void
partial_queue::disable() {
delete [] m_data;
m_data = NULL;
m_maxLayerSize = 0;
}
inline void
partial_queue::clear() {
if (m_data == NULL)
return;
m_index = 0;
m_ceiling = ceiling(num_layers - 1);
m_layers = {};
}
inline bool
partial_queue::insert(key_type key, mapped_type value) {
if (key >= m_ceiling)
return false;
size_type idx = 0;
// Hmm... since we already check the 'm_ceiling' above, we only need
// to find the target layer. Could this be calculated directly?
while (key >= ceiling(idx))
++idx;
m_index = std::min(m_index, idx);
// Currently don't allow overflow.
if (is_layer_full(idx))
throw std::logic_error("partial_queue::insert(...) layer already full.");
//return false;
m_data[m_maxLayerSize * idx + m_layers[idx].second] = value;
m_layers[idx].second++;
if (is_layer_full(idx))
// Set the ceiling to 0 when layer 0 is full so no more values can
// be inserted.
m_ceiling = idx > 0 ? ceiling(idx - 1) : 0;
return true;
}
// is_empty() will iterate to the first layer with un-popped elements
// and return true, else return false when it reaches a overflowed or
// the last layer.
inline bool
partial_queue::prepare_pop() {
while (m_layers[m_index].first == m_layers[m_index].second) {
if (is_layer_full(m_index) || m_index + 1 == num_layers)
return false;
m_index++;
}
return true;
}
inline partial_queue::mapped_type
partial_queue::pop() {
if (m_index >= num_layers || m_layers[m_index].first >= m_layers[m_index].second)
throw std::logic_error("partial_queue::pop() bad state.");
return m_data[m_index * m_maxLayerSize + m_layers[m_index].first++];
}
}
#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
-425
View File
@@ -1,425 +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_STRING_MANIP_H
#define RAK_STRING_MANIP_H
#include <algorithm>
#include <cctype>
#include <climits>
#include <cstdlib>
#include <functional>
#include <iterator>
#include <locale>
#include <random>
namespace rak {
// Use these trim functions until n1872 is widely supported.
template <typename Sequence>
Sequence trim_begin(const Sequence& seq) {
if (seq.empty() || !std::isspace(*seq.begin()))
return seq;
typename Sequence::size_type pos = 0;
while (pos != seq.length() && std::isspace(seq[pos]))
pos++;
return seq.substr(pos, seq.length() - pos);
}
template <typename Sequence>
Sequence trim_end(const Sequence& seq) {
if (seq.empty() || !std::isspace(*(--seq.end())))
return seq;
typename Sequence::size_type pos = seq.size();
while (pos != 0 && std::isspace(seq[pos - 1]))
pos--;
return seq.substr(0, pos);
}
template <typename Sequence>
Sequence trim(const Sequence& seq) {
return trim_begin(trim_end(seq));
}
template <typename Sequence>
Sequence trim_begin_classic(const Sequence& seq) {
if (seq.empty() || !std::isspace(*seq.begin(), std::locale::classic()))
return seq;
typename Sequence::size_type pos = 0;
while (pos != seq.length() && std::isspace(seq[pos], std::locale::classic()))
pos++;
return seq.substr(pos, seq.length() - pos);
}
template <typename Sequence>
Sequence trim_end_classic(const Sequence& seq) {
if (seq.empty() || !std::isspace(*(--seq.end()), std::locale::classic()))
return seq;
typename Sequence::size_type pos = seq.size();
while (pos != 0 && std::isspace(seq[pos - 1], std::locale::classic()))
pos--;
return seq.substr(0, pos);
}
template <typename Sequence>
Sequence trim_classic(const Sequence& seq) {
return trim_begin_classic(trim_end_classic(seq));
}
// Consider rewritting such that m_seq is replaced by first/last.
template <typename Sequence>
class split_iterator_t {
public:
typedef typename Sequence::const_iterator const_iterator;
typedef typename Sequence::value_type value_type;
split_iterator_t() {}
split_iterator_t(const Sequence& seq, value_type delim) :
m_seq(&seq),
m_delim(delim),
m_pos(seq.begin()),
m_next(std::find(seq.begin(), seq.end(), delim)) {
}
Sequence operator * () { return Sequence(m_pos, m_next); }
split_iterator_t& operator ++ () {
m_pos = m_next;
if (m_pos == m_seq->end())
return *this;
m_pos++;
m_next = std::find(m_pos, m_seq->end(), m_delim);
return *this;
}
bool operator == (const split_iterator_t&) const { return m_pos == m_seq->end(); }
bool operator != (const split_iterator_t&) const { return m_pos != m_seq->end(); }
private:
const Sequence* m_seq;
value_type m_delim;
const_iterator m_pos;
const_iterator m_next;
};
template <typename Sequence>
inline split_iterator_t<Sequence>
split_iterator(const Sequence& seq, typename Sequence::value_type delim) {
return split_iterator_t<Sequence>(seq, delim);
}
template <typename Sequence>
inline split_iterator_t<Sequence>
split_iterator(const Sequence&) {
return split_iterator_t<Sequence>();
}
// Could optimize this abit.
inline char
hexchar_to_value(char c) {
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'A' && c <= 'F')
return 10 + c - 'A';
else
return 10 + c - 'a';
}
template <int pos, typename Value>
inline char
value_to_hexchar(Value v) {
v >>= pos * 4;
v &= 0xf;
if (v < 0xA)
return '0' + v;
else
return 'A' + v - 0xA;
}
template <typename InputIterator, typename OutputIterator>
OutputIterator
copy_escape_html(InputIterator first, InputIterator last, OutputIterator dest) {
while (first != last) {
if (std::isalpha(*first, std::locale::classic()) ||
std::isdigit(*first, std::locale::classic()) ||
*first == '-') {
*(dest++) = *first;
} else {
*(dest++) = '%';
*(dest++) = value_to_hexchar<1>(*first);
*(dest++) = value_to_hexchar<0>(*first);
}
++first;
}
return dest;
}
template <typename InputIterator, typename OutputIterator>
OutputIterator
copy_escape_html(InputIterator first1, InputIterator last1, OutputIterator first2, OutputIterator last2) {
while (first1 != last1) {
if (std::isalpha(*first1, std::locale::classic()) ||
std::isdigit(*first1, std::locale::classic()) ||
*first1 == '-') {
if (first2 == last2) break; else *(first2++) = *first1;
} else {
if (first2 == last2) break; else *(first2++) = '%';
if (first2 == last2) break; else *(first2++) = value_to_hexchar<1>(*first1);
if (first2 == last2) break; else *(first2++) = value_to_hexchar<0>(*first1);
}
++first1;
}
return first2;
}
template <typename Iterator>
inline std::string
copy_escape_html(Iterator first, Iterator last) {
std::string dest;
copy_escape_html(first, last, std::back_inserter(dest));
return dest;
}
template <typename Sequence>
inline Sequence
copy_escape_html(const Sequence& src) {
Sequence dest;
copy_escape_html(src.begin(), src.end(), std::back_inserter(dest));
return dest;
}
template <typename Sequence>
inline std::string
copy_escape_html_str(const Sequence& src) {
std::string dest;
copy_escape_html(src.begin(), src.end(), std::back_inserter(dest));
return dest;
}
// Consider support for larger than char type.
template <typename InputIterator, typename OutputIterator>
OutputIterator
transform_hex(InputIterator first, InputIterator last, OutputIterator dest) {
while (first != last) {
*(dest++) = value_to_hexchar<1>(*first);
*(dest++) = value_to_hexchar<0>(*first);
++first;
}
return dest;
}
template <typename InputIterator, typename OutputIterator>
OutputIterator
transform_hex(InputIterator first1, InputIterator last1, OutputIterator first2, OutputIterator last2) {
while (first1 != last1) {
if (first2 == last2) break; else *(first2++) = value_to_hexchar<1>(*first1);
if (first2 == last2) break; else *(first2++) = value_to_hexchar<0>(*first1);
++first1;
}
return first2;
}
template <typename Sequence>
inline Sequence
transform_hex(const Sequence& src) {
Sequence dest;
transform_hex(src.begin(), src.end(), std::back_inserter(dest));
return dest;
}
template <typename Iterator>
inline std::string
transform_hex(Iterator first, Iterator last) {
std::string dest;
transform_hex(first, last, std::back_inserter(dest));
return dest;
}
template <typename Sequence>
inline std::string
transform_hex_str(const Sequence& seq) {
std::string dest;
transform_hex(seq.begin(), seq.end(), std::back_inserter(dest));
return dest;
}
template <typename Sequence>
Sequence
generate_random(size_t length) {
std::random_device rd;
std::mt19937 mt(rd());
using bytes_randomizer = std::independent_bits_engine<std::mt19937, CHAR_BIT, uint8_t>;
bytes_randomizer bytes(mt);
Sequence s;
s.reserve(length);
std::generate_n(std::back_inserter(s), length, std::ref(bytes));
return s;
}
template <typename Iterator>
inline bool
is_all_alpha(Iterator first, Iterator last) {
while (first != last)
if (!std::isalpha(*first++, std::locale::classic()))
return false;
return true;
}
template <typename Sequence>
inline bool
is_all_alpha(const Sequence& src) {
return is_all_alpha(src.begin(), src.end());
}
template <typename Iterator>
inline bool
is_all_alnum(Iterator first, Iterator last) {
while (first != last)
if (!std::isalnum(*first++, std::locale::classic()))
return false;
return true;
}
template <typename Sequence>
inline bool
is_all_alnum(const Sequence& src) {
return is_all_alnum(src.begin(), src.end());
}
template <typename Iterator>
inline bool
is_all_name(Iterator first, Iterator last) {
while (first != last) {
if (!std::isalnum(*first, std::locale::classic()) && *first != '_')
return false;
first++;
}
return true;
}
template <typename Sequence>
inline bool
is_all_name(const Sequence& src) {
return is_all_name(src.begin(), src.end());
}
template <typename Iterator>
std::string
sanitize(Iterator first, Iterator last) {
std::string dest;
for (; first != last; ++first) {
if (std::isprint(*first) && *first != '\r' && *first != '\n' && *first != '\t')
dest += *first;
else
dest += " ";
}
return dest;
}
template <typename Sequence>
std::string
sanitize(const Sequence& src) {
return trim(sanitize(src.begin(), src.end()));
}
template <typename Iterator>
std::string striptags(Iterator first, Iterator last) {
bool copychar = true;
std::string dest;
for (; first != last; ++first) {
if (std::isprint(*first) && *first == '<') {
copychar = false;
} else if (std::isprint(*first) && *first == '>') {
copychar = true;
continue;
}
if (copychar)
dest += *first;
}
return dest;
}
template <typename Sequence>
std::string striptags(const Sequence& src) {
return striptags(src.begin(), src.end());
}
}
#endif
-107
View File
@@ -1,107 +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_UNORDERED_VECTOR_H
#define RAK_UNORDERED_VECTOR_H
#include <vector>
namespace rak {
template <typename _Tp>
class unordered_vector : private std::vector<_Tp> {
public:
typedef std::vector<_Tp> Base;
typedef typename Base::value_type value_type;
typedef typename Base::pointer pointer;
typedef typename Base::const_pointer const_pointer;
typedef typename Base::reference reference;
typedef typename Base::const_reference const_reference;
typedef typename Base::size_type size_type;
typedef typename Base::difference_type difference_type;
typedef typename Base::allocator_type allocator_type;
typedef typename Base::iterator iterator;
typedef typename Base::reverse_iterator reverse_iterator;
typedef typename Base::const_iterator const_iterator;
typedef typename Base::const_reverse_iterator const_reverse_iterator;
using Base::clear;
using Base::empty;
using Base::size;
using Base::reserve;
using Base::front;
using Base::back;
using Base::begin;
using Base::end;
using Base::rbegin;
using Base::rend;
using Base::push_back;
using Base::pop_back;
// Use the range erase function, the single element erase gets
// overloaded.
using Base::erase;
iterator insert(iterator position, const value_type& x);
iterator erase(iterator position);
private:
};
template <typename _Tp>
typename unordered_vector<_Tp>::iterator
unordered_vector<_Tp>::insert(iterator position, const value_type& x) {
Base::push_back(x);
return --end();
}
template <typename _Tp>
typename unordered_vector<_Tp>::iterator
unordered_vector<_Tp>::erase(iterator position) {
// We don't need to check if position == end - 1 since we then copy
// to the position we pop later.
*position = Base::back();
Base::pop_back();
return position;
}
}
#endif
+124 -16
View File
@@ -10,8 +10,8 @@
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXX and
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
# or '14' (for the C++14 standard).
# CXXCPP to enable support. VERSION may be '11', '14', '17', '20', or
# '23' for the respective C++ standard version.
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
@@ -36,13 +36,15 @@
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
# Copyright (c) 2020 Jason Merrill <jason@redhat.com>
# Copyright (c) 2021, 2024 Jörn Heusipp <osmanx@problemloesungsmaschine.de>
# Copyright (c) 2015, 2022, 2023, 2024 Olly Betts
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 12
#serial 25
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
@@ -51,6 +53,8 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
[$1], [20], [ax_cxx_compile_alternatives="20"],
[$1], [23], [ax_cxx_compile_alternatives="23"],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
@@ -102,9 +106,18 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
dnl MSVC needs -std:c++NN for C++17 and later (default is C++14)
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do
if test x"$switch" = xMSVC; then
dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide
dnl with -std=c++17. We suffix the cache variable name with _MSVC to
dnl avoid this.
switch=-std:c++${alternative}
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC])
else
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
fi
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
@@ -148,23 +161,44 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
dnl Test body for checking C++11 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11]
)
dnl Test body for checking C++14 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14]
)
dnl Test body for checking C++17 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17]
)
dnl Test body for checking C++20 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20],
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
_AX_CXX_COMPILE_STDCXX_testbody_new_in_20]
)
dnl Test body for checking C++23 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_23],
[_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
_AX_CXX_COMPILE_STDCXX_testbody_new_in_20
_AX_CXX_COMPILE_STDCXX_testbody_new_in_23]
)
dnl Tests for new features in C++11
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
@@ -176,7 +210,21 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
// MSVC always sets __cplusplus to 199711L in older versions; newer versions
// only set it correctly if /Zc:__cplusplus is specified as well as a
// /std:c++NN switch:
//
// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
//
// The value __cplusplus ought to have is available in _MSVC_LANG since
// Visual Studio 2015 Update 3:
//
// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros
//
// This was also the first MSVC version to support C++14 so we can't use the
// value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having
// C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later.
#elif __cplusplus < 201103L && !defined _MSC_VER
#error "This is not a C++11 compiler"
@@ -467,7 +515,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
#error "This is not a C++ compiler"
#elif __cplusplus < 201402L
#elif __cplusplus < 201402L && !defined _MSC_VER
#error "This is not a C++14 compiler"
@@ -591,7 +639,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
#error "This is not a C++ compiler"
#elif __cplusplus < 201703L
#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L
#error "This is not a C++17 compiler"
@@ -957,6 +1005,66 @@ namespace cxx17
} // namespace cxx17
#endif // __cplusplus < 201703L
#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L
]])
dnl Tests for new features in C++20
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L
#error "This is not a C++20 compiler"
#else
#include <version>
namespace cxx20
{
// As C++20 supports feature test macros in the standard, there is no
// immediate need to actually test for feature availability on the
// Autoconf side.
} // namespace cxx20
#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L
]])
dnl Tests for new features in C++23
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_23], [[
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L
#error "This is not a C++23 compiler"
#else
#include <version>
namespace cxx23
{
// As C++23 supports feature test macros in the standard, there is no
// immediate need to actually test for feature availability on the
// Autoconf side.
} // namespace cxx23
#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L
]])
+83 -34
View File
@@ -19,7 +19,7 @@
# header is checked to match the Lua interpreter version exactly. When
# searching for Lua libraries, the version number is used as a suffix.
# This is done with the goal of supporting multiple Lua installs (5.1,
# 5.2, and 5.3 side-by-side).
# 5.2, 5.3, and 5.4 side-by-side).
#
# A note on compatibility with previous versions: This file has been
# mostly rewritten for serial 18. Most developers should be able to use
@@ -49,6 +49,14 @@
# interpreter. If LUA is blank, the user's path is searched for an
# suitable interpreter.
#
# Optionally a LUAJIT option may be set ahead of time to look for and
# validate a LuaJIT install instead of PUC Lua. Usage might look like:
#
# AC_ARG_WITH(luajit, [AS_HELP_STRING([--with-luajit],
# [Prefer LuaJIT over PUC Lua, even if the latter is newer. Default: no])
# ])
# AM_CONDITIONAL([LUAJIT], [test "x$with_luajit" != 'xno'])
#
# If MINIMUM-VERSION is supplied, then only Lua interpreters with a
# version number greater or equal to MINIMUM-VERSION will be accepted. If
# TOO-BIG-VERSION is also supplied, then only Lua interpreters with a
@@ -82,7 +90,7 @@
# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES.
#
# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is
# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT-
# performed, otherwise ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-
# FOUND is blank, then it will default to printing an error. To prevent
# the default behavior, give ':' as an action.
#
@@ -152,6 +160,7 @@
#
# LICENSE
#
# Copyright (c) 2023 Caleb Maclennan <caleb@alerque.com>
# Copyright (c) 2015 Reuben Thomas <rrt@sc3d.org>
# Copyright (c) 2014 Tim Perkins <tprk77@gmail.com>
#
@@ -181,7 +190,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 42
#serial 47
dnl =========================================================================
dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION],
@@ -197,13 +206,14 @@ AC_DEFUN([AX_PROG_LUA],
AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1])
dnl Find a Lua interpreter.
m4_define_default([_AX_LUA_INTERPRETER_LIST],
[lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua50])
AM_COND_IF([LUAJIT],
[_ax_lua_interpreter_list='luajit luajit-2.1.0-beta3 luajit-2.0.5 luajit-2.0.4 luajit-2.0.3'],
[_ax_lua_interpreter_list='lua lua5.4 lua54 lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua5.0 lua50'])
m4_if([$1], [],
[ dnl No version check is needed. Find any Lua interpreter.
AS_IF([test "x$LUA" = 'x'],
[AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])])
[AC_PATH_PROGS([LUA], [$_ax_lua_interpreter_list], [:])])
ax_display_LUA='lua'
AS_IF([test "x$LUA" != 'x:'],
@@ -242,7 +252,7 @@ AC_DEFUN([AX_PROG_LUA],
[_ax_check_text="for a Lua interpreter with version >= $1, < $2"])
AC_CACHE_CHECK([$_ax_check_text],
[ax_cv_pathless_LUA],
[ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do
[ for ax_cv_pathless_LUA in $_ax_lua_interpreter_list none; do
test "x$ax_cv_pathless_LUA" = 'xnone' && break
_AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue])
_AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break])
@@ -268,13 +278,25 @@ AC_DEFUN([AX_PROG_LUA],
ax_cv_lua_version=[`$LUA -e '
-- return a version number in X.Y format
local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)")
print(ver)'`]
print(ver or "")'`]
])
AS_IF([test "x$ax_cv_lua_version" = 'x'],
[AC_MSG_ERROR([invalid Lua version number])])
AC_SUBST([LUA_VERSION], [$ax_cv_lua_version])
AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | $SED 's|\.||'`])
AM_COND_IF([LUAJIT], [
AC_CACHE_CHECK([for $ax_display_LUA jit version], [ax_cv_luajit_version],
[ ax_cv_luajit_version=[`$LUA -e '
local _, _, ver = string.find(jit and jit.version, "(%d+%..+)")
print(ver or "")'`]
])
AS_IF([test "x$ax_cv_luajit_version" = 'x'],
[AC_MSG_ERROR([invalid Lua jit version number])])
AC_SUBST([LUAJIT_VERSION], [$ax_cv_luajit_version])
AC_SUBST([LUAJIT_SHORT_VERSION], [$(echo "$LUAJIT_VERSION" | $SED 's|\.|§|;s|\..*||;s|§|.|')])
])
dnl The following check is not supported:
dnl At times (like when building shared libraries) you may want to know
dnl which OS platform Lua thinks this is.
@@ -464,33 +486,50 @@ AC_DEFUN([AX_LUA_HEADERS],
AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION])
])
AM_COND_IF([LUAJIT],[
dnl Check for LUAJIT_VERSION.
AC_MSG_CHECKING([if LUAJIT_VERSION is defined])
AS_IF([test "x$LUAJIT_VERSION" != 'x'],
[AC_MSG_RESULT([yes])],
[ AC_MSG_RESULT([no])
AC_MSG_ERROR([cannot check Lua jit headers without knowing LUAJIT_VERSION])
])
])
dnl Make LUA_INCLUDE a precious variable.
AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1])
dnl Some default directories to search.
LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'`
m4_define_default([_AX_LUA_INCLUDE_LIST],
[ /usr/include/lua$LUA_VERSION \
/usr/include/lua-$LUA_VERSION \
/usr/include/lua/$LUA_VERSION \
/usr/include/lua$LUA_SHORT_VERSION \
/usr/local/include/lua$LUA_VERSION \
/usr/local/include/lua-$LUA_VERSION \
/usr/local/include/lua/$LUA_VERSION \
/usr/local/include/lua$LUA_SHORT_VERSION \
])
dnl Some default directories to search.
AM_COND_IF([LUAJIT],
[_ax_lua_include_list="
/usr/include/luajit-$LUAJIT_VERSION
/usr/include/luajit-$LUAJIT_SHORT_VERSION
/usr/local/include/luajit-$LUAJIT_VERSION
/usr/local/include/luajit-$LUAJIT_SHORT_VERSION"],
[_ax_lua_include_list="
/usr/include/lua$LUA_VERSION
/usr/include/lua-$LUA_VERSION
/usr/include/lua/$LUA_VERSION
/usr/include/lua$LUA_SHORT_VERSION
/usr/local/include/lua$LUA_VERSION
/usr/local/include/lua-$LUA_VERSION
/usr/local/include/lua/$LUA_VERSION
/usr/local/include/lua$LUA_SHORT_VERSION"])
dnl Try to find the headers.
_ax_lua_saved_cppflags=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
AM_COND_IF([LUAJIT], [AC_CHECK_HEADERS([luajit.h])])
CPPFLAGS=$_ax_lua_saved_cppflags
dnl Try some other directories if LUA_INCLUDE was not set.
AS_IF([test "x$LUA_INCLUDE" = 'x' &&
test "x$ac_cv_header_lua_h" != 'xyes'],
test "x$ac_cv_header_lua_h" != 'xyes' ||
test "x$with_luajit" != 'xno' &&
test "x$ac_cv_header_luajit_h" != 'xyes'],
[ dnl Try some common include paths.
for _ax_include_path in _AX_LUA_INCLUDE_LIST; do
for _ax_include_path in $_ax_lua_include_list; do
test ! -d "$_ax_include_path" && continue
AC_MSG_CHECKING([for Lua headers in])
@@ -500,10 +539,12 @@ AC_DEFUN([AX_LUA_HEADERS],
AS_UNSET([ac_cv_header_lualib_h])
AS_UNSET([ac_cv_header_lauxlib_h])
AS_UNSET([ac_cv_header_luaconf_h])
AS_UNSET([ac_cv_header_luajit_h])
_ax_lua_saved_cppflags=$CPPFLAGS
CPPFLAGS="$CPPFLAGS -I$_ax_include_path"
AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
AM_COND_IF([LUAJIT], [AC_CHECK_HEADERS([luajit.h])])
CPPFLAGS=$_ax_lua_saved_cppflags
AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
@@ -621,18 +662,26 @@ AC_DEFUN([AX_LUA_LIBS],
dnl Try to find the Lua libs.
_ax_lua_saved_libs=$LIBS
LIBS="$LIBS $LUA_LIB"
AC_SEARCH_LIBS([lua_load],
[ lua$LUA_VERSION \
lua$LUA_SHORT_VERSION \
lua-$LUA_VERSION \
lua-$LUA_SHORT_VERSION \
:liblua-$LUA_VERSION.so.0 \
:liblua-$LUA_SHORT_VERSION.so.0 \
lua \
],
[_ax_found_lua_libs='yes'],
[_ax_found_lua_libs='no'],
[$_ax_lua_extra_libs])
AM_COND_IF([LUAJIT],
[AC_SEARCH_LIBS([lua_load],
[ luajit$LUA_VERSION \
luajit$LUA_SHORT_VERSION \
luajit-$LUA_VERSION \
luajit-$LUA_SHORT_VERSION \
luajit],
[_ax_found_lua_libs='yes'],
[_ax_found_lua_libs='no'],
[$_ax_lua_extra_libs])],
[AC_SEARCH_LIBS([lua_load],
[ lua$LUA_VERSION \
lua$LUA_SHORT_VERSION \
lua-$LUA_VERSION \
lua-$LUA_SHORT_VERSION \
lua \
],
[_ax_found_lua_libs='yes'],
[_ax_found_lua_libs='no'],
[$_ax_lua_extra_libs])])
LIBS=$_ax_lua_saved_libs
AS_IF([test "x$ac_cv_search_lua_load" != 'xno' &&
+175 -10
View File
@@ -54,6 +54,8 @@ AC_DEFUN([TORRENT_CHECK_EPOLL], [
}
])],
[
use_epoll=yes
AC_DEFINE(USE_EPOLL, 1, Use epoll.)
AC_MSG_RESULT(yes)
], [
@@ -86,6 +88,8 @@ AC_DEFUN([TORRENT_CHECK_KQUEUE], [
}
])],
[
use_kqueue=yes
AC_DEFINE(USE_KQUEUE, 1, Use kqueue.)
AC_MSG_RESULT(yes)
], [
@@ -125,7 +129,7 @@ AC_DEFUN([TORRENT_CHECK_FALLOCATE], [
#include <fcntl.h>
]], [[ fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 0); return 0;
]])],[
AC_DEFINE(HAVE_FALLOCATE, 1, Linux's fallocate supported.)
AC_DEFINE(USE_FALLOCATE, 1, Linux's fallocate supported.)
AC_MSG_RESULT(yes)
],[
AC_MSG_RESULT(no)
@@ -157,6 +161,116 @@ AC_DEFUN([TORRENT_WITH_POSIX_FALLOCATE], [
])
])
AC_DEFUN([TORRENT_CHECK_STATVFS], [
AC_CHECK_HEADERS(sys/vfs.h sys/statvfs.h sys/statfs.h)
AC_MSG_CHECKING(for statvfs)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#if HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#if HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
]], [[
struct statvfs s; fsblkcnt_t c;
statvfs("", &s);
fstatvfs(0, &s);
]])],[
AC_DEFINE(FS_STAT_FD, [fstatvfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
AC_DEFINE(FS_STAT_FN, [statvfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
AC_DEFINE(FS_STAT_STRUCT, [struct statvfs], Type of second argument to statfs function)
AC_DEFINE(FS_STAT_SIZE_TYPE, [unsigned long], Type of block size member in stat struct)
AC_DEFINE(FS_STAT_COUNT_TYPE, [fsblkcnt_t], Type of block count member in stat struct)
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_frsize)], Determine the block size)
AC_MSG_RESULT(ok)
have_stat_vfs=yes
],[
AC_MSG_RESULT(no)
have_stat_vfs=no
])
])
AC_DEFUN([TORRENT_CHECK_STATFS], [
AC_CHECK_HEADERS(sys/statfs.h)
AC_MSG_CHECKING(for statfs)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
]], [[
struct statfs s;
statfs("", &s);
fstatfs(0, &s);
]])],[
AC_DEFINE(FS_STAT_FD, [fstatfs(fd, &m_stat) == 0], Function to determine filesystem stats from fd)
AC_DEFINE(FS_STAT_FN, [statfs(fn, &m_stat) == 0], Function to determine filesystem stats from filename)
AC_DEFINE(FS_STAT_STRUCT, [struct statfs], Type of second argument to statfs function)
AC_DEFINE(FS_STAT_SIZE_TYPE, [long], Type of block size member in stat struct)
AC_DEFINE(FS_STAT_COUNT_TYPE, [long], Type of block count member in stat struct)
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(m_stat.f_bsize)], Determine the block size)
AC_MSG_RESULT(ok)
have_stat_vfs=yes
],[
AC_MSG_RESULT(no)
have_stat_vfs=no
])
])
AC_DEFUN([TORRENT_DISABLED_STATFS], [
AC_DEFINE(FS_STAT_FD, [(errno = ENOSYS) == 0], Function to determine filesystem stats from fd)
AC_DEFINE(FS_STAT_FN, [(errno = ENOSYS) == 0], Function to determine filesystem stats from filename)
AC_DEFINE(FS_STAT_STRUCT, [struct {blocksize_type f_bsize; blockcount_type f_bavail;}], Type of second argument to statfs function)
AC_DEFINE(FS_STAT_SIZE_TYPE, [int], Type of block size member in stat struct)
AC_DEFINE(FS_STAT_COUNT_TYPE, [int], Type of block count member in stat struct)
AC_DEFINE(FS_STAT_BLOCK_SIZE, [(4096)], Determine the block size)
AC_MSG_RESULT(No filesystem stats available)
])
AC_DEFUN([TORRENT_WITHOUT_STATVFS], [
AC_ARG_WITH(statvfs,
AS_HELP_STRING([--without-statvfs],[don't try to use statvfs to find free diskspace]),
[
if test "$withval" = "yes"; then
TORRENT_CHECK_STATVFS
else
have_stat_vfs=no
fi
],
[
TORRENT_CHECK_STATVFS
])
])
AC_DEFUN([TORRENT_WITHOUT_STATFS], [
AC_ARG_WITH(statfs,
AS_HELP_STRING([--without-statfs],[don't try to use statfs to find free diskspace]),
[
if test "$have_stat_vfs" = "no"; then
if test "$withval" = "yes"; then
TORRENT_CHECK_STATFS
else
TORRENT_DISABLED_STATFS
fi
fi
],
[
if test "$have_stat_vfs" = "no"; then
TORRENT_CHECK_STATFS
if test "$have_stat_vfs" = "no"; then
TORRENT_DISABLED_STATFS
fi
fi
])
])
AC_DEFUN([TORRENT_WITH_ADDRESS_SPACE], [
AC_ARG_WITH(address-space,
AS_HELP_STRING([--with-address-space=MB],[change the default address space size [[default=1024mb]]]),
@@ -189,7 +303,7 @@ AC_DEFUN([TORRENT_WITH_FASTCGI], [
elif test "$withval" = "yes"; then
CXXFLAGS="$CXXFLAGS"
LIBS="$LIBS -lfcgi"
LIBS="$LIBS -lfcgi"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include <fcgiapp.h>
]], [[ FCGX_Init(); ]])],[
@@ -281,29 +395,45 @@ AC_DEFUN([TORRENT_WITH_LUA], [
AC_MSG_RESULT(no)
else
AX_PROG_LUA
AX_LUA_LIBS
AX_LUA_HEADERS
AC_DEFINE(HAVE_LUA, 1, Use LUA.)
AC_DEFINE(LUA_DATADIR, [PACKAGE_DATADIR "/lua"], [LUA data directory])
LIBS="$LIBS $LUA_LIB"
CXXFLAGS="$CXXFLAGS $LUA_INCLUDE"
# 1. Override AX_LUA_LIBS default crash behavior
AX_LUA_LIBS([have_lua_libs=yes], [have_lua_libs=no])
# 2. Override AX_LUA_HEADERS default crash behavior
AX_LUA_HEADERS([have_lua_headers=yes], [have_lua_headers=no])
# 3. Only inject if both checks completely pass
if test "x$have_lua_libs" = "xyes" && test "x$have_lua_headers" = "xyes"; then
AC_DEFINE(HAVE_LUA, 1, Use LUA.)
AC_DEFINE(LUA_DATADIR, [PACKAGE_DATADIR "/lua"], [LUA data directory])
LIBS="$LIBS $LUA_LIB"
CXXFLAGS="$CXXFLAGS $LUA_INCLUDE"
else
# Throw fatal error ONLY if user strictly ran --with-lua=yes
if test "$withval" = "yes"; then
AC_MSG_ERROR([Lua support explicitly requested, but compatible Lua 5.3 libs/headers were not found.])
else
AC_MSG_WARN([Lua 5.3 libs or headers missing. Proceeding without Lua support.])
fi
fi
fi
],[
AC_MSG_RESULT(ignored)
])
])
AC_DEFUN([TORRENT_WITH_INOTIFY], [
AC_LANG_PUSH(C++)
AC_CHECK_HEADERS([sys/inotify.h mcheck.h])
AC_CHECK_HEADERS([sys/inotify.h])
AC_MSG_CHECKING([whether sys/inotify.h actually works])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <sys/inotify.h>
int main(int,const char**) { return (-1 == inotify_init()); }])
],[
AC_DEFINE(HAVE_INOTIFY, 1, [sys/inotify.h exists and works correctly])
AC_DEFINE(USE_INOTIFY, 1, [sys/inotify.h exists and works correctly])
AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(failed)]
)
@@ -317,6 +447,7 @@ AC_DEFUN([TORRENT_CHECK_PTHREAD_SETNAME_NP], [
AC_MSG_CHECKING(for pthread_setname_np type)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#define _GNU_SOURCE
#include <pthread.h>
#include <sys/types.h>
]], [[
@@ -358,3 +489,37 @@ AC_DEFUN([TORRENT_DISABLE_PTHREAD_SETNAME_NP], [
]
)
])
AC_DEFUN([TORRENT_WITH_SYSTEMD], [
AC_ARG_WITH(systemd,
AS_HELP_STRING([--with-systemd],[enable systemd socket activation support [[default=no]]]),
[
if test "$withval" = "yes"; then
PKG_CHECK_MODULES([SYSTEMD], [libsystemd],
[
CXXFLAGS="$CXXFLAGS $SYSTEMD_CFLAGS"
LIBS="$LIBS $SYSTEMD_LIBS"
AC_DEFINE(HAVE_SYSTEMD, 1, [Support for systemd socket activation.])
],
[AC_MSG_ERROR([libsystemd not found. Install libsystemd-dev (or the equivalent for your distribution).])])
fi
])
])
AC_DEFUN([TORRENT_WITHOUT_NCURSES], [
AC_ARG_WITH([ncurses],
[AS_HELP_STRING([--without-ncurses], [build without ncurses (daemon-only mode)])],
[with_ncurses=$withval],
[with_ncurses=yes])
if test "x$with_ncurses" = xno; then
AC_DEFINE([HAVE_NO_NCURSES], [1], [Define to 1 if building without ncurses])
CURSES_LIBS=""
CURSES_CFLAGS=""
CURSES_LIB=""
fi
AM_CONDITIONAL([NO_NCURSES], [test "x$with_ncurses" = xno])
])
+66 -16
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
])
@@ -158,23 +159,72 @@ AC_DEFUN([TORRENT_CHECK_POPCOUNT], [
])
AC_DEFUN([TORRENT_CHECK_CACHELINE], [
AC_MSG_CHECKING(for cacheline)
AC_REQUIRE([AC_CANONICAL_HOST])
AC_MSG_CHECKING([for target cacheline size])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <stdlib.h>
#include <linux/cache.h>
void* vptr __cacheline_aligned;
void f() { posix_memalign(&vptr, SMP_CACHE_BYTES, 42); }
])],
[
AC_MSG_RESULT(found builtin)
dnl Need to fix this so that it uses the stuff defined by the system.
case "$host_os" in
linux*)
# REGION: Linux Kernel Extraction Loop
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#include <stdlib.h>
#include <linux/cache.h>
void* vptr;
void f() {
int res = posix_memalign(&vptr, SMP_CACHE_BYTES, 42);
(void)res;
}
]])],[
# We need an explicit variable fallback condition inside AC_COMPUTE_INT
AC_COMPUTE_INT([torrent_cv_cacheline_size], [SMP_CACHE_BYTES], [#include <linux/cache.h>], [torrent_cv_cacheline_size=0])
AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.)
], [
AC_MSG_RESULT(using default 128 bytes)
AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.)
])
if test "$torrent_cv_cacheline_size" -gt 0; then
AC_MSG_RESULT([linux builtin ($torrent_cv_cacheline_size bytes)])
AC_DEFINE_UNQUOTED([LT_SMP_CACHE_BYTES], [$torrent_cv_cacheline_size], [System-defined Linux L1 SMP cacheline size.])
else
# Handle scenarios where macro maps to a complex runtime expression or fails
AC_MSG_RESULT([failed to parse SMP_CACHE_BYTES value])
AC_MSG_FAILURE([Linux kernel headers found, but cacheline constant could not be computed at compile-time.])
fi
],[
# Explicitly validate the CPU type even on Linux if the header check fails
case "$host_cpu" in
x86_64*|amd64*|i386*|i486*|i586*|i686*)
AC_MSG_RESULT([linux fallback x86 64 bytes])
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Fallback 64-byte alignment for Linux x86 hardware.])
;;
arm*|aarch64*|powerpc*|ppc*|s390x*)
AC_MSG_RESULT([linux fallback enterprise 128 bytes])
AC_DEFINE([LT_SMP_CACHE_BYTES], 128, [Fallback 128-byte alignment for Linux enterprise hardware.])
;;
*)
AC_MSG_RESULT([unrecognized CPU arch on Linux header fallback])
AC_MSG_FAILURE([Unrecognized CPU architecture ($host_cpu) on Linux fallback path. Aborting build.])
;;
esac
])
;;
*)
# REGION: Cross-Platform Strict Hardware Mapping (macOS, FreeBSD, OpenBSD, NetBSD)
case "$host_cpu" in
x86_64*|amd64*|i386*|i486*|i586*|i686*)
# Explicit x86 desktop hardware baseline block
AC_MSG_RESULT([$host_os ($host_cpu) standard x86 64 bytes])
AC_DEFINE([LT_SMP_CACHE_BYTES], 64, [Standard 64-byte alignment for stable x86 hardware layout.])
;;
arm*|aarch64*|powerpc*|ppc*|s390x*)
# Explicit modern enterprise and Apple Silicon hardware baseline block
AC_MSG_RESULT([$host_os ($host_cpu) stable enterprise 128 bytes])
AC_DEFINE([LT_SMP_CACHE_BYTES], 128, [Optimized 128-byte alignment for newer high-performance chipsets.])
;;
*)
# STRICT ENFORCEMENT: Fail the build immediately if the CPU isn't explicitly known
AC_MSG_RESULT([unrecognized architecture])
AC_MSG_FAILURE([The target CPU architecture ($host_cpu) is unrecognized. Aborting configuration to prevent fatal runtime false-sharing or memory misalignment errors.])
;;
esac
;;
esac
])
AC_DEFUN([TORRENT_CHECK_ALIGNED], [
+21 -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 \
@@ -161,11 +169,13 @@ libsub_root_a_SOURCES = \
utils/file_status_cache.cc \
utils/file_status_cache.h \
utils/functional.h \
utils/gzip.cc \
utils/gzip.h \
utils/list_focus.h \
utils/lockfile.cc \
utils/lockfile.h \
utils/socket_fd.cc \
utils/socket_fd.h \
utils/watch_ready_queue.cc \
utils/watch_ready_queue.h \
\
command_download.cc \
command_dynamic.cc \
@@ -189,10 +199,14 @@ libsub_root_a_SOURCES = \
globals.h \
option_parser.cc \
option_parser.h \
setup.cc \
setup.h \
signal_handler.cc \
signal_handler.h \
thread_worker.cc \
thread_worker.h
signal_handler.h
if NO_NCURSES
libsub_root_a_SOURCES += display/curses_stub.cc display/curses_stub.h
endif
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -DPACKAGE_DATADIR=\"$(pkgdatadir)\"
+217 -78
View File
@@ -5,9 +5,6 @@
#include <functional>
#include <netdb.h>
#include <unistd.h>
#include <rak/file_stat.h>
#include <rak/path.h>
#include <rak/string_manip.h>
#include <rak/regex.h>
#include <torrent/rate.h>
#include <torrent/throttle.h>
@@ -21,41 +18,49 @@
#include <torrent/net/types.h>
#include <torrent/peer/connection_list.h>
#include <torrent/peer/peer_list.h>
#include <torrent/system/callbacks.h>
#include <torrent/utils/file_stat.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include <torrent/utils/string_manip.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"
#include "command_helpers.h"
std::string
torrent::string_utf8
retrieve_d_base_path(core::Download* download) {
if (download->file_list()->is_multi_file())
return download->file_list()->frozen_root_dir();
else
return download->file_list()->empty() ? std::string() : download->file_list()->at(0)->frozen_path();
if (download->file_list()->empty())
return {};
return download->file_list()->at(0)->frozen_path();
}
std::string
torrent::string_utf8
retrieve_d_base_filename(core::Download* download) {
const std::string* base;
torrent::string_utf8 base_path;
if (download->file_list()->is_multi_file())
base = &download->file_list()->frozen_root_dir();
base_path = download->file_list()->frozen_root_dir();
else if (!download->file_list()->empty())
base_path = download->file_list()->at(0)->frozen_path();
else
base = &download->file_list()->at(0)->frozen_path();
return {};
std::string::size_type split = base->rfind('/');
auto split = base_path.str().rfind('/');
if (split == std::string::npos)
return *base;
else
return base->substr(split + 1);
return base_path;
return torrent::string_utf8::from_string(base_path.str().substr(split + 1));
}
torrent::Object
@@ -77,23 +82,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);
// link = 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 {
@@ -109,7 +114,7 @@ apply_d_change_link(core::Download* download, const torrent::Object::list_type&
case 1:
{
rak::file_stat fileStat;
torrent::utils::FileStat fileStat;
errno = 0;
if (!fileStat.update_link(link) || !fileStat.is_link() || unlink(link.c_str()) == -1)
@@ -131,7 +136,7 @@ apply_d_delete_tied(core::Download* download) {
if (tie.empty())
return torrent::Object();
if (::unlink(rak::path_expand(tie).c_str()) == -1)
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));
@@ -143,9 +148,9 @@ apply_d_directory(core::Download* download, const std::string& name) {
if (!download->file_list()->is_multi_file())
download->set_root_directory(name);
else if (name.empty() || *name.rbegin() == '/')
download->set_root_directory(name + download->info()->name());
download->set_root_directory(name + download->info()->name().str());
else
download->set_root_directory(name + "/" + download->info()->name());
download->set_root_directory(name + "/" + download->info()->name().str());
}
torrent::Object
@@ -270,16 +275,6 @@ retrieve_d_custom_map(core::Download* download, bool keys_only, const torrent::O
return result;
}
torrent::Object
retrieve_d_bitfield(core::Download* download) {
const torrent::Bitfield* bitField = download->download()->file_list()->bitfield();
if (bitField->empty())
return torrent::Object("");
return torrent::Object(rak::transform_hex(bitField->begin(), bitField->end()));
}
void
apply_d_add_peer(core::Download* download, const std::string& arg) {
int port, ret;
@@ -302,10 +297,12 @@ 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());
auto callback_id = torrent::system::make_callback_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) {
torrent::this_thread::resolver()->resolve_preferred(callback_id, host, AF_UNSPEC, AF_INET, [download, port](torrent::c_sa_shared_ptr sa, int err) {
if (sa == nullptr) {
lt_log_print(torrent::LOG_TORRENT_WARN, "could not resolve hostname for added peer: %s", gai_strerror(err));
return;
@@ -327,7 +324,8 @@ d_chunks_seen(core::Download* download) {
std::string result;
result.resize(size * 2);
rak::transform_hex((const char*)seen, (const char*)seen + size, result.begin());
torrent::utils::transform_to_hex(seen, seen + size, result);
return result;
}
@@ -445,9 +443,11 @@ p_call_target(const torrent::Object::list_type& args) {
torrent::HashString hash;
if (peer_id.size() != 40 ||
torrent::hash_string_from_hex_c_str(peer_id.c_str(), hash) == peer_id.c_str())
throw torrent::input_error("Not a hash string.");
if (peer_id.size() != 40)
throw torrent::input_error("invalid argument: peer id target is not 40 bytes long");
if (torrent::utils::transform_from_hex(peer_id.c_str(), peer_id.c_str() + 40, hash) != hash.end())
throw torrent::input_error("invalid argument: peer id target is not a hex string");
torrent::ConnectionList::iterator peerItr = download->connection_list()->find(hash.c_str());
@@ -468,12 +468,14 @@ download_tracker_insert(core::Download* download, const torrent::Object::list_ty
if (args.size() != 2)
throw torrent::input_error("Wrong argument count.");
int64_t group;
int64_t group = 0;
if (args.front().is_string())
rpc::parse_whole_value_nothrow(args.front().as_string().c_str(), &group);
else
if (args.front().is_string()) {
if (!rpc::parse_whole_value_nothrow(args.front().as_string().c_str(), &group))
throw torrent::input_error("Invalid tracker group number.");
} else {
group = args.front().as_value();
}
if (group < 0 || group > 32)
throw torrent::input_error("Tracker group number invalid.");
@@ -495,6 +497,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)
@@ -539,16 +554,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); }))
@@ -603,12 +615,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)); \
@@ -628,30 +644,48 @@ void cg_d_group_set(core::Download* download, const torrent::Objec
void
initialize_command_download() {
CMD2_DL("d.hash", std::bind(&rak::transform_hex_str<torrent::HashString>, CMD2_ON_INFO(hash)));
CMD2_DL("d.local_id", std::bind(&rak::transform_hex_str<torrent::HashString>, CMD2_ON_INFO(local_id)));
CMD2_DL("d.local_id_html", std::bind(&rak::copy_escape_html_str<torrent::HashString>, CMD2_ON_INFO(local_id)));
CMD2_DL("d.bitfield", std::bind(&retrieve_d_bitfield, std::placeholders::_1));
CMD2_DL("d.base_path", std::bind(&retrieve_d_base_path, std::placeholders::_1));
CMD2_DL("d.base_filename", std::bind(&retrieve_d_base_filename, std::placeholders::_1));
CMD2_DL("d.hash", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(download->info()->hash()); });
CMD2_DL("d.local_id", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(download->info()->local_id()); });
CMD2_DL("d.local_id_html", [](auto* download, auto) { return torrent::utils::copy_escape_html_str(download->info()->local_id()); });
CMD2_DL("d.bitfield", [](auto* download, auto) { return torrent::utils::transform_to_hex_str(*download->download()->file_list()->bitfield()); });
CMD2_DL("d.base_path", [](auto* download, auto) { return retrieve_d_base_path(download).str(); });
CMD2_DL("d.base_path.hex", [](auto* download, auto) { return retrieve_d_base_path(download).object_hex(); });
CMD2_DL("d.base_path.base64", [](auto* download, auto) { return retrieve_d_base_path(download).object_base64(); });
CMD2_DL("d.base_path.base64_as_binary", [](auto* download, auto) { return retrieve_d_base_path(download).object_base64_as_binary(); });
CMD2_DL("d.base_path.as_binary", [](auto* download, auto) { return retrieve_d_base_path(download).object_as_binary(); });
CMD2_DL("d.base_path.or_base64", [](auto* download, auto) { return retrieve_d_base_path(download).object_utf8_or_base64(); });
CMD2_DL("d.base_path.or_as_binary", [](auto* download, auto) { return retrieve_d_base_path(download).object_utf8_or_as_binary(); });
CMD2_DL("d.base_filename", [](auto* download, auto) { return retrieve_d_base_filename(download).str(); });
CMD2_DL("d.base_filename.hex", [](auto* download, auto) { return retrieve_d_base_filename(download).object_hex(); });
CMD2_DL("d.base_filename.base64", [](auto* download, auto) { return retrieve_d_base_filename(download).object_base64(); });
CMD2_DL("d.base_filename.base64_as_binary", [](auto* download, auto) { return retrieve_d_base_filename(download).object_base64_as_binary(); });
CMD2_DL("d.base_filename.as_binary", [](auto* download, auto) { return retrieve_d_base_filename(download).object_as_binary(); });
CMD2_DL("d.base_filename.or_base64", [](auto* download, auto) { return retrieve_d_base_filename(download).object_utf8_or_base64(); });
CMD2_DL("d.base_filename.or_as_binary", [](auto* download, auto) { return retrieve_d_base_filename(download).object_utf8_or_as_binary(); });
CMD2_DL("d.name", CMD2_ON_INFO(name));
CMD2_DL("d.creation_date", CMD2_ON_INFO(creation_date));
CMD2_DL("d.load_date", CMD2_ON_INFO(load_date));
CMD2_DL("d.name", [](auto* download, auto) { return download->info()->name().str(); });
CMD2_DL("d.name.hex", [](auto* download, auto) { return download->info()->name().object_hex(); });
CMD2_DL("d.name.base64", [](auto* download, auto) { return download->info()->name().object_base64(); });
CMD2_DL("d.name.base64_as_binary", [](auto* download, auto) { return download->info()->name().object_base64_as_binary(); });
CMD2_DL("d.name.as_binary", [](auto* download, auto) { return download->info()->name().object_as_binary(); });
CMD2_DL("d.name.or_base64", [](auto* download, auto) { return download->info()->name().object_utf8_or_base64(); });
CMD2_DL("d.name.or_as_binary", [](auto* download, auto) { return download->info()->name().object_utf8_or_as_binary(); });
CMD2_DL("d.creation_date", [](auto* download, auto) { return download->info()->creation_date(); });
CMD2_DL("d.load_date", [](auto* download, auto) { return download->info()->load_date(); });
//
// Network related:
//
CMD2_DL ("d.up.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(up_rate)));
CMD2_DL ("d.up.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(up_rate)));
CMD2_DL ("d.down.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(down_rate)));
CMD2_DL ("d.down.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(down_rate)));
CMD2_DL ("d.skip.rate", std::bind(&torrent::Rate::rate, CMD2_ON_INFO(skip_rate)));
CMD2_DL ("d.skip.total", std::bind(&torrent::Rate::total, CMD2_ON_INFO(skip_rate)));
CMD2_DL ("d.up.rate", [](auto* download, auto) { return download->info()->up_rate()->rate(); });
CMD2_DL ("d.up.total", [](auto* download, auto) { return download->info()->up_rate()->total(); });
CMD2_DL ("d.down.rate", [](auto* download, auto) { return download->info()->down_rate()->rate(); });
CMD2_DL ("d.down.total", [](auto* download, auto) { return download->info()->down_rate()->total(); });
CMD2_DL ("d.skip.rate", [](auto* download, auto) { return download->info()->skip_rate()->rate(); });
CMD2_DL ("d.skip.total", [](auto* download, auto) { return download->info()->skip_rate()->total(); });
CMD2_DL ("d.peer_exchange", CMD2_ON_INFO(is_pex_enabled));
CMD2_DL_VALUE_V ("d.peer_exchange.set", std::bind(&torrent::Download::set_pex_enabled, CMD2_BIND_DL, std::placeholders::_2));
CMD2_DL ("d.peer_exchange", [](auto* download, auto) { return download->info()->is_pex_enabled(); });
CMD2_DL_VALUE_V ("d.peer_exchange.set", [](auto* download, auto value) { download->download()->set_pex_enabled(value); });
CMD2_DL_LIST ("d.create_link", std::bind(&apply_d_change_link, std::placeholders::_1, std::placeholders::_2, 0));
CMD2_DL_LIST ("d.delete_link", std::bind(&apply_d_change_link, std::placeholders::_1, std::placeholders::_2, 1));
@@ -667,16 +701,16 @@ initialize_command_download() {
// Control functinos:
//
CMD2_DL ("d.is_open", CMD2_ON_INFO(is_open));
CMD2_DL ("d.is_active", CMD2_ON_INFO(is_active));
CMD2_DL ("d.is_open", [](auto* download, auto) { return download->info()->is_open(); });
CMD2_DL ("d.is_active", [](auto* download, auto) { return download->info()->is_active(); });
CMD2_DL ("d.is_hash_checked", std::bind(&torrent::Download::is_hash_checked, CMD2_BIND_DL));
CMD2_DL ("d.is_hash_checking", std::bind(&torrent::Download::is_hash_checking, CMD2_BIND_DL));
CMD2_DL ("d.is_multi_file", std::bind(&torrent::FileList::is_multi_file, CMD2_BIND_FL));
CMD2_DL ("d.is_private", CMD2_ON_INFO(is_private));
CMD2_DL ("d.is_pex_active", CMD2_ON_INFO(is_pex_active));
CMD2_DL ("d.is_private", [](auto* download, auto) { return download->info()->is_private(); });
CMD2_DL ("d.is_pex_active", [](auto* download, auto) { return download->info()->is_pex_active(); });
CMD2_DL ("d.is_partially_done", CMD2_ON_DATA(is_partially_done));
CMD2_DL ("d.is_not_partially_done", CMD2_ON_DATA(is_not_partially_done));
CMD2_DL ("d.is_meta", CMD2_ON_INFO(is_meta_download));
CMD2_DL ("d.is_meta", [](auto* download, auto) { return download->info()->is_meta_download(); });
CMD2_DL_V ("d.resume", std::bind(&core::DownloadList::resume_default, control->core()->download_list(), std::placeholders::_1));
CMD2_DL_V ("d.pause", std::bind(&core::DownloadList::pause_default, control->core()->download_list(), std::placeholders::_1));
@@ -686,8 +720,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));
@@ -769,8 +803,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.
@@ -871,4 +905,109 @@ initialize_command_download() {
CMD2_DL_LIST ("t.multicall", std::bind(&t_multicall, std::placeholders::_1, std::placeholders::_2));
CMD2_ANY_LIST ("p.call_target", std::bind(&p_call_target, std::placeholders::_2));
rpc::rpc.mark_safe("add_peer");
rpc::rpc.mark_safe("d.hash");
rpc::rpc.mark_safe("d.local_id");
rpc::rpc.mark_safe("d.local_id_html");
rpc::rpc.mark_safe("d.bitfield");
rpc::rpc.mark_safe("d.base_path");
rpc::rpc.mark_safe("d.base_path.hex");
rpc::rpc.mark_safe("d.base_path.base64");
rpc::rpc.mark_safe("d.base_path.base64_as_binary");
rpc::rpc.mark_safe("d.base_path.as_binary");
rpc::rpc.mark_safe("d.base_path.or_base64");
rpc::rpc.mark_safe("d.base_path.or_as_binary");
rpc::rpc.mark_safe("d.base_filename");
rpc::rpc.mark_safe("d.base_filename.hex");
rpc::rpc.mark_safe("d.base_filename.base64");
rpc::rpc.mark_safe("d.base_filename.base64_as_binary");
rpc::rpc.mark_safe("d.base_filename.as_binary");
rpc::rpc.mark_safe("d.base_filename.or_base64");
rpc::rpc.mark_safe("d.base_filename.or_as_binary");
rpc::rpc.mark_safe("d.name");
rpc::rpc.mark_safe("d.name.hex");
rpc::rpc.mark_safe("d.name.base64");
rpc::rpc.mark_safe("d.name.base64_as_binary");
rpc::rpc.mark_safe("d.name.as_binary");
rpc::rpc.mark_safe("d.name.or_base64");
rpc::rpc.mark_safe("d.name.or_as_binary");
rpc::rpc.mark_safe("d.directory");
rpc::rpc.mark_safe("d.directory_base");
rpc::rpc.mark_safe("d.creation_date");
rpc::rpc.mark_safe("d.load_date");
rpc::rpc.mark_safe("d.up.rate");
rpc::rpc.mark_safe("d.up.total");
rpc::rpc.mark_safe("d.down.rate");
rpc::rpc.mark_safe("d.down.total");
rpc::rpc.mark_safe("d.skip.rate");
rpc::rpc.mark_safe("d.skip.total");
rpc::rpc.mark_safe("d.is_open");
rpc::rpc.mark_safe("d.is_active");
rpc::rpc.mark_safe("d.is_hash_checked");
rpc::rpc.mark_safe("d.is_hash_checking");
rpc::rpc.mark_safe("d.is_multi_file");
rpc::rpc.mark_safe("d.is_private");
rpc::rpc.mark_safe("d.is_pex_active");
rpc::rpc.mark_safe("d.is_partially_done");
rpc::rpc.mark_safe("d.is_not_partially_done");
rpc::rpc.mark_safe("d.is_meta");
rpc::rpc.mark_safe("d.peer_exchange");
rpc::rpc.mark_safe("d.resume");
rpc::rpc.mark_safe("d.pause");
rpc::rpc.mark_safe("d.open");
rpc::rpc.mark_safe("d.close");
rpc::rpc.mark_safe("d.close.directly");
rpc::rpc.mark_safe("d.erase");
rpc::rpc.mark_safe("d.check_hash");
rpc::rpc.mark_safe("d.save_resume");
rpc::rpc.mark_safe("d.save_full_session");
rpc::rpc.mark_safe("d.update_priorities");
rpc::rpc.mark_safe("d.custom");
rpc::rpc.mark_safe("d.custom1");
rpc::rpc.mark_safe("d.custom2");
rpc::rpc.mark_safe("d.custom3");
rpc::rpc.mark_safe("d.custom4");
rpc::rpc.mark_safe("d.custom5");
rpc::rpc.mark_safe("d.size_bytes");
rpc::rpc.mark_safe("d.size_chunks");
rpc::rpc.mark_safe("d.size_pex");
rpc::rpc.mark_safe("d.completed_bytes");
rpc::rpc.mark_safe("d.bytes_done");
rpc::rpc.mark_safe("d.peers_accounted");
rpc::rpc.mark_safe("d.chunks_hashed");
rpc::rpc.mark_safe("d.tracker_size");
rpc::rpc.mark_safe("d.completed_chunks");
rpc::rpc.mark_safe("d.left_bytes");
rpc::rpc.mark_safe("d.chunk_size");
rpc::rpc.mark_safe("d.priority");
rpc::rpc.mark_safe("d.priority_str");
rpc::rpc.mark_safe("d.state");
rpc::rpc.mark_safe("d.state_changed");
rpc::rpc.mark_safe("d.state_counter");
rpc::rpc.mark_safe("d.connection_current");
rpc::rpc.mark_safe("d.connection_leech");
rpc::rpc.mark_safe("d.connection_seed");
rpc::rpc.mark_safe("d.throttle_name");
rpc::rpc.mark_safe("d.uploads_max");
rpc::rpc.mark_safe("d.downloads_max");
rpc::rpc.mark_safe("d.peers_min");
rpc::rpc.mark_safe("d.peers_max");
rpc::rpc.mark_safe("d.peers_connected");
rpc::rpc.mark_safe("d.peers_not_connected");
rpc::rpc.mark_safe("d.peers_complete");
rpc::rpc.mark_safe("d.tracker_numwant");
rpc::rpc.mark_safe("d.tracker_focus");
rpc::rpc.mark_safe("d.message");
rpc::rpc.mark_safe("d.hashing");
rpc::rpc.mark_safe("d.hashing_failed");
rpc::rpc.mark_safe("d.free_diskspace");
rpc::rpc.mark_safe("d.views");
rpc::rpc.mark_safe("d.views.remove");
rpc::rpc.mark_safe("d.views.push_back_unique");
rpc::rpc.mark_safe("d.ratio");
rpc::rpc.mark_safe("f.multicall");
rpc::rpc.mark_safe("p.multicall");
rpc::rpc.mark_safe("p.call_target");
rpc::rpc.mark_safe("t.multicall");
}
+23
View File
@@ -455,4 +455,27 @@ initialize_command_dynamic() {
CMD2_ANY ("strings.tracker_event", std::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_EVENT));
CMD2_ANY ("strings.tracker_mode", std::bind(&torrent::option_list_strings, torrent::OPTION_TRACKER_MODE));
// clang-format on
#ifdef HAVE_XMLRPC_TINYXML2
rpc::rpc.mark_safe("system.listMethods");
#endif
rpc::rpc.mark_safe("method.use_deprecated");
rpc::rpc.mark_safe("method.const");
rpc::rpc.mark_safe("method.has_key");
rpc::rpc.mark_safe("method.list_keys");
rpc::rpc.mark_safe("method.get");
rpc::rpc.mark_safe("method.rlookup");
rpc::rpc.mark_safe("catch");
rpc::rpc.mark_safe("strings.choke_heuristics");
rpc::rpc.mark_safe("strings.choke_heuristics.upload");
rpc::rpc.mark_safe("strings.choke_heuristics.download");
rpc::rpc.mark_safe("strings.connection_type");
rpc::rpc.mark_safe("strings.encryption");
rpc::rpc.mark_safe("strings.ip_filter");
rpc::rpc.mark_safe("strings.ip_tos");
rpc::rpc.mark_safe("strings.log_group");
rpc::rpc.mark_safe("strings.tracker_event");
rpc::rpc.mark_safe("strings.tracker_mode");
}
+48 -18
View File
@@ -2,14 +2,14 @@
#include <functional>
#include <cstdio>
#include <rak/error_number.h>
#include <rak/file_stat.h>
#include <rak/path.h>
#include <rak/string_manip.h>
#include <string>
#include <vector>
#include <torrent/rate.h>
#include <torrent/hash_string.h>
#include <torrent/utils/log.h>
#include <torrent/utils/directory_events.h>
#include <torrent/utils/file_stat.h>
#include <torrent/utils/string_manip.h>
#include "globals.h"
#include "control.h"
@@ -21,6 +21,7 @@
#include "rpc/command_scheduler.h"
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
#include "utils/watch_ready_queue.h"
torrent::Object
apply_on_ratio(const torrent::Object& rawArgs) {
@@ -67,10 +68,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 +84,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 +97,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 +110,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));
@@ -210,7 +211,7 @@ apply_download_list(const torrent::Object::list_type& args) {
for (core::View::const_iterator itr = (*view_itr)->begin_visible(), last = (*view_itr)->end_visible(); itr != last; itr++) {
const torrent::HashString* hashString = &(*itr)->info()->hash();
resultList.push_back(rak::transform_hex(hashString->begin(), hashString->end()));
resultList.push_back(torrent::utils::transform_to_hex_str(*hashString));
}
return result;
@@ -293,22 +294,39 @@ call_watch_command(const std::string& command, const std::string& path) {
}
torrent::Object
directory_watch_added(const torrent::Object::list_type& args) {
directory_watch(const torrent::Object::list_type& args, int flags) {
if (args.size() != 2)
throw torrent::input_error("Too few arguments.");
auto& path = args.front().as_string();
auto& command = args.back().as_string();
std::string expanded_path = expand_path(path);
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,
std::bind(&call_watch_command, command, std::placeholders::_1));
torrent::watch_descriptor::slot_string slot =
flags == torrent::directory_events::flag_on_ready ?
torrent::watch_descriptor::slot_string([command](const auto& arg) { control->watch_ready_queue()->push(command, arg); }) :
torrent::watch_descriptor::slot_string(std::bind(&call_watch_command, command, std::placeholders::_1));
control->directory_events()->notify_on(expanded_path.c_str(), flags, slot);
return torrent::Object();
}
torrent::Object
directory_watch_added(const torrent::Object::list_type& args) {
return directory_watch(args,
torrent::directory_events::flag_on_added |
torrent::directory_events::flag_on_updated);
}
torrent::Object
directory_watch_ready(const torrent::Object::list_type& args) {
return directory_watch(args,
torrent::directory_events::flag_on_ready);
}
void
initialize_command_events() {
CMD2_ANY_STRING ("on_ratio", std::bind(&apply_on_ratio, std::placeholders::_2));
@@ -346,4 +364,16 @@ initialize_command_events() {
CMD2_ANY_LIST ("d.multicall.filtered", std::bind(&d_multicall_filtered, std::placeholders::_2));
CMD2_ANY_LIST ("directory.watch.added", std::bind(&directory_watch_added, std::placeholders::_2));
CMD2_ANY_LIST ("directory.watch.ready", std::bind(&directory_watch_ready, std::placeholders::_2));
rpc::rpc.mark_safe("start_tied");
rpc::rpc.mark_safe("stop_untied");
rpc::rpc.mark_safe("close_untied");
rpc::rpc.mark_safe("remove_untied");
rpc::rpc.mark_safe("close_low_diskspace");
rpc::rpc.mark_safe("close_low_diskspace.normal");
rpc::rpc.mark_safe("download_list");
rpc::rpc.mark_safe("d.multicall2");
rpc::rpc.mark_safe("d.multicall.filtered");
}
+78 -59
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>
@@ -60,24 +24,34 @@ apply_f_path(torrent::File* file) {
if (file->path()->empty())
return std::string();
torrent::Object resultRaw(*file->path()->begin());
torrent::Object::string_type& result = resultRaw.as_string();
torrent::Object result_raw(file->path()->begin()->str());
auto& result = result_raw.as_string();
for (torrent::Path::const_iterator itr = ++file->path()->begin(), last = file->path()->end(); itr != last; itr++)
result += '/' + *itr;
result += '/' + itr->str();
return resultRaw;
return result_raw;
}
torrent::Object
apply_f_path_components(torrent::File* file) {
torrent::Object resultRaw = torrent::Object::create_list();
torrent::Object::list_type& result = resultRaw.as_list();
apply_f_path_components(torrent::File* file, int output_type) {
auto result_raw = torrent::Object::create_list();
auto& result = result_raw.as_list();
for (const auto& itr : *file->path())
result.push_back(itr);
for (const auto& itr : *file->path()) {
switch (output_type) {
case 0: result.push_back(itr.str()); break;
case 1: result.push_back(itr.object_hex()); break;
case 2: result.push_back(itr.object_base64()); break;
case 3: result.push_back(itr.object_base64_as_binary()); break;
case 4: result.push_back(itr.object_as_binary()); break;
case 5: result.push_back(itr.object_utf8_or_base64()); break;
case 6: result.push_back(itr.object_utf8_or_as_binary()); break;
default: throw torrent::input_error("apply_f_path_components(): invalid output type");
};
}
return resultRaw;
return result_raw;
}
torrent::Object
@@ -93,7 +67,7 @@ apply_fi_filename_last(torrent::FileListIterator* itr) {
if (itr->depth() >= itr->file()->path()->size())
return "ERROR";
return itr->file()->path()->at(itr->depth());
return itr->file()->path()->at(itr->depth()).str();
}
void
@@ -116,21 +90,32 @@ initialize_command_file() {
CMD2_FILE_V("f.prioritize_last.enable", std::bind(&torrent::File::set_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
CMD2_FILE_V("f.prioritize_last.disable", std::bind(&torrent::File::unset_flags, std::placeholders::_1, torrent::File::flag_prioritize_last));
CMD2_FILE("f.size_bytes", std::bind(&torrent::File::size_bytes, std::placeholders::_1));
CMD2_FILE("f.size_chunks", std::bind(&torrent::File::size_chunks, std::placeholders::_1));
CMD2_FILE("f.completed_chunks", std::bind(&torrent::File::completed_chunks, std::placeholders::_1));
CMD2_FILE("f.size_bytes", [](auto* file, auto) { return file->size_bytes(); });
CMD2_FILE("f.size_chunks", [](auto* file, auto) { return file->size_chunks(); });
CMD2_FILE("f.completed_chunks", [](auto* file, auto) { return file->completed_chunks(); });
CMD2_FILE("f.offset", std::bind(&torrent::File::offset, std::placeholders::_1));
CMD2_FILE("f.range_first", std::bind(&torrent::File::range_first, std::placeholders::_1));
CMD2_FILE("f.range_second", std::bind(&torrent::File::range_second, std::placeholders::_1));
CMD2_FILE("f.offset", [](auto* file, auto) { return file->offset(); });
CMD2_FILE("f.range_first", [](auto* file, auto) { return file->range_first(); });
CMD2_FILE("f.range_second", [](auto* file, auto) { return file->range_second(); });
CMD2_FILE("f.priority", std::bind(&torrent::File::priority, std::placeholders::_1));
CMD2_FILE_VALUE_V("f.priority.set", std::bind(&apply_f_set_priority, std::placeholders::_1, std::placeholders::_2));
CMD2_FILE("f.priority", [](auto* file, auto) { return file->priority(); });
CMD2_FILE_VALUE_V("f.priority.set", [](auto* file, auto v) { apply_f_set_priority(file, v); });
CMD2_FILE("f.path", std::bind(&apply_f_path, std::placeholders::_1));
CMD2_FILE("f.path_components", std::bind(&apply_f_path_components, std::placeholders::_1));
CMD2_FILE("f.path_depth", std::bind(&apply_f_path_depth, std::placeholders::_1));
CMD2_FILE("f.frozen_path", std::bind(&torrent::File::frozen_path, std::placeholders::_1));
CMD2_FILE("f.path", [](auto* file, auto) { return apply_f_path(file); });
CMD2_FILE("f.path_components", [](auto* file, auto) { return apply_f_path_components(file, 0); });
CMD2_FILE("f.path_components.hex", [](auto* file, auto) { return apply_f_path_components(file, 1); });
CMD2_FILE("f.path_components.base64", [](auto* file, auto) { return apply_f_path_components(file, 2); });
CMD2_FILE("f.path_components.base64_as_binary", [](auto* file, auto) { return apply_f_path_components(file, 3); });
CMD2_FILE("f.path_components.as_binary", [](auto* file, auto) { return apply_f_path_components(file, 4); });
CMD2_FILE("f.path_components.or_base64", [](auto* file, auto) { return apply_f_path_components(file, 5); });
CMD2_FILE("f.path_components.or_as_binary", [](auto* file, auto) { return apply_f_path_components(file, 6); });
CMD2_FILE("f.path_depth", [](auto* file, auto) { return apply_f_path_depth(file); });
CMD2_FILE("f.frozen_path", [](auto* file, auto) { return file->frozen_path().str(); });
CMD2_FILE("f.frozen_path.hex", [](auto* file, auto) { return file->frozen_path().object_hex(); });
CMD2_FILE("f.frozen_path.base64", [](auto* file, auto) { return file->frozen_path().object_base64(); });
CMD2_FILE("f.frozen_path.as_binary", [](auto* file, auto) { return file->frozen_path().object_as_binary(); });
CMD2_FILE("f.frozen_path.or_base64", [](auto* file, auto) { return file->frozen_path().object_utf8_or_base64(); });
CMD2_FILE("f.frozen_path.or_as_binary", [](auto* file, auto) { return file->frozen_path().object_utf8_or_as_binary(); });
CMD2_FILE("f.match_depth_prev", std::bind(&torrent::File::match_depth_prev, std::placeholders::_1));
CMD2_FILE("f.match_depth_next", std::bind(&torrent::File::match_depth_next, std::placeholders::_1));
@@ -139,4 +124,38 @@ initialize_command_file() {
CMD2_FILEITR("fi.filename_last", std::bind(&apply_fi_filename_last, std::placeholders::_1));
CMD2_FILEITR("fi.is_file", std::bind(&torrent::FileListIterator::is_file, std::placeholders::_1));
rpc::rpc.mark_safe("f.path");
rpc::rpc.mark_safe("f.path_components");
rpc::rpc.mark_safe("f.path_depth");
rpc::rpc.mark_safe("f.frozen_path");
rpc::rpc.mark_safe("f.frozen_path.hex");
rpc::rpc.mark_safe("f.frozen_path.base64");
rpc::rpc.mark_safe("f.frozen_path.base64_as_binary");
rpc::rpc.mark_safe("f.frozen_path.as_binary");
rpc::rpc.mark_safe("f.frozen_path.or_base64");
rpc::rpc.mark_safe("f.frozen_path.or_as_binary");
rpc::rpc.mark_safe("f.offset");
rpc::rpc.mark_safe("f.size_bytes");
rpc::rpc.mark_safe("f.size_chunks");
rpc::rpc.mark_safe("f.completed_chunks");
rpc::rpc.mark_safe("f.range_first");
rpc::rpc.mark_safe("f.range_second");
rpc::rpc.mark_safe("f.priority");
rpc::rpc.mark_safe("f.priority.set");
rpc::rpc.mark_safe("f.is_created");
rpc::rpc.mark_safe("f.is_open");
rpc::rpc.mark_safe("f.is_create_queued");
rpc::rpc.mark_safe("f.is_resize_queued");
rpc::rpc.mark_safe("f.prioritize_first");
rpc::rpc.mark_safe("f.prioritize_first.enable");
rpc::rpc.mark_safe("f.prioritize_first.disable");
rpc::rpc.mark_safe("f.prioritize_last");
rpc::rpc.mark_safe("f.prioritize_last.enable");
rpc::rpc.mark_safe("f.prioritize_last.disable");
rpc::rpc.mark_safe("f.last_touched");
rpc::rpc.mark_safe("f.match_depth_prev");
rpc::rpc.mark_safe("f.match_depth_next");
rpc::rpc.mark_safe("fi.filename_last");
rpc::rpc.mark_safe("fi.is_file");
}
+20
View File
@@ -385,4 +385,24 @@ initialize_command_groups() {
CMD2_ANY ("choke_group.down.heuristics", std::bind(&torrent::option_as_string, torrent::OPTION_CHOKE_HEURISTICS,
std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::down_queue))));
CMD2_ANY_LIST ("choke_group.down.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, false));
rpc::rpc.mark_safe("choke_group.list");
rpc::rpc.mark_safe("choke_group.size");
rpc::rpc.mark_safe("choke_group.index_of");
rpc::rpc.mark_safe("choke_group.general.size");
rpc::rpc.mark_safe("choke_group.tracker.mode");
rpc::rpc.mark_safe("choke_group.up.rate");
rpc::rpc.mark_safe("choke_group.down.rate");
rpc::rpc.mark_safe("choke_group.up.max");
rpc::rpc.mark_safe("choke_group.up.max.unlimited");
rpc::rpc.mark_safe("choke_group.up.total");
rpc::rpc.mark_safe("choke_group.up.queued");
rpc::rpc.mark_safe("choke_group.up.unchoked");
rpc::rpc.mark_safe("choke_group.up.heuristics");
rpc::rpc.mark_safe("choke_group.down.max");
rpc::rpc.mark_safe("choke_group.down.max.unlimited");
rpc::rpc.mark_safe("choke_group.down.total");
rpc::rpc.mark_safe("choke_group.down.queued");
rpc::rpc.mark_safe("choke_group.down.unchoked");
rpc::rpc.mark_safe("choke_group.down.heuristics");
}
-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>
+3 -1
View File
@@ -104,8 +104,10 @@ void initialize_commands();
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc | rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_NO_EXPORT(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_dont_delete);
#define CMD2_REDIRECT_MUTABLE(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc);
#define CMD2_REDIRECT_STR(from_key, to_key) \
rpc::commands.create_redirect(from_key, to_key, rpc::CommandMap::flag_public_rpc;
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) \
+18 -49
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);
@@ -65,7 +29,7 @@ torrent::Object
apply_ip_tables_size_data(const std::string& args) {
rpc::ip_table_list::const_iterator itr = ip_tables.find(args);
if (itr != ip_tables.end())
if (itr == ip_tables.end())
throw torrent::input_error("IP table does not exist.");
uint32_t size = itr->table.sizeof_data();
@@ -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))
@@ -239,9 +203,14 @@ ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address
uint32_t mask=0;
uint32_t end_mask=0;
mask = (~mask) << (32-mask_bits);
if (mask_bits == 0) {
mask = 0;
end_mask = ~(uint32_t)0;
} else {
mask = (~mask) << (32-mask_bits);
end_mask = (~end_mask) >> mask_bits;
}
*address_start = ip & mask;
end_mask = (~end_mask) >> mask_bits;
*address_end = (ip & mask) | end_mask;
valid=true;
@@ -298,7 +267,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 +295,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);
+71 -31
View File
@@ -1,27 +1,26 @@
#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>
#include <torrent/chunk_manager.h>
#include <torrent/data/file_manager.h>
#include <torrent/data/chunk_utils.h>
#include <torrent/runtime/runtime.h>
#include <torrent/utils/chrono.h>
#include <torrent/utils/option_strings.h>
#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"
@@ -96,8 +95,12 @@ post_increment(torrent::Object::list_const_iterator& itr, const torrent::Object:
inline const std::string&
check_name(const std::string& str) {
if (!rak::is_all_name(str))
throw torrent::input_error("Non-alphanumeric characters found.");
auto itr = std::find_if(str.begin(), str.end(), [](char c) {
return !std::isalnum(c, std::locale::classic()) && c != '_';
});
if (itr != str.end())
throw torrent::input_error("Invalid characters found in name.");
return str;
}
@@ -121,17 +124,26 @@ group_insert(const torrent::Object::list_type& args) {
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.max", "value", (int64_t)300));
rpc::commands.call("method.insert", rpc::create_object_list("group." + name + ".ratio.upload", "value", (int64_t)20 << 20));
rpc::rpc.mark_safe("group." + name + ".view");
rpc::rpc.mark_safe("group." + name + ".view.set");
rpc::rpc.mark_safe("group." + name + ".ratio.min");
rpc::rpc.mark_safe("group." + name + ".ratio.min.set");
rpc::rpc.mark_safe("group." + name + ".ratio.max");
rpc::rpc.mark_safe("group." + name + ".ratio.max.set");
rpc::rpc.mark_safe("group." + name + ".ratio.upload");
rpc::rpc.mark_safe("group." + name + ".ratio.upload.set");
if (rpc::call_command_value("method.use_intermediate") == 3) {
// Cleaned up in 0.16.1:
CMD2_REDIRECT_STR_NO_EXPORT("group2." + name + ".view", "group." + name + ".view");
CMD2_REDIRECT_STR_NO_EXPORT("group2." + name + ".view.set", "group." + name + ".view.set");
CMD2_REDIRECT_STR_NO_EXPORT("group2." + name + ".ratio.min", "group." + name + ".ratio.min");
CMD2_REDIRECT_STR_NO_EXPORT("group2." + name + ".ratio.min.set", "group." + name + ".ratio.min.set");
CMD2_REDIRECT_STR_NO_EXPORT("group2." + name + ".ratio.max", "group." + name + ".ratio.max");
CMD2_REDIRECT_STR_NO_EXPORT("group2." + name + ".ratio.max.set", "group." + name + ".ratio.max.set");
CMD2_REDIRECT_STR_NO_EXPORT("group2." + name + ".ratio.upload", "group." + name + ".ratio.upload");
CMD2_REDIRECT_STR_NO_EXPORT("group2." + name + ".ratio.upload.set", "group." + 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;
@@ -171,12 +183,16 @@ 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);
fprintf(output, "\n");
try {
file_print_list(++args.begin(), args.end(), output, file_print_delim_space);
fprintf(output, "\n");
} catch (...) {
fclose(output);
throw;
}
fclose(output);
return torrent::Object();
}
@@ -184,7 +200,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();
@@ -193,7 +208,7 @@ initialize_command_local() {
CMD2_VAR_C_STRING("system.api_version", (int64_t)API_VERSION);
CMD2_VAR_C_STRING("system.client_version", PACKAGE_VERSION);
CMD2_VAR_C_STRING("system.library_version", torrent::version());
CMD2_VAR_C_STRING("system.library_version", torrent::runtime::version());
CMD2_VAR_VALUE ("system.file.allocate", 0);
CMD2_VAR_VALUE ("system.file.max_size", (int64_t)512 << 30);
@@ -212,7 +227,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));
@@ -270,22 +286,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) \
@@ -317,4 +336,25 @@ initialize_command_local() {
CMD2_ANY_P("argument.3", std::bind(&rpc::command_base::argument_ref, 3));
CMD2_ANY_LIST ("group.insert", std::bind(&group_insert, std::placeholders::_2));
rpc::rpc.mark_safe("system.api_version");
rpc::rpc.mark_safe("system.client_version");
rpc::rpc.mark_safe("system.library_version");
rpc::rpc.mark_safe("system.file.max_size");
rpc::rpc.mark_safe("system.file.split_size");
rpc::rpc.mark_safe("system.file.split_suffix");
rpc::rpc.mark_safe("directory.default");
rpc::rpc.mark_safe("session.path");
rpc::rpc.mark_safe("session.use_lock");
rpc::rpc.mark_safe("session.on_completion");
rpc::rpc.mark_safe("pieces.sync.always_safe");
rpc::rpc.mark_safe("pieces.sync.timeout");
rpc::rpc.mark_safe("pieces.sync.timeout_safe");
rpc::rpc.mark_safe("pieces.preload.type");
rpc::rpc.mark_safe("pieces.preload.min_size");
rpc::rpc.mark_safe("pieces.preload.min_rate");
rpc::rpc.mark_safe("pieces.memory.max");
rpc::rpc.mark_safe("pieces.hash.on_completion");
}
+30 -55
View File
@@ -8,53 +8,23 @@
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "control.h"
#include "command_helpers.h"
#include "globals.h"
#include "setup.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"
static const int log_flag_use_gz = 0x1;
static const int log_flag_append_pid = 0x2;
static const int log_flag_append_file = 0x4;
void
log_add_group_output_str(const char* group_name, const char* output_id) {
int log_group = torrent::option_find_string(torrent::OPTION_LOG_GROUP, group_name);
torrent::log_add_group_output(log_group, output_id);
}
torrent::Object
apply_log_open(int output_flags, const torrent::Object::list_type& args) {
if (args.size() < 2)
throw torrent::input_error("Invalid number of arguments.");
apply_log_open(int output_flags, const torrent::Object::list_type& raw_args) {
std::vector<std::string> 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());
if ((output_flags & log_flag_append_pid)) {
char buffer[32];
snprintf(buffer, 32, ".%li", (long)getpid());
file_name += buffer;
}
bool append = (output_flags & log_flag_append_file);
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);
while (itr != args.end())
log_add_group_output_str((itr++)->as_string().c_str(), output_id.c_str());
for (const auto& arg : raw_args)
args.push_back(arg.as_string());
apply_log_open_str(output_flags, args);
return torrent::Object();
}
@@ -62,9 +32,8 @@ 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());
log_add_group_output_str(args.front().as_string(), args.back().as_string());
return torrent::Object();
}
@@ -86,7 +55,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.");
@@ -118,6 +87,9 @@ log_vmmap_dump(const std::string& str) {
FILE* log_file = fopen(str.c_str(), "w");
if (log_file == NULL)
throw torrent::input_error("Could not open log file: " + str);
for (auto& all_mapping : all_mappings) {
fprintf(log_file, "%8p-%8p [%5llxk]\n", all_mapping.ptr, (char*)all_mapping.ptr + all_mapping.length, (long long unsigned int)(all_mapping.length / 1024));
}
@@ -128,19 +100,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
}
+166 -77
View File
@@ -3,20 +3,22 @@
#include <functional>
#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/runtime/network_config.h>
#include <torrent/runtime/runtime.h>
#include <torrent/runtime/socket_manager.h>
#include <torrent/tracker/tracker.h>
#include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h>
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "core/download.h"
#include "core/manager.h"
#include "rpc/scgi.h"
@@ -24,24 +26,25 @@
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#ifdef HAVE_SYSTEMD
#include <sys/socket.h>
#include <systemd/sd-daemon.h>
#endif
torrent::Object
apply_encryption(const torrent::Object::list_type& args) {
uint32_t options_mask = torrent::net::NetworkConfig::encryption_none;
uint32_t options_mask = torrent::runtime::NetworkConfig::encryption_none;
for (const auto& arg : args) {
uint32_t opt = torrent::option_find_string(torrent::OPTION_ENCRYPTION, arg.as_string().c_str());
if (opt == torrent::net::NetworkConfig::encryption_none)
options_mask = torrent::net::NetworkConfig::encryption_none;
if (opt == torrent::runtime::NetworkConfig::encryption_none)
options_mask = torrent::runtime::NetworkConfig::encryption_none;
else
options_mask |= opt;
}
torrent::config::network_config()->set_encryption_options(options_mask);
torrent::runtime::network_config()->set_encryption_options(options_mask);
return torrent::Object();
}
@@ -53,7 +56,7 @@ apply_tos(const torrent::Object::string_type& arg) {
if (!rpc::parse_whole_value_nothrow(arg.c_str(), &value, 16, 1))
value = torrent::option_find_string(torrent::OPTION_IP_TOS, arg.c_str());
torrent::config::network_config()->set_priority(value);
torrent::runtime::network_config()->set_priority(value);
return torrent::Object();
}
@@ -79,19 +82,18 @@ 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();
rpc::SCgi* scgi = new rpc::SCgi;
rak::address_info* ai = NULL;
torrent::sa_unique_ptr sa;
auto scgi = std::make_unique<rpc::SCgi>();
try {
int port, err;
char dummy;
int port{};
char dummy{};
char address[1024];
std::string path;
@@ -105,10 +107,11 @@ apply_scgi(const std::string& arg, int type) {
} 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)
throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + ".");
sa = torrent::sa_copy(ai->c_addrinfo()->ai_addr);
try {
sa = torrent::sa_copy(torrent::sa_lookup_address(address, AF_UNSPEC).get());
} catch (torrent::input_error& e) {
throw torrent::input_error("Could not bind address: " + std::string(e.what()));
}
lt_log_print(torrent::LOG_RPC_EVENTS, "SCGI socket is bound to an address and might be a security risk");
@@ -126,26 +129,75 @@ apply_scgi(const std::string& arg, int type) {
case 2:
default:
path = rak::path_expand(arg);
path = expand_path(arg);
unlink(path.c_str());
scgi->open_named(path);
break;
}
if (ai != NULL) rak::address_info::free_address_info(ai);
} catch (torrent::local_error& e) {
if (ai != NULL) rak::address_info::free_address_info(ai);
delete scgi;
throw torrent::input_error(e.what());
}
worker_thread->set_scgi(scgi);
scgi_thread::set_scgi(scgi.release());
return torrent::Object();
}
torrent::Object
apply_scgi_systemd() {
#ifdef HAVE_SYSTEMD
if (scgi_thread::scgi() != nullptr)
throw torrent::input_error("SCGI already enabled.");
int n = sd_listen_fds(0);
if (n < 1)
throw torrent::input_error("No systemd socket(s) provided (sd_listen_fds returned " +
std::to_string(n) + ").");
// Iterate over all provided fds. Use the first listening stream socket;
// close the rest. The systemd docs say unused fds should be closed.
int selected_fd = -1;
for (int i = 0; i < n; i++) {
int fd = SD_LISTEN_FDS_START + i;
if (selected_fd != -1) {
::close(fd);
continue;
}
auto err = sd_is_socket(fd, AF_UNSPEC, SOCK_STREAM, 1);
if (err < 0) {
// Safe to ignore errors here - we just skip it and move on.
::close(fd);
continue;
}
if (err == 0) {
// Not the socket we're looking for.
::close(fd);
continue;
}
selected_fd = fd;
}
if (selected_fd == -1)
throw torrent::input_error("No listening stream socket found among systemd-provided fds.");
initialize_rpc_handlers();
rpc::SCgi* scgi = new rpc::SCgi;
scgi->open_fd(selected_fd);
scgi_thread::set_scgi(scgi);
return torrent::Object();
#else
throw torrent::input_error("Systemd SCGI endpoint is not supported.");
#endif
}
torrent::Object
apply_xmlrpc_dialect(const std::string& arg) {
int value;
@@ -165,10 +217,9 @@ apply_xmlrpc_dialect(const std::string& arg) {
void
initialize_command_network() {
auto cm = torrent::connection_manager();
auto file_manager = torrent::file_manager();
auto http_stack = torrent::net_thread::http_stack();
auto network_config = torrent::config::network_config();
auto file_manager = torrent::file_manager();
auto http_stack = torrent::net_thread::http_stack();
auto nw_config = torrent::runtime::network_config();
CMD2_ANY_STRING ("encoding.add", std::bind(&apply_encoding_list, std::placeholders::_2));
@@ -177,18 +228,18 @@ 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::net::NetworkConfig::listen_port, network_config));
CMD2_ANY ("network.listen.backlog", std::bind(&torrent::net::NetworkConfig::listen_backlog, network_config));
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");
@@ -212,56 +263,94 @@ initialize_command_network() {
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", [network_config](auto, auto) { return network_config->send_buffer_size(); });
CMD2_ANY_VALUE_V ("network.send_buffer.size.set", [network_config](auto, auto& value) { return network_config->set_send_buffer_size(value); });
CMD2_ANY ("network.receive_buffer.size", [network_config](auto, auto) { return network_config->receive_buffer_size(); });
CMD2_ANY_VALUE_V ("network.receive_buffer.size.set", [network_config](auto, auto& value) { return network_config->set_receive_buffer_size(value); });
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", [network_config](auto, auto) { return network_config->bind_address_best_match_str(); });
CMD2_ANY_STRING_V("network.bind_address.set", [network_config](auto, auto& str) { return network_config->set_bind_address_str(str); });
CMD2_ANY ("network.bind_address.ipv4", [network_config](auto, auto) { return network_config->bind_inet_address_str(); });
CMD2_ANY_STRING_V("network.bind_address.ipv4.set", [network_config](auto, auto& str) { return network_config->set_bind_inet_address_str(str); });
CMD2_ANY ("network.bind_address.ipv6", [network_config](auto, auto) { return network_config->bind_inet6_address_str(); });
CMD2_ANY_STRING_V("network.bind_address.ipv6.set", [network_config](auto, auto& str) { return network_config->set_bind_inet6_address_str(str); });
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.local_address", [network_config](auto, auto) { return network_config->local_address_best_match_str(); });
CMD2_ANY_STRING_V("network.local_address.set", [network_config](auto, auto& str) { return network_config->set_local_address_str(str); });
CMD2_ANY ("network.local_address.ipv4", [network_config](auto, auto) { return network_config->local_inet_address_str(); });
CMD2_ANY_STRING_V("network.local_address.ipv4.set", [network_config](auto, auto& str) { return network_config->set_local_inet_address_str(str); });
CMD2_ANY ("network.local_address.ipv6", [network_config](auto, auto) { return network_config->local_inet6_address_str(); });
CMD2_ANY_STRING_V("network.local_address.ipv6.set", [network_config](auto, auto& str) { return network_config->set_local_inet6_address_str(str); });
CMD2_ANY ("network.local_address", [nw_config](auto, auto) { return nw_config->local_address_best_match_str(); });
CMD2_ANY_STRING_V("network.local_address.set", [nw_config](auto, auto& str) { return nw_config->set_local_address_str(str); });
CMD2_ANY ("network.local_address.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_address_str(); });
CMD2_ANY_STRING_V("network.local_address.ipv4.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet_address_str(str); });
CMD2_ANY ("network.local_address.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_address_str(); });
CMD2_ANY_STRING_V("network.local_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet6_address_str(str); });
CMD2_ANY ("network.proxy_address", [network_config](auto, auto) { return network_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.proxy_address", [nw_config](auto, auto) { return nw_config->proxy_address_str(); });
CMD2_ANY_STRING_V("network.proxy_address.set", [](auto, auto& str) { return control->core()->set_proxy_address(str); });
CMD2_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); });
CMD2_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); });
CMD2_ANY_VALUE_V ("network.max_open_files.set", [file_manager](auto, auto& value) { return file_manager->set_max_open_files(value); });
CMD2_ANY ("network.total_handshakes", [](auto, auto) { return torrent::total_handshakes(); });
CMD2_ANY ("network.open_sockets", [cm](auto, auto) { return cm->size(); });
CMD2_ANY ("network.max_open_sockets", [cm](auto, auto) { return cm->max_size(); });
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", [cm](auto, auto& value) { return cm->set_max_size(value); });
CMD2_ANY ("network.total_handshakes", [](auto, auto) { return torrent::runtime::total_handshakes(); });
CMD2_ANY ("network.open_sockets", [](auto, auto) { return torrent::runtime::socket_manager()->size(); });
CMD2_ANY ("network.max_open_sockets", [](auto, auto) { return torrent::runtime::socket_manager()->max_size(); });
CMD2_ANY_VALUE_V ("network.max_open_sockets.set", [](auto, auto& value) { return torrent::runtime::socket_manager()->set_max_size_and_adjust(value); });
CMD2_ANY_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1));
CMD2_ANY_STRING ("network.scgi.open_local", std::bind(&apply_scgi, std::placeholders::_2, 2));
CMD2_VAR_BOOL ("network.scgi.dont_route", false);
CMD2_ANY ("network.scgi.open_systemd", [](auto, auto) { return apply_scgi_systemd(); });
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.scgi.use_gzip", [](const auto&, const auto&) { return rpc::rpc.scgi_allow_compression(); });
CMD2_ANY_VALUE_V ("network.scgi.use_gzip.set", [](const auto&, const auto& arg) { return rpc::rpc.set_scgi_allow_compression(arg); });
CMD2_ANY ("network.scgi.gzip.min_size", [](const auto&, const auto&) { return rpc::rpc.scgi_min_compress_size(); });
CMD2_ANY_VALUE_V ("network.scgi.gzip.min_size.set", [](const auto&, const auto& arg) { return rpc::rpc.set_scgi_min_compress_size(arg); });
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_VAR_BOOL ("network.rpc.use_xmlrpc", true);
CMD2_VAR_BOOL ("network.rpc.use_jsonrpc", true);
CMD2_ANY ("network.block.ipv4", [network_config](auto, auto) { return network_config->is_block_ipv4(); });
CMD2_ANY_VALUE_V ("network.block.ipv4.set", [network_config](auto, auto& value) { return network_config->set_block_ipv4(value); });
CMD2_ANY ("network.block.ipv6", [network_config](auto, auto) { return network_config->is_block_ipv6(); });
CMD2_ANY_VALUE_V ("network.block.ipv6.set", [network_config](auto, auto& value) { return network_config->set_block_ipv6(value); });
CMD2_ANY ("network.block.ipv4in6", [network_config](auto, auto) { return network_config->is_block_ipv4in6(); });
CMD2_ANY_VALUE_V ("network.block.ipv4in6.set", [network_config](auto, auto& value) { return network_config->set_block_ipv4in6(value); });
CMD2_ANY ("network.block.outgoing", [network_config](auto, auto) { return network_config->is_block_outgoing(); });
CMD2_ANY_VALUE_V ("network.block.outgoing.set", [network_config](auto, auto& value) { return network_config->set_block_outgoing(value); });
CMD2_ANY ("network.prefer.ipv6", [network_config](auto, auto) { return network_config->is_prefer_ipv6(); });
CMD2_ANY_VALUE_V ("network.prefer.ipv6.set", [network_config](auto, auto& value) { return network_config->set_prefer_ipv6(value); });
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); });
rpc::rpc.mark_safe("network.port_open");
rpc::rpc.mark_safe("network.port_random");
rpc::rpc.mark_safe("network.port_range");
rpc::rpc.mark_safe("network.listen.port");
rpc::rpc.mark_safe("network.listen.backlog");
rpc::rpc.mark_safe("network.http.current_open");
rpc::rpc.mark_safe("network.http.max_cache_connections");
rpc::rpc.mark_safe("network.http.max_host_connections");
rpc::rpc.mark_safe("network.http.max_total_connections");
rpc::rpc.mark_safe("network.open_files");
rpc::rpc.mark_safe("network.max_open_files");
rpc::rpc.mark_safe("network.max_open_sockets");
rpc::rpc.mark_safe("network.total_handshakes");
rpc::rpc.mark_safe("network.send_buffer.size");
rpc::rpc.mark_safe("network.receive_buffer.size");
rpc::rpc.mark_safe("network.bind_address");
rpc::rpc.mark_safe("network.local_address");
rpc::rpc.mark_safe("network.xmlrpc.size_limit");
rpc::rpc.mark_safe("network.open_sockets");
rpc::rpc.mark_safe("network.http.cacert");
rpc::rpc.mark_safe("network.http.capath");
rpc::rpc.mark_safe("network.http.proxy_address");
rpc::rpc.mark_safe("network.proxy_address");
rpc::rpc.mark_safe("network.scgi.dont_route");
rpc::rpc.mark_safe("protocol.pex");
rpc::rpc.mark_safe("network.rpc.use_xmlrpc");
rpc::rpc.mark_safe("network.rpc.use_jsonrpc");
}
+36 -28
View File
@@ -1,33 +1,18 @@
#include "config.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>
#include "core/manager.h"
#include "display/utils.h"
#include <torrent/utils/string_manip.h>
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
torrent::Object
retrieve_p_id(torrent::Peer* peer) {
const torrent::HashString* hashString = &peer->id();
return rak::transform_hex(hashString->begin(), hashString->end());
}
torrent::Object
retrieve_p_id_html(torrent::Peer* peer) {
const torrent::HashString* hashString = &peer->id();
return rak::copy_escape_html(hashString->begin(), hashString->end());
}
#include "control.h"
#include "core/manager.h"
#include "display/utils.h"
torrent::Object
retrieve_p_address(torrent::Peer* peer) {
@@ -40,11 +25,6 @@ retrieve_p_address(torrent::Peer* peer) {
return addr_str;
}
torrent::Object
retrieve_p_port(torrent::Peer* peer) {
return torrent::sa_port(peer->peer_info()->socket_address());
}
torrent::Object
retrieve_p_client_version(torrent::Peer* peer) {
char buf[128];
@@ -55,18 +35,20 @@ retrieve_p_client_version(torrent::Peer* peer) {
torrent::Object
retrieve_p_options_str(torrent::Peer* peer) {
return rak::transform_hex(peer->peer_info()->options(), peer->peer_info()->options() + 8);
return torrent::utils::transform_to_hex_str(peer->peer_info()->options(), peer->peer_info()->options() + 8);
}
torrent::Object
retrieve_p_completed_percent(torrent::Peer* peer) {
if (peer->bitfield()->size_bits() == 0)
return int64_t(0);
return (100 * peer->bitfield()->size_set()) / peer->bitfield()->size_bits();
}
void
initialize_command_peer() {
CMD2_PEER("p.id", std::bind(&retrieve_p_id, std::placeholders::_1));
CMD2_PEER("p.id_html", std::bind(&retrieve_p_id_html, std::placeholders::_1));
CMD2_PEER("p.id", [](auto* peer, auto) { return torrent::utils::transform_to_hex_str(peer->id()); });
CMD2_PEER("p.id_html", [](auto* peer, auto) { return torrent::utils::copy_escape_html_str(peer->id()); });
CMD2_PEER("p.client_version", std::bind(&retrieve_p_client_version, std::placeholders::_1));
CMD2_PEER("p.options_str", std::bind(&retrieve_p_options_str, std::placeholders::_1));
@@ -80,7 +62,7 @@ initialize_command_peer() {
CMD2_PEER("p.is_preferred", std::bind(&torrent::PeerInfo::is_preferred, std::bind(&torrent::Peer::peer_info, std::placeholders::_1)));
CMD2_PEER("p.address", std::bind(&retrieve_p_address, std::placeholders::_1));
CMD2_PEER("p.port", std::bind(&retrieve_p_port, std::placeholders::_1));
CMD2_PEER("p.port", [](auto* peer, auto) { return torrent::sa_port(peer->peer_info()->socket_address()); });
CMD2_PEER("p.completed_percent", std::bind(&retrieve_p_completed_percent, std::placeholders::_1));
@@ -98,4 +80,30 @@ initialize_command_peer() {
CMD2_PEER_V("p.disconnect", std::bind(&torrent::Peer::disconnect, std::placeholders::_1, 0));
CMD2_PEER_V("p.disconnect_delayed", std::bind(&torrent::Peer::disconnect, std::placeholders::_1, torrent::ConnectionList::disconnect_delayed));
rpc::rpc.mark_safe("p.address");
rpc::rpc.mark_safe("p.port");
rpc::rpc.mark_safe("p.client_version");
rpc::rpc.mark_safe("p.options_str");
rpc::rpc.mark_safe("p.id");
rpc::rpc.mark_safe("p.id_html");
rpc::rpc.mark_safe("p.up_rate");
rpc::rpc.mark_safe("p.up_total");
rpc::rpc.mark_safe("p.down_rate");
rpc::rpc.mark_safe("p.down_total");
rpc::rpc.mark_safe("p.peer_rate");
rpc::rpc.mark_safe("p.peer_total");
rpc::rpc.mark_safe("p.is_encrypted");
rpc::rpc.mark_safe("p.is_incoming");
rpc::rpc.mark_safe("p.is_obfuscated");
rpc::rpc.mark_safe("p.is_snubbed");
rpc::rpc.mark_safe("p.is_unwanted");
rpc::rpc.mark_safe("p.is_preferred");
rpc::rpc.mark_safe("p.snubbed");
rpc::rpc.mark_safe("p.snubbed.set");
rpc::rpc.mark_safe("p.banned");
rpc::rpc.mark_safe("p.banned.set");
rpc::rpc.mark_safe("p.completed_percent");
rpc::rpc.mark_safe("p.disconnect");
rpc::rpc.mark_safe("p.disconnect_delayed");
}
+73 -12
View File
@@ -8,7 +8,6 @@
#include "core/manager.h"
#include "ui/root.h"
#include "rak/address_info.h"
#include "rpc/parse.h"
#include "rpc/parse_commands.h"
@@ -21,21 +20,26 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
unsigned int prefixWidth, ret;
char dummy;
char host[1024];
rak::address_info* ai;
torrent::sa_unique_ptr sa;
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.");
if (ret < 1)
throw torrent::input_error("Invalid address/prefix.");
try {
sa = torrent::sa_copy(torrent::sa_lookup_address(host, AF_INET).get());
} catch (torrent::input_error& e) {
throw torrent::input_error("Could not resolve host: " + std::string(e.what()));
}
uint32_t begin, end;
auto sa = torrent::sa_copy(ai->c_addrinfo()->ai_addr);
auto sa_addr = htonl(reinterpret_cast<sockaddr_in*>(sa.get())->sin_addr.s_addr);
begin = end = sa_addr;
rak::address_info::free_address_info(ai);
if (ret == 2) {
if (++itr != args.end())
throw torrent::input_error("Cannot specify both network and range end.");
@@ -48,13 +52,14 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis
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.");
try {
sa = torrent::sa_copy(torrent::sa_lookup_address(itr->as_string(), AF_INET).get());
} catch (torrent::input_error& e) {
throw torrent::input_error("Could not resolve host: " + std::string(e.what()));
}
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_addr;
}
@@ -199,4 +204,60 @@ initialize_command_throttle() {
CMD2_ANY_STRING ("throttle.up.rate", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_up | throttle_info_rate));
CMD2_ANY_STRING ("throttle.down.max", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_down | throttle_info_max));
CMD2_ANY_STRING ("throttle.down.rate", std::bind(&retrieve_throttle_info, std::placeholders::_2, throttle_info_down | throttle_info_rate));
rpc::rpc.mark_safe("throttle.unchoked_uploads");
rpc::rpc.mark_safe("throttle.max_unchoked_uploads");
rpc::rpc.mark_safe("throttle.unchoked_downloads");
rpc::rpc.mark_safe("throttle.max_unchoked_downloads");
rpc::rpc.mark_safe("throttle.min_peers.normal");
rpc::rpc.mark_safe("throttle.min_peers.normal.set");
rpc::rpc.mark_safe("throttle.max_peers.normal");
rpc::rpc.mark_safe("throttle.max_peers.normal.set");
rpc::rpc.mark_safe("throttle.min_peers.seed");
rpc::rpc.mark_safe("throttle.min_peers.seed.set");
rpc::rpc.mark_safe("throttle.max_peers.seed");
rpc::rpc.mark_safe("throttle.max_peers.seed.set");
rpc::rpc.mark_safe("throttle.min_uploads");
rpc::rpc.mark_safe("throttle.min_uploads.set");
rpc::rpc.mark_safe("throttle.max_uploads");
rpc::rpc.mark_safe("throttle.max_uploads.set");
rpc::rpc.mark_safe("throttle.min_downloads");
rpc::rpc.mark_safe("throttle.min_downloads.set");
rpc::rpc.mark_safe("throttle.max_downloads");
rpc::rpc.mark_safe("throttle.max_downloads.set");
rpc::rpc.mark_safe("throttle.max_uploads.div");
rpc::rpc.mark_safe("throttle.max_uploads.div.set");
rpc::rpc.mark_safe("throttle.max_uploads.div._val");
rpc::rpc.mark_safe("throttle.max_uploads.div._val.set");
rpc::rpc.mark_safe("throttle.max_uploads.global");
rpc::rpc.mark_safe("throttle.max_uploads.global.set");
rpc::rpc.mark_safe("throttle.max_uploads.global._val");
rpc::rpc.mark_safe("throttle.max_uploads.global._val.set");
rpc::rpc.mark_safe("throttle.max_downloads.div");
rpc::rpc.mark_safe("throttle.max_downloads.div.set");
rpc::rpc.mark_safe("throttle.max_downloads.div._val");
rpc::rpc.mark_safe("throttle.max_downloads.div._val.set");
rpc::rpc.mark_safe("throttle.max_downloads.global");
rpc::rpc.mark_safe("throttle.max_downloads.global.set");
rpc::rpc.mark_safe("throttle.max_downloads.global._val");
rpc::rpc.mark_safe("throttle.max_downloads.global._val.set");
rpc::rpc.mark_safe("throttle.global_up.rate");
rpc::rpc.mark_safe("throttle.global_up.total");
rpc::rpc.mark_safe("throttle.global_up.max_rate");
rpc::rpc.mark_safe("throttle.global_up.max_rate.set");
rpc::rpc.mark_safe("throttle.global_up.max_rate.set_kb");
rpc::rpc.mark_safe("throttle.global_down.rate");
rpc::rpc.mark_safe("throttle.global_down.total");
rpc::rpc.mark_safe("throttle.global_down.max_rate");
rpc::rpc.mark_safe("throttle.global_down.max_rate.set");
rpc::rpc.mark_safe("throttle.global_down.max_rate.set_kb");
rpc::rpc.mark_safe("throttle.up.max");
rpc::rpc.mark_safe("throttle.up.rate");
rpc::rpc.mark_safe("throttle.down.max");
rpc::rpc.mark_safe("throttle.down.rate");
}
+67 -43
View File
@@ -3,8 +3,10 @@
#include <cassert>
#include <cstdio>
#include <netdb.h>
#include <torrent/net/network_config.h>
#include <torrent/net/resolver.h>
#include <torrent/runtime/network_config.h>
#include <torrent/runtime/network_manager.h>
#include <torrent/system/callbacks.h>
#include <torrent/tracker/dht_controller.h>
#include <torrent/tracker/tracker.h>
#include <torrent/utils/log.h>
@@ -27,9 +29,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];
@@ -44,21 +43,23 @@ 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);
// TODO: Move this lookup to DhtController.
auto callback_id = torrent::system::make_callback_id();
// Currently discarding SOCK_STREAM.
torrent::this_thread::resolver()->resolve_specific(nullptr, host_str, PF_INET, [host_str, port](torrent::c_sa_shared_ptr sa, int err) {
torrent::this_thread::resolver()->resolve_specific(callback_id, host_str, PF_INET, [host_str, port](torrent::c_sa_shared_ptr sa, int err) {
if (sa == nullptr) {
lt_log_print(torrent::LOG_DHT_ERROR, "dht.add_node : could not resolve host : %s (%s)", gai_strerror(err), host_str.c_str());
return;
}
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();
@@ -70,16 +71,6 @@ apply_enable_trackers(int64_t arg) {
for (auto download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.disable(); });
} else if (rpc::call_command_value("trackers.use_udp") == 0) {
for (auto download : *control->core()->download_list()) {
download->tracker_controller().for_each([](auto& tracker) {
if (tracker.type() == torrent::TRACKER_UDP)
tracker.disable();
else
tracker.enable();
});
}
} else {
for (auto download : *control->core()->download_list())
download->tracker_controller().for_each([](auto& tracker) { tracker.enable(); });
@@ -90,10 +81,10 @@ apply_enable_trackers(int64_t arg) {
void
initialize_command_tracker() {
CMD2_TRACKER ("t.is_busy", std::bind(&torrent::tracker::Tracker::is_busy, std::placeholders::_1));
CMD2_TRACKER ("t.is_busy", std::bind(&torrent::tracker::Tracker::is_requesting, std::placeholders::_1));
CMD2_TRACKER ("t.is_enabled", std::bind(&torrent::tracker::Tracker::is_enabled, std::placeholders::_1));
CMD2_TRACKER ("t.is_extra_tracker", std::bind(&torrent::tracker::Tracker::is_extra_tracker, std::placeholders::_1));
CMD2_TRACKER ("t.is_open", std::bind(&torrent::tracker::Tracker::is_busy, std::placeholders::_1));
CMD2_TRACKER ("t.is_open", std::bind(&torrent::tracker::Tracker::is_requesting, std::placeholders::_1));
CMD2_TRACKER ("t.is_scrapable", std::bind(&torrent::tracker::Tracker::is_scrapable, std::placeholders::_1));
CMD2_TRACKER ("t.is_usable", std::bind(&torrent::tracker::Tracker::is_usable, std::placeholders::_1));
@@ -110,49 +101,82 @@ initialize_command_tracker() {
CMD2_TRACKER ("t.type", std::bind(&torrent::tracker::Tracker::type, std::placeholders::_1));
CMD2_TRACKER ("t.id", std::bind(&torrent::tracker::Tracker::tracker_id, std::placeholders::_1));
CMD2_TRACKER ("t.latest_event", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().latest_event(); });
CMD2_TRACKER ("t.latest_new_peers", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().latest_new_peers(); });
CMD2_TRACKER ("t.latest_sum_peers", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().latest_sum_peers(); });
CMD2_TRACKER ("t.latest_event", [](auto* tracker, auto) { return tracker->state().latest_event(); });
CMD2_TRACKER ("t.latest_new_peers", [](auto* tracker, auto) { return tracker->state().latest_new_peers(); });
CMD2_TRACKER ("t.latest_sum_peers", [](auto* tracker, auto) { return tracker->state().latest_sum_peers(); });
CMD2_TRACKER ("t.normal_interval", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().normal_interval(); });
CMD2_TRACKER ("t.min_interval", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().min_interval(); });
CMD2_TRACKER ("t.normal_interval", [](auto* tracker, auto) { return tracker->state().normal_interval(); });
CMD2_TRACKER ("t.min_interval", [](auto* tracker, auto) { return tracker->state().min_interval(); });
CMD2_TRACKER ("t.activity_time_next", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().activity_time_next(); });
CMD2_TRACKER ("t.activity_time_last", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().activity_time_last(); });
CMD2_TRACKER ("t.activity_time_next", [](auto* tracker, auto) { return tracker->state().activity_time_next(); });
CMD2_TRACKER ("t.activity_time_last", [](auto* tracker, auto) { return tracker->state().activity_time_last(); });
CMD2_TRACKER ("t.success_time_next", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().success_time_next(); });
CMD2_TRACKER ("t.success_time_last", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().success_time_last(); });
CMD2_TRACKER ("t.success_counter", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().success_counter(); });
CMD2_TRACKER ("t.success_time_next", [](auto* tracker, auto) { return tracker->state().success_time_next(); });
CMD2_TRACKER ("t.success_time_last", [](auto* tracker, auto) { return tracker->state().success_time_last(); });
CMD2_TRACKER ("t.success_counter", [](auto* tracker, auto) { return tracker->state().success_counter(); });
CMD2_TRACKER ("t.failed_time_next", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().failed_time_next(); });
CMD2_TRACKER ("t.failed_time_last", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().failed_time_last(); });
CMD2_TRACKER ("t.failed_counter", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().failed_counter(); });
CMD2_TRACKER ("t.failed_time_next", [](auto* tracker, auto) { return tracker->state().failed_time_next(); });
CMD2_TRACKER ("t.failed_time_last", [](auto* tracker, auto) { return tracker->state().failed_time_last(); });
CMD2_TRACKER ("t.failed_counter", [](auto* tracker, auto) { return tracker->state().failed_counter(); });
CMD2_TRACKER ("t.scrape_time_last", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_time_last(); });
CMD2_TRACKER ("t.scrape_counter", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_counter(); });
CMD2_TRACKER ("t.scrape_time_last", [](auto* tracker, auto) { return tracker->state().scrape_time_last(); });
CMD2_TRACKER ("t.scrape_counter", [](auto* tracker, auto) { return tracker->state().scrape_counter(); });
CMD2_TRACKER ("t.scrape_complete", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_complete(); });
CMD2_TRACKER ("t.scrape_incomplete", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_incomplete(); });
CMD2_TRACKER ("t.scrape_downloaded", [](torrent::tracker::Tracker* tracker, [[maybe_unused]] auto o) -> auto { return tracker->state().scrape_downloaded(); });
CMD2_TRACKER ("t.scrape_complete", [](auto* tracker, auto) { return tracker->state().scrape_complete(); });
CMD2_TRACKER ("t.scrape_incomplete", [](auto* tracker, auto) { return tracker->state().scrape_incomplete(); });
CMD2_TRACKER ("t.scrape_downloaded", [](auto* tracker, auto) { return tracker->state().scrape_downloaded(); });
CMD2_ANY_VALUE ("trackers.enable", std::bind(&apply_enable_trackers, int64_t(1)));
CMD2_ANY_VALUE ("trackers.disable", std::bind(&apply_enable_trackers, int64_t(0)));
CMD2_VAR_BOOL ("trackers.delay_scrape", false);
CMD2_VAR_VALUE ("trackers.numwant", -1);
CMD2_VAR_BOOL ("trackers.use_udp", true);
CMD2_ANY ("trackers.use_udp", [](auto, auto) { return true; });
CMD2_ANY_VALUE_V ("trackers.use_udp.set", [](auto, auto) {
lt_log_print(torrent::LOG_ERROR, "trackers.use_udp.set is no longer supported", 0);
})
auto dht_manager = control->dht_manager();
CMD2_ANY_STRING_V ("dht.mode.set", std::bind(&core::DhtManager::set_mode, control->dht_manager(), std::placeholders::_2));
CMD2_ANY ("dht.port", std::bind(&torrent::tracker::DhtController::port, torrent::dht_controller()));
CMD2_ANY ("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 ("dht.override_port", std::bind(&torrent::runtime::NetworkConfig::override_dht_port, torrent::runtime::network_config()));
CMD2_ANY_VALUE_V ("dht.override_port.set", std::bind(&torrent::runtime::NetworkConfig::set_override_dht_port, torrent::runtime::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, dht_manager));
CMD2_ANY ("dht.throttle.name", std::bind(&core::DhtManager::throttle_name, dht_manager));
CMD2_ANY_STRING_V ("dht.throttle.name.set", std::bind(&core::DhtManager::set_throttle_name, dht_manager, std::placeholders::_2));
rpc::rpc.mark_safe("t.url");
rpc::rpc.mark_safe("t.group");
rpc::rpc.mark_safe("t.id");
rpc::rpc.mark_safe("t.type");
rpc::rpc.mark_safe("t.is_usable");
rpc::rpc.mark_safe("t.is_busy");
rpc::rpc.mark_safe("t.is_enabled");
rpc::rpc.mark_safe("t.is_enabled.set");
rpc::rpc.mark_safe("t.is_extra_tracker");
rpc::rpc.mark_safe("t.is_open");
rpc::rpc.mark_safe("t.normal_interval");
rpc::rpc.mark_safe("t.scrape_time_last");
rpc::rpc.mark_safe("t.scrape_counter");
rpc::rpc.mark_safe("t.success_time_last");
rpc::rpc.mark_safe("t.success_counter");
rpc::rpc.mark_safe("t.failed_time_last");
rpc::rpc.mark_safe("t.failed_counter");
rpc::rpc.mark_safe("t.activity_time_last");
rpc::rpc.mark_safe("t.activity_time_next");
rpc::rpc.mark_safe("t.scrape_complete");
rpc::rpc.mark_safe("t.scrape_incomplete");
rpc::rpc.mark_safe("t.scrape_downloaded");
rpc::rpc.mark_safe("dht.mode.set");
rpc::rpc.mark_safe("dht.port");
rpc::rpc.mark_safe("dht.override_port");
rpc::rpc.mark_safe("dht.add_node");
rpc::rpc.mark_safe("dht.statistics");
rpc::rpc.mark_safe("trackers.numwant");
rpc::rpc.mark_safe("trackers.use_udp");
}
+46 -2
View File
@@ -4,7 +4,6 @@
#include <ctime>
#include <regex>
#include <rak/algorithm.h>
#include <torrent/utils/log.h>
#include "core/manager.h"
@@ -730,6 +729,26 @@ apply_arith_count(const torrent::Object::list_type& args) {
return val;
}
// Get the median of an unordered set of numbers of arbitrary
// type by modifing the underlying dataset
template <typename T = double, typename _InputIter>
T median(_InputIter __first, _InputIter __last) {
T __med;
unsigned int __size = __last - __first;
unsigned int __middle = __size / 2;
_InputIter __target1 = __first + __middle;
std::nth_element(__first, __target1, __last);
__med = *__target1;
if (__size % 2 == 0) {
_InputIter __target2 = std::max_element(__first, __target1);
__med = (__med + *__target2) / 2.0;
}
return __med;
}
int64_t
apply_arith_other(const char* op, const torrent::Object::list_type& args) {
if (args.size() == 0)
@@ -739,7 +758,8 @@ apply_arith_other(const char* op, const torrent::Object::list_type& args) {
return (int64_t)(apply_math_basic(op, std::plus<int64_t>(), args) / apply_arith_count(args));
} else if (strcmp(op, "median") == 0) {
std::vector<int64_t> result = as_vector(args);
return (int64_t)rak::median(result.begin(), result.end());
return (int64_t)median(result.begin(), result.end());
} else {
throw torrent::input_error("Wrong operation supplied to apply_arith_other.");
}
@@ -888,4 +908,28 @@ initialize_command_ui() {
return control->object_storage()->get_str(display::color_vars[color_id]);
});
}
rpc::rpc.mark_safe("view.set_visible");
rpc::rpc.mark_safe("view.set_not_visible");
rpc::rpc.mark_safe("cat");
rpc::rpc.mark_safe("if");
rpc::rpc.mark_safe("branch");
rpc::rpc.mark_safe("and");
rpc::rpc.mark_safe("or");
rpc::rpc.mark_safe("not");
rpc::rpc.mark_safe("value");
rpc::rpc.mark_safe("compare");
rpc::rpc.mark_safe("elapsed.less");
rpc::rpc.mark_safe("elapsed.greater");
rpc::rpc.mark_safe("convert.gm_time");
rpc::rpc.mark_safe("convert.gm_date");
rpc::rpc.mark_safe("convert.time");
rpc::rpc.mark_safe("convert.date");
rpc::rpc.mark_safe("convert.elapsed_time");
rpc::rpc.mark_safe("convert.kb");
rpc::rpc.mark_safe("convert.mb");
rpc::rpc.mark_safe("convert.xb");
rpc::rpc.mark_safe("convert.throttle");
}
+28 -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,7 +25,9 @@
#include "rpc/lua.h"
#include "rpc/parse_commands.h"
#include "rpc/object_storage.h"
#include "session/session_manager.h"
#include "ui/root.h"
#include "utils/watch_ready_queue.h"
Control::Control()
: m_ui(new ui::Root()),
@@ -36,11 +37,12 @@ Control::Control()
m_commandScheduler(new rpc::CommandScheduler()),
m_objectStorage(new rpc::object_storage()),
m_lua_engine(new rpc::LuaEngine()),
m_directory_events(new torrent::directory_events()) {
m_directory_events(new torrent::directory_events()),
m_watch_ready_queue(new utils::WatchReadyQueue()) {
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 +52,7 @@ Control::Control()
}
Control::~Control() {
m_viewManager.reset();
m_view_manager.reset();
m_ui.reset();
m_display.reset();
@@ -58,6 +60,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,8 +71,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_core->set_hashing_view(*m_view_manager->find_throw("hashing"));
m_ui->init(this);
@@ -81,11 +85,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();
@@ -103,7 +111,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
@@ -115,18 +123,20 @@ Control::is_shutdown_completed() {
if (torrent::net_thread::http_stack()->size() != 0 || !core()->http_queue()->empty())
return false;
return torrent::is_inactive();
return core()->is_download_shutdown_completed();
}
void
Control::handle_shutdown() {
m_watch_ready_queue->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);
@@ -135,13 +145,9 @@ 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);
}
m_shutdownQuick = true;
m_shutdownReceived = false;
}
+10 -4
View File
@@ -38,6 +38,10 @@ namespace torrent {
class directory_events;
}
namespace utils {
class WatchReadyQueue;
}
class Control {
public:
Control();
@@ -57,8 +61,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(); }
@@ -70,6 +74,7 @@ public:
rpc::LuaEngine* lua_engine() { return m_lua_engine.get(); }
torrent::directory_events* directory_events() { return m_directory_events.get(); }
utils::WatchReadyQueue* watch_ready_queue() { return m_watch_ready_queue.get(); }
uint64_t tick() const { return m_tick; }
void inc_tick() { m_tick++; }
@@ -82,8 +87,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;
@@ -94,6 +99,7 @@ private:
std::unique_ptr<rpc::object_storage> m_objectStorage;
std::unique_ptr<rpc::LuaEngine> m_lua_engine;
std::unique_ptr<torrent::directory_events> m_directory_events;
std::unique_ptr<utils::WatchReadyQueue> m_watch_ready_queue;
uint64_t m_tick{};
+36 -49
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__);
@@ -35,13 +35,13 @@ DhtManager::~DhtManager() {
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();
@@ -61,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();
@@ -71,26 +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 (!torrent::dht_controller()->start()) {
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);
@@ -109,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;
@@ -161,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()) {
@@ -186,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) {
@@ -211,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) {
@@ -233,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,
@@ -252,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;
@@ -264,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);
@@ -276,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);
@@ -288,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;
}
}
-5
View File
@@ -20,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;
@@ -47,8 +44,6 @@ private:
bool m_warned{};
int m_start{dht_off};
std::string m_throttleName;
};
}
+13 -27
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));
@@ -32,21 +32,6 @@ Download::~Download() {
m_download = download_type();
}
void
Download::enable_udp_trackers(bool state) {
for (int idx = 0, end = m_download.tracker_controller().size(); idx < end; ++idx) {
auto tracker = m_download.tracker_controller().at(idx);
if (tracker.type() != torrent::TRACKER_UDP)
continue;
if (state)
tracker.enable();
else
tracker.disable();
}
}
uint32_t
Download::priority() {
return bencode()->get_key("rtorrent").get_key_value("priority");
@@ -118,29 +103,30 @@ 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 &&
(file_list->is_multi_file() ?
!file_list->is_root_dir_created() :
!file_stat.update(file_list->front()->frozen_path()))) {
!file_stat.update(file_list->front()->frozen_path().str()))) {
set_message("Cannot change the directory of an open download after the files have been moved.");
rpc::call_command("d.state.set", (int64_t)0, rpc::make_target(this));
control->core()->download_list()->close_directly(this);
throw torrent::input_error("Cannot change the directory of an open download atter the files have been moved.");
throw torrent::input_error("Cannot change the directory of an open download after the files have been moved.");
}
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);
}
-2
View File
@@ -70,8 +70,6 @@ public:
const std::string& message() const { return m_message; }
void set_message(const std::string& msg) { m_message = msg; }
void enable_udp_trackers(bool state);
uint32_t priority();
void set_priority(uint32_t p);
+20 -14
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>
@@ -16,11 +15,11 @@
#include <torrent/rate.h>
#include <torrent/data/file_utils.h>
#include <torrent/net/http_stack.h>
#include <torrent/utils/string_manip.h>
#include "control.h"
#include "globals.h"
#include "core/download.h"
#include "core/download_store.h"
#include "core/http_queue.h"
#include "core/manager.h"
#include "rpc/parse_commands.h"
@@ -110,8 +109,8 @@ DownloadFactory::receive_load() {
HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream);
itr->add_done_slot([this]() { receive_loaded(); });
itr->add_failed_slot([this](const std::string& error) { receive_failed(error); });
itr->add_done_slot(torrent::this_thread::thread(), [this]() { receive_loaded(); });
itr->add_failed_slot(torrent::this_thread::thread(), [this](const std::string& error) { receive_failed(error); });
m_variables["tied_to_file"] = (int64_t)false;
@@ -124,7 +123,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 +158,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;
@@ -239,9 +238,6 @@ DownloadFactory::receive_success() {
rpc::call_command("d.peers_max.set", rpc::call_command("throttle.max_peers.seed"), rpc::make_target(download));
}
if (!rpc::call_command_value("trackers.use_udp"))
download->enable_udp_trackers(false);
// Skip forcing trackers to scrape when rtorrent starts
if (m_initLoad && rpc::call_command_value("trackers.delay_scrape"))
download->set_resume_flags(torrent::Download::start_skip_tracker);
@@ -255,11 +251,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));
@@ -319,7 +325,7 @@ void
DownloadFactory::log_created(Download* download, torrent::Object* rtorrent) {
std::stringstream dump;
dump << "info_hash = " << torrent::hash_string_to_hex_str(download->info()->hash()) << std::endl;
dump << "info_hash = " << torrent::utils::transform_to_hex_str(download->info()->hash()) << std::endl;
dump << "session = " << (m_session ? "true" : "false") << std::endl;
if (download->download()->info()->is_meta_download())
+24 -19
View File
@@ -1,9 +1,9 @@
#include "config.h"
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <rak/string_manip.h>
#include <torrent/data/file.h>
#include <torrent/utils/resume.h>
#include <torrent/exceptions.h>
@@ -13,6 +13,7 @@
#include <torrent/object_stream.h>
#include <torrent/torrent.h>
#include <torrent/utils/log.h>
#include <torrent/utils/string_manip.h>
#include "rpc/parse_commands.h"
@@ -22,10 +23,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 +69,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();
@@ -84,10 +83,13 @@ DownloadList::find(const torrent::HashString& hash) {
DownloadList::iterator
DownloadList::find_hex(const char* hash) {
if (strlen(hash) < 40)
return end();
torrent::HashString key;
for (torrent::HashString::iterator itr = key.begin(), last = key.end(); itr != last; itr++, hash += 2)
*itr = (rak::hexchar_to_value(*hash) << 4) + rak::hexchar_to_value(*(hash + 1));
if (torrent::utils::transform_from_hex(hash, hash + 40, key) != key.end())
return end();
return std::find_if(begin(), end(), [key](Download* d) { return key == d->info()->hash(); });
}
@@ -199,10 +201,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 +641,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 +655,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().");
@@ -683,8 +683,10 @@ DownloadList::process_meta_download(Download* download) {
rpc::call_command("d.stop", torrent::Object(), rpc::make_target(download));
rpc::call_command("d.close", torrent::Object(), rpc::make_target(download));
std::string metafile = (*download->file_list()->begin())->frozen_path();
std::string metafile = (*download->file_list()->begin())->frozen_path().str();
std::fstream file(metafile.c_str(), std::ios::in | std::ios::binary);
if (!file.is_open()) {
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not read download metadata.");
return;
@@ -692,11 +694,13 @@ DownloadList::process_meta_download(Download* download) {
torrent::Object* bencode = new torrent::Object(torrent::Object::create_map());
file >> bencode->insert_key("info", torrent::Object());
if (file.fail()) {
delete bencode;
lt_log_print(torrent::LOG_TORRENT_ERROR, "Could not create download, the input is not a valid torrent.");
return;
}
file.close();
// Steal the keys we still need. The old download has no use for them.
@@ -707,6 +711,7 @@ DownloadList::process_meta_download(Download* download) {
bencode->insert_key("announce-list", torrent::Object()).swap(download->bencode()->get_key("announce-list"));
erase_ptr(download);
control->core()->try_create_download_from_meta_download(bencode, metafile);
}
-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
+2 -2
View File
@@ -15,8 +15,8 @@ HttpQueue::insert(const std::string& url, std::shared_ptr<std::ostream> stream)
for (auto& slot : m_signal_insert)
slot(*itr);
itr->add_done_slot([this, itr]() { erase(itr); });
itr->add_failed_slot([this, itr](auto) { erase(itr); });
itr->add_done_slot(torrent::this_thread::thread(), [this, itr]() { erase(itr); });
itr->add_failed_slot(torrent::this_thread::thread(), [this, itr](auto) { erase(itr); });
// TODO: Downloading http torrents doesn't seem to work.
// TODO: Quitting no longer works.
+107 -31
View File
@@ -1,26 +1,26 @@
#include "config.h"
#include "core/manager.h"
#include <cstdio>
#include <cstring>
#include <fstream>
#include <sstream>
#include <unistd.h>
#include <sys/select.h>
#include <rak/address_info.h>
#include <rak/regex.h>
#include <rak/path.h>
#include <rak/string_manip.h>
#include <torrent/utils/resume.h>
#include <torrent/object.h>
#include <torrent/connection_manager.h>
#include <torrent/error.h>
#include <torrent/exceptions.h>
#include <torrent/object_stream.h>
#include <torrent/throttle.h>
#include <torrent/net/http_stack.h>
#include <torrent/net/network_config.h>
#include <torrent/net/socket_address.h>
#include <torrent/runtime/network_config.h>
#include <torrent/runtime/network_manager.h>
#include <torrent/utils/log.h>
#include <torrent/utils/string_manip.h>
#include "rpc/parse_commands.h"
#include "utils/directory.h"
@@ -31,9 +31,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 {
@@ -49,11 +47,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>();
@@ -67,6 +64,20 @@ Manager::~Manager() {
torrent::Throttle::destroy_throttle(m_throttles["NULL"].first);
}
bool
Manager::is_download_shutdown_completed() {
for (const auto& download : *download_list()) {
// TODO: Why is this being checked?
// if (download->tracker_controller().is_active())
// return false;
if (download->tracker_controller().has_active_trackers_not_dht_scrape_disownable())
return false;
}
return true;
}
void
Manager::set_hashing_view(View* v) {
if (v == nullptr || m_hashingView != nullptr)
@@ -133,6 +144,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
@@ -175,12 +196,12 @@ 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;
}
@@ -190,7 +211,7 @@ Manager::listen_open() {
void
Manager::set_proxy_address(const std::string& addr) {
int port;
rak::address_info* ai;
torrent::sa_unique_ptr sa;
std::string buf(addr.length() + 1, '\0');
@@ -202,20 +223,18 @@ Manager::set_proxy_address(const std::string& addr) {
if (err == 1)
port = 80;
if ((err = rak::address_info::get_address_info(buf.data(), PF_INET, SOCK_STREAM, &ai)) != 0)
throw torrent::input_error("Could not set proxy address: " + std::string(rak::address_info::strerror(err)) + ".");
try {
auto sa = torrent::sa_copy(ai->c_addrinfo()->ai_addr);
torrent::sap_set_port(sa, port);
torrent::config::network_config()->set_proxy_address(sa.get());
rak::address_info::free_address_info(ai);
sa = torrent::sa_copy(torrent::sa_lookup_address(buf, AF_INET).get());
} catch (torrent::input_error& e) {
throw torrent::input_error("Could not resolve proxy address: " + std::string(e.what()));
}
try {
torrent::sa_set_port(sa.get(), port);
torrent::runtime::network_config()->set_proxy_address(sa.get());
} catch (torrent::input_error& e) {
rak::address_info::free_address_info(ai);
throw e;
}
}
@@ -232,9 +251,10 @@ is_data_uri(const std::string& uri) {
std::string
decode_data_uri(const std::string& uri) {
const auto start = uri.find("base64,", 5) + 7;
if (start == std::string::npos)
const auto pos = uri.find("base64,", 5);
if (pos == std::string::npos)
throw torrent::input_error("Invalid data uri: not base64 encoded.");
const auto start = pos + 7;
if (start >= uri.size())
throw torrent::input_error("Empty base64.");
return utils::decode_base64(uri.substr(start));
@@ -248,7 +268,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.
@@ -305,14 +325,70 @@ path_expand_transform(std::string path, const utils::directory_entry& entry) {
return path + entry.s_name;
}
namespace {
// Consider rewritting such that m_seq is replaced by first/last.
template <typename Sequence>
class split_iterator_t {
public:
typedef typename Sequence::const_iterator const_iterator;
typedef typename Sequence::value_type value_type;
split_iterator_t() {}
split_iterator_t(const Sequence& seq, value_type delim) :
m_seq(&seq),
m_delim(delim),
m_pos(seq.begin()),
m_next(std::find(seq.begin(), seq.end(), delim)) {
}
Sequence operator * () { return Sequence(m_pos, m_next); }
split_iterator_t& operator ++ () {
m_pos = m_next;
if (m_pos == m_seq->end())
return *this;
m_pos++;
m_next = std::find(m_pos, m_seq->end(), m_delim);
return *this;
}
bool operator == (const split_iterator_t&) const { return m_pos == m_seq->end(); }
bool operator != (const split_iterator_t&) const { return m_pos != m_seq->end(); }
private:
const Sequence* m_seq;
value_type m_delim;
const_iterator m_pos;
const_iterator m_next;
};
template <typename Sequence>
inline split_iterator_t<Sequence>
split_iterator(const Sequence& seq, typename Sequence::value_type delim) {
return split_iterator_t<Sequence>(seq, delim);
}
template <typename Sequence>
inline split_iterator_t<Sequence>
split_iterator(const Sequence&) {
return split_iterator_t<Sequence>();
}
}
// Move this somewhere better.
void
path_expand(std::vector<std::string>* paths, const std::string& pattern) {
std::vector<utils::Directory> currentCache;
std::vector<utils::Directory> nextCache;
rak::split_iterator_t<std::string> first = rak::split_iterator(pattern, '/');
rak::split_iterator_t<std::string> last = rak::split_iterator(pattern);
auto first = split_iterator(pattern, '/');
auto last = split_iterator(pattern);
if (first == last)
return;
@@ -321,7 +397,7 @@ path_expand(std::vector<std::string>* paths, const std::string& pattern) {
if ((*first).empty()) {
currentCache.push_back(utils::Directory("/"));
++first;
} else if (rak::trim(*first) == "~") {
} else if (torrent::utils::trim_spaces_str(*first) == "~") {
currentCache.push_back(utils::Directory("~"));
++first;
} else {
+9 -3
View File
@@ -21,7 +21,6 @@ class FileStatusCache;
namespace core {
class DownloadStore;
class HttpQueue;
typedef std::map<std::string, torrent::ThrottlePair> ThrottleMap;
@@ -36,8 +35,9 @@ public:
Manager();
~Manager();
bool is_download_shutdown_completed();
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(); }
@@ -63,6 +63,9 @@ public:
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);
@@ -95,7 +98,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;
@@ -106,11 +108,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
+2 -1
View File
@@ -35,7 +35,8 @@ ViewManager::insert(const std::string& name) {
View* view = new View();
view->initialize(name);
return base_type::insert(end(), view);
base_type::push_back(view);
return --end();
}
ViewManager::iterator
+4 -4
View File
@@ -2,16 +2,16 @@
#define RTORRENT_CORE_VIEW_MANAGER_H
#include <string>
#include <rak/unordered_vector.h>
#include <torrent/utils/unordered_vector.h>
#include "view.h"
namespace core {
class ViewManager : public rak::unordered_vector<View*> {
class ViewManager : public torrent::utils::unordered_vector<View*> {
public:
typedef rak::unordered_vector<View*> base_type;
typedef std::list<std::string> filter_args;
typedef torrent::utils::unordered_vector<View*> base_type;
typedef std::list<std::string> filter_args;
using base_type::iterator;
using base_type::const_iterator;
+3 -1
View File
@@ -4,7 +4,9 @@
#include <string>
#include <vector>
#if defined(HAVE_NCURSESW_CURSES_H)
#if defined(HAVE_NO_NCURSES)
#include "curses_stub.h"
#elif defined(HAVE_NCURSESW_CURSES_H)
#include <ncursesw/curses.h>
#elif defined(HAVE_NCURSESW_H)
#include <ncursesw.h>
+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();
}
}
+4
View File
@@ -4,7 +4,11 @@
#include <array>
#include <map>
#if defined(HAVE_NO_NCURSES)
#include "curses_stub.h"
#else
#include <curses.h>
#endif
namespace display {
+6
View File
@@ -0,0 +1,6 @@
// Dummy ncurses stub: provides the stdscr symbol expected by the codebase.
#include "curses_stub.h"
// Define stdscr as a null pointer; all ncurses calls are no-ops in this stub.
WINDOW* stdscr = nullptr;
+108
View File
@@ -0,0 +1,108 @@
// Dummy ncurses stub header for building rtorrent without ncurses.
// Provides types, macros, and no-op function stubs so the codebase
// compiles without a real curses library. All display functions become
// no-ops; use with system.daemon.set = true.
#ifndef RTORRENT_DISPLAY_CURSES_STUB_H
#define RTORRENT_DISPLAY_CURSES_STUB_H
#include <cstdarg>
#include <cstdio>
#include <cstddef>
// Opaque window type
typedef void* WINDOW;
// Character type used by curses
typedef unsigned int chtype;
typedef unsigned int attr_t;
// The standard screen
extern WINDOW* stdscr;
// Boolean constants and return codes
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef ERR
#define ERR (-1)
#endif
// Attribute constants
#define A_NORMAL 0
#define A_STANDOUT (1U << 8)
#define A_UNDERLINE (1U << 9)
#define A_REVERSE (1U << 10)
#define A_BLINK (1U << 11)
#define A_DIM (1U << 12)
#define A_BOLD (1U << 13)
// Color support
#define COLORS 0
#define COLOR_BLACK 0
#define COLOR_RED 1
#define COLOR_GREEN 2
#define COLOR_YELLOW 3
#define COLOR_BLUE 4
#define COLOR_MAGENTA 5
#define COLOR_CYAN 6
#define COLOR_WHITE 7
#define COLOR_PAIR(n) 0
// Key constants
#define KEY_DOWN 0x102
#define KEY_UP 0x103
#define KEY_LEFT 0x104
#define KEY_RIGHT 0x105
#define KEY_HOME 0x106
#define KEY_BACKSPACE 0x107
#define KEY_DC 0x14a
#define KEY_ENTER 0x157
#define KEY_NPAGE 0x152
#define KEY_PPAGE 0x153
#define KEY_END 0x168
#define KEY_MOUSE 0x199
#define KEY_RESIZE 0x19a
// Stubbed functions
inline WINDOW* initscr() { return nullptr; }
inline int endwin() { return 0; }
inline WINDOW* newwin(int, int, int, int) { return nullptr; }
inline int delwin(WINDOW*) { return 0; }
inline int wresize(WINDOW*, int, int) { return 0; }
inline int mvwin(WINDOW*, int, int) { return 0; }
inline int wnoutrefresh(WINDOW*) { return 0; }
inline int redrawwin(WINDOW*) { return 0; }
inline int werase(WINDOW*) { return 0; }
inline int wmove(WINDOW*, int, int) { return 0; }
inline int vw_printw(WINDOW*, char*, va_list) { return 0; }
inline int waddch(WINDOW*, const chtype) { return 0; }
inline int mvwaddch(WINDOW*, int, int, const chtype) { return 0; }
inline int mvwchgat(WINDOW*, int, int, int, attr_t, short, const void*) { return 0; }
inline int wattrset(WINDOW*, int) { return 0; }
inline int wattr_get(WINDOW*, attr_t*, short*, void*) { return 0; }
inline int wattr_set(WINDOW*, attr_t, short, void*) { return 0; }
inline int doupdate() { return 0; }
inline int start_color() { return 0; }
inline int use_default_colors() { return 0; }
inline int raw() { return 0; }
inline int noraw() { return 0; }
inline int noecho() { return 0; }
inline int nodelay(WINDOW*, bool) { return 0; }
inline int keypad(WINDOW*, bool) { return 0; }
inline int curs_set(int) { return 0; }
inline int init_pair(short, short, short) { return 0; }
inline int pair_content(short, short*, short*) { return 0; }
inline int resizeterm(int, int) { return 0; }
inline int getch() { return ERR; }
inline int set_escdelay(int) { return 0; }
// getyx / getmaxyx are macros in real ncurses; stub them as no-ops
#define getyx(w, y, x) do { (y) = 0; (x) = 0; } while (0)
#define getmaxyx(w, y, x) do { (y) = 24; (x) = 80; } while (0)
#endif // RTORRENT_DISPLAY_CURSES_STUB_H
+16 -51
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;
@@ -396,7 +361,7 @@ Frame::balance_row(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
(*itr)->balance(x, y, m_width, std::min((*itr)->m_height, height));
y += (*itr)->m_height;
height -= (*itr)->m_height;
height -= std::min(height, (*itr)->m_height);
}
}
@@ -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;
@@ -471,7 +436,7 @@ Frame::balance_column(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
(*itr)->balance(x, y, std::min((*itr)->m_width, width), m_height);
x += (*itr)->m_width;
width -= (*itr)->m_width;
width -= std::min(width, (*itr)->m_width);
}
}
+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 {
+13 -46
View File
@@ -1,43 +1,10 @@
// 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/string_manip.h>
#include "display/text_element_string.h"
#include <torrent/utils/string_manip.h>
#include "rpc/parse_commands.h"
#include "text_element_string.h"
namespace display {
@@ -53,17 +20,17 @@ TextElementStringBase::print(char* first, char* last, Canvas::attributes_list* a
auto buffer = std::make_unique<char[]>(last - first);
char* bufferLast = copy_string(buffer.get(), buffer.get() + (last - first), target);
first = rak::transform_hex(buffer.get(), bufferLast, first, last);
first = torrent::utils::transform_to_hex(buffer.get(), bufferLast, first, last);
} else if (m_flags & flag_escape_html) {
auto buffer = std::make_unique<char[]>(last - first);
char* bufferLast = copy_string(buffer.get(), buffer.get() + (last - first), target);
first = rak::copy_escape_html(buffer.get(), bufferLast, first, last);
first = torrent::utils::copy_escape_html(buffer.get(), bufferLast, first, last);
} else {
first = copy_string(first, last, target);
}
}
push_attribute(attributes, Attributes(first, baseAttribute));
@@ -71,16 +38,16 @@ TextElementStringBase::print(char* first, char* last, Canvas::attributes_list* a
}
char*
TextElementString::copy_string(char* first, char* last, rpc::target_type target) {
TextElementString::copy_string(char* first, char* last, [[maybe_unused]] rpc::target_type target) {
extent_type length = std::min<extent_type>(last - first, m_string.size());
std::memcpy(first, m_string.c_str(), length);
return first + length;
}
char*
TextElementCString::copy_string(char* first, char* last, rpc::target_type target) {
TextElementCString::copy_string(char* first, char* last, [[maybe_unused]] rpc::target_type target) {
extent_type length = std::min<extent_type>(last - first, m_length);
std::memcpy(first, m_string, length);
@@ -104,22 +71,22 @@ TextElementCommand::print(char* first, char* last, Canvas::attributes_list* attr
const std::string& str = result.as_string();
if (m_flags & flag_escape_hex) {
first = rak::transform_hex(str.c_str(), str.c_str() + str.size(), first, last);
first = torrent::utils::transform_to_hex(str.c_str(), str.c_str() + str.size(), first, last);
} else if (m_flags & flag_escape_html) {
first = rak::copy_escape_html(str.c_str(), str.c_str() + str.size(), first, last);
first = torrent::utils::copy_escape_html(str.c_str(), str.c_str() + str.size(), first, last);
} else {
size_t length = std::min<size_t>(str.size(), std::distance(first, last));
std::memcpy(first, str.c_str(), length);
first += std::min<size_t>(str.size(), length);
}
}
break;
}
case torrent::Object::TYPE_VALUE:
{
{
first += std::min<ptrdiff_t>(std::max(snprintf(first, last - first + 1, "%lld", (long long int)result.as_value()), 0), last - first + 1);
break;
}
-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_TEXT_ELEMENT_STRING_H
#define RTORRENT_DISPLAY_TEXT_ELEMENT_STRING_H
+28 -15
View File
@@ -7,7 +7,6 @@
#include <sstream>
#include <iomanip>
#include <torrent/exceptions.h>
#include <torrent/connection_manager.h>
#include <torrent/rate.h>
#include <torrent/throttle.h>
#include <torrent/torrent.h>
@@ -16,9 +15,11 @@
#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 <torrent/runtime/network_config.h>
#include <torrent/runtime/runtime.h>
#include <torrent/runtime/socket_manager.h>
#include "control.h"
#include "globals.h"
@@ -150,11 +151,11 @@ print_download_status(char* first, char* last, core::Download* d) {
if (d->is_hash_checking()) {
first = print_buffer(first, last, "Checking hash [%2i%%]",
(d->download()->chunks_hashed() * 100) / d->download()->file_list()->size_chunks());
d->download()->file_list()->size_chunks() != 0 ? (d->download()->chunks_hashed() * 100) / d->download()->file_list()->size_chunks() : 0);
} else if (d->tracker_controller().has_active_trackers_not_scrape()) {
auto tracker = d->tracker_controller().find_if([](const auto& t) {
return t.is_busy_not_scrape();
return t.is_requesting_not_scrape();
});
if (tracker.is_valid()) {
@@ -208,7 +209,7 @@ print_download_info_compact(char* first, char* last, core::Download* d) {
if (d->is_done())
first = print_buffer(first, last, " 100%% ");
else if (d->is_open())
first = print_buffer(first, last, " %2u%% ",(d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks());
first = print_buffer(first, last, " %2u%% ", d->download()->file_list()->size_chunks() != 0 ? (d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks() : 0);
else
first = print_buffer(first, last, " ");
@@ -260,7 +261,7 @@ print_download_percentage_done(char* first, char* last, core::Download* d) {
//return print_buffer(first, last, "[--%%]");
return print_buffer(first, last, " ");
else
return print_buffer(first, last, "[%2u%%]", (d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks());
return print_buffer(first, last, "[%2u%%]", d->download()->file_list()->size_chunks() != 0 ? (d->download()->file_list()->completed_chunks() * 100) / d->download()->file_list()->size_chunks() : 0);
}
char*
@@ -374,10 +375,9 @@ 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::config::network_config()->listen_port());
auto local_address = torrent::config::network_config()->local_address_best_match();
auto local_address = torrent::runtime::network_config()->local_address_best_match();
if (!torrent::sa_is_any(local_address.get())) {
first = print_buffer(first, last, " [Local ");
@@ -388,11 +388,24 @@ print_status_info(char* first, char* last) {
if (first > last)
throw torrent::internal_error("print_status_info(...) wrote past end of the buffer.");
auto bind_address = torrent::config::network_config()->bind_address_best_match();
auto bind_inet_address = torrent::runtime::network_config()->bind_inet_address();
auto bind_inet6_address = torrent::runtime::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 (!torrent::sa_is_any(bind_address.get())) {
if (show_bind_inet || show_bind_inet6) {
first = print_buffer(first, last, " [Bind ");
first = print_address(first, last, bind_address.get());
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, "]");
}
@@ -414,9 +427,9 @@ print_status_extra(char* first, char* last) {
torrent::net_thread::http_stack()->max_total_connections());
first = print_buffer(first, last, " [S %i/%i/%i]",
torrent::total_handshakes(),
torrent::connection_manager()->size(),
torrent::connection_manager()->max_size());
torrent::runtime::total_handshakes(),
torrent::runtime::socket_manager()->size(),
torrent::runtime::socket_manager()->max_size());
first = print_buffer(first, last, " [F %i/%i]",
torrent::file_manager()->open_files(),
-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
+59 -2
View File
@@ -3,7 +3,7 @@
#include <functional>
#include <torrent/utils/scheduler.h>
#include <torrent/utils/thread.h>
#include <torrent/system/thread.h>
#include "canvas.h"
#include "globals.h"
@@ -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;
@@ -102,6 +102,63 @@ protected:
torrent::utils::SchedulerEntry m_task_update;
};
// Return a range with a distance of no more than __distance and
// between __first and __last, centered on __middle1.
template <typename _InputIter, typename _Distance>
std::pair<_InputIter, _InputIter>
advance_bidirectional(_InputIter __first, _InputIter __middle1, _InputIter __last, _Distance __distance) {
_InputIter __middle2 = __middle1;
do {
if (!__distance)
break;
if (__middle2 != __last) {
++__middle2;
--__distance;
} else if (__middle1 == __first) {
break;
}
if (!__distance)
break;
if (__middle1 != __first) {
--__middle1;
--__distance;
} else if (__middle2 == __last) {
break;
}
} while (true);
return std::make_pair(__middle1, __middle2);
}
template <typename _InputIter, typename _Distance>
_InputIter
advance_forward(_InputIter __first, _InputIter __last, _Distance __distance) {
while (__first != __last && __distance != 0) {
__first++;
__distance--;
}
return __first;
}
template <typename _InputIter, typename _Distance>
_InputIter
advance_backward(_InputIter __first, _InputIter __last, _Distance __distance) {
while (__first != __last && __distance != 0) {
__first--;
__distance--;
}
return __first;
}
}
#endif
+4 -4
View File
@@ -1,17 +1,17 @@
#include "config.h"
#include "display/window_download_chunks_seen.h"
#include <cmath>
#include <stdexcept>
#include <rak/string_manip.h>
#include <torrent/bitfield.h>
#include <torrent/data/block.h>
#include <torrent/data/block_list.h>
#include <torrent/data/transfer_list.h>
#include <torrent/utils/string_manip.h>
#include "core/download.h"
#include "window_download_chunks_seen.h"
namespace display {
WindowDownloadChunksSeen::WindowDownloadChunksSeen(core::Download* d, unsigned int *focus) :
@@ -82,7 +82,7 @@ WindowDownloadChunksSeen::redraw() {
attr = A_BOLD;
}
m_canvas->print_char(attr | rak::value_to_hexchar<0>(std::min<uint8_t>(*chunk, 0xF)));
m_canvas->print_char(attr | torrent::utils::value_to_hex0(std::min<uint8_t>(*chunk, 0xF)));
chunk++;
if ((chunk - seen) % 10 == 0) {
+8 -10
View File
@@ -1,17 +1,15 @@
#include "config.h"
#include "display/color_map.h"
#include <rak/algorithm.h>
#include "globals.h"
#include "core/download.h"
#include "core/view.h"
#include "display/canvas.h"
#include "display/utils.h"
#include "display/window_download_list.h"
#include "rpc/parse_commands.h"
#include "canvas.h"
#include "globals.h"
#include "utils.h"
#include "window_download_list.h"
namespace display {
WindowDownloadList::WindowDownloadList() :
@@ -104,10 +102,10 @@ WindowDownloadList::redraw() {
typedef std::pair<core::View::iterator, core::View::iterator> Range;
Range range = rak::advance_bidirectional(m_view->begin_visible(),
m_view->focus() != m_view->end_visible() ? m_view->focus() : m_view->begin_visible(),
m_view->end_visible(),
page_size(layout_name));
Range range = advance_bidirectional(m_view->begin_visible(),
m_view->focus() != m_view->end_visible() ? m_view->focus() : m_view->begin_visible(),
m_view->end_visible(),
page_size(layout_name));
// Make sure we properly fill out the last lines so it looks like
// there are more torrents, yet don't hide it if we got the last one
@@ -2,7 +2,6 @@
#include <cmath>
#include <stdexcept>
#include <rak/string_manip.h>
#include <torrent/data/block_list.h>
#include <torrent/data/transfer_list.h>
+11 -4
View File
@@ -135,8 +135,11 @@ WindowFileList::redraw() {
m_canvas->print(0, pos, "%*c%-*s", 16, ' ', filenameWidth, "EMPTY");
} else if (itr.is_entering()) {
m_canvas->print(0, pos, "%*c %ls", 16 + itr.depth(), '\\',
itr.depth() < itr.file()->path()->size() ? wstring_width(itr.file()->path()->at(itr.depth()), filenameWidth - itr.depth() - 1).c_str() : L"UNKNOWN");
if (itr.depth() < itr.file()->path()->size())
m_canvas->print(0, pos, "%*c %ls", 16 + itr.depth(), '\\',
wstring_width(itr.file()->path()->at(itr.depth()).str(), filenameWidth - itr.depth() - 1).c_str());
else
m_canvas->print(0, pos, "%*c %ls", 16 + itr.depth(), '\\', L"UNKNOWN");
} else if (itr.is_leaving()) {
m_canvas->print(0, pos, "%*c %-*s", 16 + (itr.depth() - 1), '/', filenameWidth - (itr.depth() - 1), "");
@@ -166,8 +169,12 @@ WindowFileList::redraw() {
else
m_canvas->print(8, pos, "%5.1f T", (double)val / (int64_t(1) << 40));
m_canvas->print(15, pos, "%*c %ls", 1 + itr.depth(), '|',
itr.depth() < itr.file()->path()->size() ? wstring_width(itr.file()->path()->at(itr.depth()), filenameWidth - itr.depth() - 1).c_str() : L"UNKNOWN");
if (itr.depth() < itr.file()->path()->size())
m_canvas->print(15, pos, "%*c %ls", 1 + itr.depth(), '|',
wstring_width(itr.file()->path()->at(itr.depth()).str(), filenameWidth - itr.depth() - 1).c_str());
else
m_canvas->print(15, pos, "%*c %ls", 1 + itr.depth(), '|', L"UNKNOWN");
} else {
m_canvas->print(0, pos, "BORK BORK");
+1 -1
View File
@@ -19,7 +19,7 @@ WindowHttpQueue::WindowHttpQueue(core::HttpQueue* q) :
set_active(false);
m_conn_insert = m_queue->signal_insert().insert(m_queue->signal_insert().end(), [this](auto h) { receive_insert(h); });
m_conn_erase = m_queue->signal_erase().insert(m_queue->signal_insert().end(), [this](auto h) { receive_erase(h); });
m_conn_erase = m_queue->signal_erase().insert(m_queue->signal_erase().end(), [this](auto h) { receive_erase(h); });
m_task_deactivate.slot() = [this] {
if (!m_container.empty())
+1 -35
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"
@@ -46,7 +12,7 @@ WindowInput::redraw() {
m_canvas->erase();
m_canvas->print(0, 0, "%s> %s", m_title.c_str(), m_input != NULL ? m_input->c_str() : "<NULL>");
if (m_focus)
if (m_focus && m_input != NULL)
m_canvas->set_attr(m_input->get_pos() + 2 + m_title.size(), 0, 1, A_REVERSE, COLOR_PAIR(0));
}
-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
+12 -8
View File
@@ -2,7 +2,8 @@
#include <ctime>
#include <torrent/torrent.h>
#include <torrent/utils/thread.h>
#include <torrent/system/callbacks.h>
#include <torrent/system/thread.h>
#include "canvas.h"
#include "utils.h"
@@ -14,13 +15,14 @@ WindowLog::WindowLog(torrent::log_buffer* l) :
Window(new Canvas, 0, 0, 0, extent_full, extent_static),
m_log(l) {
m_task_update.slot() = std::bind(&WindowLog::receive_update, this);
m_task_update.slot() = [this]() { receive_update(); };
unsigned int signal_index = torrent::main_thread::thread()->signal_bitfield()->add_signal(std::bind(&WindowLog::receive_update, this));
m_log->lock_and_set_update_slot([this]() {
if (m_log_updating.exchange(true) == true)
return;
m_log->lock_and_set_update_slot([signal_index]() {
torrent::main_thread::thread()->send_event_signal(signal_index, false);
});
torrent::main_thread::callback([this]() { receive_update(); });
});
}
WindowLog::~WindowLog() {
@@ -52,11 +54,13 @@ WindowLog::redraw() {
// gets updated.
void
WindowLog::receive_update() {
m_log_updating = false;
if (!is_active())
return;
iterator itr = find_older();
extent_type height = std::min(std::distance(itr, (iterator)m_log->end()), (std::iterator_traits<iterator>::difference_type)10);
auto itr = find_older();
auto height = std::min(std::distance(itr, (iterator)m_log->end()), (std::iterator_traits<iterator>::difference_type)10);
if (height != m_max_height) {
m_min_height = height != 0 ? 1 : 0;
+2
View File
@@ -24,6 +24,8 @@ private:
torrent::log_buffer* m_log;
torrent::utils::SchedulerEntry m_task_update;
align_cacheline std::atomic<bool> m_log_updating{};
};
}
+8 -9
View File
@@ -1,5 +1,7 @@
#include "config.h"
#include "display/window_peer_list.h"
#include <stdexcept>
#include <torrent/rate.h>
#include <torrent/data/block_transfer.h>
@@ -9,11 +11,8 @@
#include <torrent/peer/peer_info.h>
#include "core/download.h"
#include "rak/algorithm.h"
#include "canvas.h"
#include "utils.h"
#include "window_peer_list.h"
#include "display/canvas.h"
#include "display/utils.h"
namespace display {
@@ -50,10 +49,10 @@ WindowPeerList::redraw() {
typedef std::pair<PList::iterator, PList::iterator> Range;
Range range = rak::advance_bidirectional(m_list->begin(),
*m_focus != m_list->end() ? *m_focus : m_list->begin(),
m_list->end(),
m_canvas->height() - y);
Range range = advance_bidirectional(m_list->begin(),
*m_focus != m_list->end() ? *m_focus : m_list->begin(),
m_list->end(),
m_canvas->height() - y);
if (m_download->download()->file_list()->size_chunks() <= 0)
throw std::logic_error("WindowPeerList::redraw() m_slotChunksTotal() returned invalid value");
+6 -7
View File
@@ -2,10 +2,9 @@
#include "window_tracker_list.h"
#include <rak/algorithm.h>
#include <rak/string_manip.h>
#include <torrent/exceptions.h>
#include <torrent/tracker/tracker.h>
#include <torrent/utils/string_manip.h>
#include "core/download.h"
@@ -37,7 +36,7 @@ WindowTrackerList::redraw() {
if (tc_size == 0 || *m_focus >= tc_size)
return;
auto range = rak::advance_bidirectional<unsigned int>(0, *m_focus, tc_size, (m_canvas->height() - 1) / 2);
auto range = advance_bidirectional<unsigned int>(0, *m_focus, tc_size, (m_canvas->height() - 1) / 2);
auto group = tc.at(range.first).group();
while (range.first != range.second) {
@@ -52,9 +51,9 @@ WindowTrackerList::redraw() {
if (pos < m_canvas->height()) {
const char* state;
if (tracker.is_busy_not_scrape())
if (tracker.is_requesting_not_scrape())
state = "req ";
else if (tracker.is_busy())
else if (tracker.is_requesting())
state = "scr ";
else
state = " ";
@@ -63,7 +62,7 @@ WindowTrackerList::redraw() {
m_canvas->print(0, pos++, "%s Id: %s Counters: %uf / %us (%u) %s S/L/D: %u/%u/%u (%u/%u)",
state,
rak::copy_escape_html(tracker.tracker_id()).c_str(),
torrent::utils::copy_escape_html_str(tracker.tracker_id()).c_str(),
tracker_state.failed_counter(),
tracker_state.success_counter(),
tracker_state.scrape_counter(),
@@ -80,7 +79,7 @@ WindowTrackerList::redraw() {
m_canvas->set_attr(4, pos - 1, m_canvas->width(), is_focused() ? A_REVERSE : A_BOLD, COLOR_PAIR(0));
}
if (tracker.is_busy()) {
if (tracker.is_requesting()) {
m_canvas->set_attr(0, pos - 2, 4, A_REVERSE, COLOR_PAIR(0));
m_canvas->set_attr(0, pos - 1, 4, A_REVERSE, COLOR_PAIR(0));
}
+23 -1
View File
@@ -2,7 +2,29 @@
#include "globals.h"
#include <cstdlib>
#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 path, only '~' or '~/...' is supported.");
const char* home = std::getenv("HOME");
if (home == nullptr || *home == '\0')
throw torrent::input_error("Could not expand ~ in path, HOME environment variable not set.");
return home + path.substr(1);
}
return path;
}
+41 -4
View File
@@ -1,14 +1,51 @@
#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::system::Thread* thread();
std::thread::id thread_id();
void callback_interrupt(torrent::system::callback_id& id, std::function<void ()>&& fn);
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::system::Thread* thread();
std::thread::id thread_id();
void callback(std::function<void ()>&& fn);
void callback(torrent::system::callback_id& id, std::function<void ()>&& fn);
void cancel_callback(torrent::system::callback_id& id);
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::system::Poll* p) {
p->open(this);
p->insert_read(this);
}
void
InputEvent::remove(torrent::Poll* p) {
InputEvent::remove(torrent::system::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/system/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::system::Poll* p);
void remove(torrent::system::Poll* p);
void event_read() override;
void event_write() override;
void event_error() override;
void slot_pressed(slot_int s) { m_slotPressed = s; }
+49 -38
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 <algorithm>
#include <functional>
#include <rak/algorithm.h>
#include <rak/path.h>
#include <dirent.h>
#include <sys/stat.h>
@@ -45,6 +10,52 @@
#include "path_input.h"
namespace {
template <typename _Value>
struct compare_base {
bool operator () (const _Value& complete, const _Value& base) const {
return !complete.compare(0, base.size(), base);
}
};
// Count the number of elements from the start of the containers to
// the first inequal element.
template <typename _InputIter1, typename _InputIter2>
typename std::iterator_traits<_InputIter1>::difference_type
count_base(_InputIter1 __first1, _InputIter1 __last1,
_InputIter2 __first2, _InputIter2 __last2) {
typename std::iterator_traits<_InputIter1>::difference_type __n = 0;
for ( ;__first1 != __last1 && __first2 != __last2; ++__first1, ++__first2, ++__n)
if (*__first1 != *__first2)
return __n;
return __n;
}
template <typename _Return, typename _InputIter, typename _Ftor>
_Return
make_base(_InputIter __first, _InputIter __last, _Ftor __ftor) {
if (__first == __last)
return "";
_Return __base = __ftor(*__first++);
for ( ;__first != __last; ++__first) {
auto __pos = count_base(__base.begin(), __base.end(),
__ftor(*__first).begin(), __ftor(*__first).end());
if (__pos < (typename std::iterator_traits<_InputIter>::difference_type)__base.size())
__base.resize(__pos);
}
return __base;
}
}
namespace input {
bool
@@ -73,7 +84,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();
@@ -94,7 +105,7 @@ PathInput::receive_do_complete() {
if (r.first == r.second)
return; // Show some nice colors here.
std::string base = rak::make_base<std::string>(r.first, r.second, std::mem_fn(&utils::directory_entry::s_name));
std::string base = make_base<std::string>(r.first, r.second, [](auto& de) { return de.s_name; });
// Clear the path after the cursor to make this code cleaner. It's
// not really nessesary to add the complexity just because someone
+124 -171
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>
@@ -22,28 +20,27 @@
#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/session_manager.h"
#include "session/thread_session.h"
#include "ui/root.h"
#include "utils/directory.h"
#include "control.h"
#include "command_helpers.h"
#include "globals.h"
#include "setup.h"
#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__);
@@ -52,37 +49,6 @@ void do_panic(int signum);
void print_help();
void initialize_commands();
void do_nothing() {}
void do_nothing_str(const std::string&) {}
int
parse_options(int argc, char** argv) {
try {
OptionParser optionParser;
// Converted.
optionParser.insert_flag('h', std::bind(&print_help));
optionParser.insert_flag('n', std::bind(&do_nothing_str, std::placeholders::_1));
optionParser.insert_flag('D', std::bind(&do_nothing_str, std::placeholders::_1));
optionParser.insert_flag('I', std::bind(&do_nothing_str, std::placeholders::_1));
optionParser.insert_flag('K', std::bind(&do_nothing_str, std::placeholders::_1));
optionParser.insert_option('b', std::bind(&rpc::call_command_set_string, "network.bind_address.set", std::placeholders::_1));
optionParser.insert_option('d', std::bind(&rpc::call_command_set_string, "directory.default.set", std::placeholders::_1));
optionParser.insert_option('i', std::bind(&rpc::call_command_set_string, "ip", std::placeholders::_1));
optionParser.insert_option('p', std::bind(&rpc::call_command_set_string, "network.port_range.set", std::placeholders::_1));
optionParser.insert_option('s', std::bind(&rpc::call_command_set_string, "session", std::placeholders::_1));
optionParser.insert_option('O', std::bind(&rpc::parse_command_single_std, std::placeholders::_1));
optionParser.insert_option_list('o', std::bind(&rpc::call_command_set_std_string, std::placeholders::_1, std::placeholders::_2));
return optionParser.process(argc, argv);
} catch (torrent::input_error& e) {
throw torrent::input_error("Failed to parse command line option: " + std::string(e.what()));
}
}
void
initialize_rpc_slots() {
rpc::rpc.slot_find_download() = [](const char* hash) {
@@ -112,43 +78,6 @@ initialize_rpc_slots() {
};
}
void
load_session_torrents() {
utils::Directory entries = control->core()->download_store()->get_formated_entries();
for (const auto& entry : entries) {
// We don't really support session torrents that are links. These
// would be overwritten anyway on exit, and thus not really be
// useful.
if (!entry.is_file())
continue;
core::DownloadFactory* f = new core::DownloadFactory(control->core());
// Replace with session torrent flag.
f->set_session(true);
f->set_init_load(true);
f->slot_finished([f](){ delete f; });
f->load(entries.path() + entry.s_name);
f->commit();
}
}
void
load_arg_torrents(char** first, char** last) {
//std::for_each(begin, end, std::bind1st(std::mem_fun(&core::Manager::insert), &control->get_core()));
for (; first != last; ++first) {
core::DownloadFactory* f = new core::DownloadFactory(control->core());
// Replace with session torrent flag.
f->set_start(true);
f->set_init_load(true);
f->slot_finished([f](){ delete f; });
f->load(*first);
f->commit();
}
}
static void
client_perform() {
// Use throw exclusively.
@@ -178,31 +107,39 @@ main(int argc, char** argv) {
srandom(random_seed);
srand48(random_seed);
torrent::initialize_main_thread();
torrent::log_initialize();
control = new Control;
// TODO: Create a fake thread object for initializing other processes and enabling logging.
torrent::initialize_main_thread();
// All signal handlers must restore errno if they return.
SignalHandler::set_ignore(SIGPIPE);
SignalHandler::set_handler(SIGINT, std::bind(&Control::receive_normal_shutdown, control));
SignalHandler::set_handler(SIGHUP, std::bind(&Control::receive_normal_shutdown, control));
SignalHandler::set_handler(SIGTERM, std::bind(&Control::receive_quick_shutdown, control));
SignalHandler::set_handler(SIGWINCH, std::bind(&display::Manager::force_redraw, control->display()));
SignalHandler::set_handler(SIGSEGV, std::bind(&do_panic, SIGSEGV));
SignalHandler::set_handler(SIGILL, std::bind(&do_panic, SIGILL));
SignalHandler::set_handler(SIGFPE, std::bind(&do_panic, SIGFPE));
SignalHandler::set_sigaction_handler(SIGBUS, &handle_sigbus);
// SIGUSR1 is used for interrupting polling, forcing the target
// thread to process new non-socket events.
// Limited list of commands with the following format:
//
// LibTorrent uses sockets for this purpose on Solaris and other
// platforms that do not properly pass signals to the target
// threads. Use '--enable-interrupt-socket' when configuring
// LibTorrent to enable this workaround.
if (torrent::utils::Thread::should_handle_sigusr1())
SignalHandler::set_handler(SIGUSR1, std::bind(&do_nothing));
// cat ~/.rtorrent.rc:
//
// # do:log.open_file=system,/usr/rakshasa/system.log
// # do:log.add_output=system,system
//
parse_config_file(argc, argv, [](auto& path) {
if (path.empty())
return;
parse_config_file_comments(path);
});
control = new Control;
SignalHandler::set_handler(SIGINT, std::bind(&Control::receive_normal_shutdown, control));
SignalHandler::set_handler(SIGHUP, std::bind(&Control::receive_normal_shutdown, control));
SignalHandler::set_handler(SIGTERM, std::bind(&Control::receive_quick_shutdown, control));
SignalHandler::set_handler(SIGWINCH, std::bind(&display::Manager::force_redraw, control->display()));
SignalHandler::set_sigaction_handler(SIGBUS, &handle_sigbus);
torrent::log_add_group_output(torrent::LOG_NOTICE, "important");
torrent::log_add_group_output(torrent::LOG_DHT_ERROR, "important");
@@ -214,10 +151,10 @@ main(int argc, char** argv) {
initialize_rpc_slots();
torrent::initialize();
torrent::set_main_thread_slots(std::bind(&client_perform));
torrent::main_thread::set_client_callback(&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.
@@ -263,7 +200,14 @@ main(int argc, char** argv) {
"method.insert = event.download.hash_queued,multi|rlookup|static\n"
"method.set_key = event.download.inserted, 1_send_scrape, ((d.tracker.send_scrape,30))\n"
"method.set_key = event.download.inserted_new, 1_prepare, {(branch,((d.state)),((view.set_visible,started)),((view.set_visible,stopped)) ),(d.save_full_session)}\n"
"method.set_key = event.download.inserted_new, 1_prepare, {(branch,((d.state)),((view.set_visible,started)),((view.set_visible,stopped)) )}\n"
// d.save_full_session runs LAST (~ prefix is ASCII 0x7E, sorts after all alphanumerics,
// matching the existing ~_delete_tied precedent on event.download.erased) so the on-disk
// snapshot includes custom fields written by other inserted_new handlers (addtime,
// seedingtime, etc.). Was previously inside 1_prepare alongside view setup, which
// snapshotted bencode before later handlers ran, so d.set_custom=addtime did not reach
// .rtorrent until the next periodic resume save — a window where rtorrent restart lost them.
"method.set_key = event.download.inserted_new, ~_save_full, ((d.save_full_session))\n"
"method.set_key = event.download.inserted_session, 1_prepare, {(branch,((d.state)),((view.set_visible,started)),((view.set_visible,stopped)) )}\n"
"method.set_key = event.download.inserted, 1_prioritize_toc, \"branch=file.prioritize_toc=,{\\\"f.multicall=(file.prioritize_toc.first),f.prioritize_first.enable=\\\",\\\"f.multicall=(file.prioritize_toc.last),f.prioritize_last.enable=\\\",d.update_priorities=}\"\n"
@@ -352,74 +296,77 @@ main(int argc, char** argv) {
// Functions that might not get depracted as they are nice for
// configuration files, and thus might do with just some
// cleanup.
CMD2_REDIRECT("upload_rate", "throttle.global_up.max_rate.set_kb");
CMD2_REDIRECT("download_rate", "throttle.global_down.max_rate.set_kb");
CMD2_REDIRECT("upload_rate", "throttle.global_up.max_rate.set_kb");
CMD2_REDIRECT("download_rate", "throttle.global_down.max_rate.set_kb");
CMD2_REDIRECT("ratio.enable", "group.seeding.ratio.enable");
CMD2_REDIRECT("ratio.disable", "group.seeding.ratio.disable");
CMD2_REDIRECT("ratio.min", "group.seeding.ratio.min");
CMD2_REDIRECT("ratio.max", "group.seeding.ratio.max");
CMD2_REDIRECT("ratio.upload", "group.seeding.ratio.upload");
CMD2_REDIRECT("ratio.min.set", "group.seeding.ratio.min.set");
CMD2_REDIRECT("ratio.max.set", "group.seeding.ratio.max.set");
CMD2_REDIRECT("ratio.upload.set", "group.seeding.ratio.upload.set");
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("encryption", "protocol.encryption.set");
CMD2_REDIRECT("encoding_list", "encoding.add");
CMD2_REDIRECT("encryption", "protocol.encryption.set");
CMD2_REDIRECT("encoding_list", "encoding.add");
CMD2_REDIRECT("connection_leech", "protocol.connection.leech.set");
CMD2_REDIRECT("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("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("dht", "dht.mode.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("directory", "directory.default.set");
CMD2_REDIRECT("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("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("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");
rpc::rpc.mark_safe("dht.throttle.name");
CMD2_REDIRECT("network.http.max_open", "network.http.max_total_connections");
CMD2_REDIRECT("network.http.max_open.set", "network.http.max_total_connections.set");
@@ -445,24 +392,30 @@ main(int argc, char** argv) {
// if (rpc::call_command_value("method.use_deprecated") == 1) {
// }
int firstArg = parse_options(argc, argv);
{
auto fd = torrent::fd_open_family(torrent::fd_flag_stream, AF_INET6);
if (OptionParser::has_flag('n', argc, argv)) {
lt_log_print(torrent::LOG_WARN, "Ignoring rtorrent.rc.");
} else {
char* config_dir = std::getenv("XDG_CONFIG_HOME");
char* home_dir = std::getenv("HOME");
if (config_dir != NULL && config_dir[0] == '/' &&
access((std::string(config_dir) + "/rtorrent/rtorrent.rc").c_str(), F_OK) != -1) {
rpc::parse_command_single(rpc::make_target(), "try_import = " + std::string(config_dir) + "/rtorrent/rtorrent.rc");
} else if (home_dir != NULL && access((std::string(home_dir) + "/.config/rtorrent/rtorrent.rc").c_str(), F_OK) != -1) {
rpc::parse_command_single(rpc::make_target(), "try_import = ~/.config/rtorrent/rtorrent.rc");
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 {
rpc::parse_command_single(rpc::make_target(), "try_import = ~/.rtorrent.rc");
torrent::fd_close(fd);
}
}
int firstArg = parse_main_options(argc, argv);
parse_config_file(argc, argv, [](auto& path) {
if (path.empty()) {
lt_log_print(torrent::LOG_WARN, "Ignoring rtorrent.rc.");
return;
}
rpc::parse_command_single(rpc::make_target(), "try_import=" + path);
});
LT_LOG("seeded srandom and srand48 (seed:%u)", random_seed);
control->initialize();
@@ -471,11 +424,8 @@ main(int argc, char** argv) {
// Load session torrents and perform scheduled tasks to ensure
// session torrents are loaded before arg torrents.
control->dht_manager()->load_dht_cache();
load_session_torrents();
// TODO: Check if this is required.
// rak::priority_queue_perform(&taskScheduler, cachedTime);
load_session_torrents(session_thread::manager()->path());
load_arg_torrents(argv + firstArg, argv + argc);
// Make sure we update the display before any scheduled tasks can
@@ -484,11 +434,9 @@ 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();
torrent::system::Thread::self()->event_loop();
control->core()->download_list()->session_save();
control->cleanup();
@@ -517,10 +465,13 @@ main(int argc, char** argv) {
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;
}
@@ -549,7 +500,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;
@@ -601,7 +552,9 @@ do_panic(int signum) {
// Use the default signal handler in the future to avoid infinit
// loops.
SignalHandler::set_default(signum);
display::Canvas::cleanup();
if (control != nullptr)
display::Canvas::cleanup();
std::stringstream output;
+6 -37
View File
@@ -1,39 +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 "option_parser.h"
#include <algorithm>
#include <cstring>
#include <cstdio>
@@ -42,8 +10,6 @@
#include <stdexcept>
#include <unistd.h>
#include "option_parser.h"
void
OptionParser::insert_flag(char c, slot_string s) {
m_container[c].m_slot = s;
@@ -137,8 +103,11 @@ void
OptionParser::call_int_pair(slot_int_pair slot, const std::string& arg) {
int a, b;
if (std::sscanf(arg.c_str(), "%u-%u", &a, &b) != 2)
if (std::sscanf(arg.c_str(), "%d-%d", &a, &b) != 2)
throw std::runtime_error("Invalid argument, \"" + arg + "\" should be \"a-b\"");
if (a < 0 || b < 0)
throw std::runtime_error("Invalid argument, \"" + arg + "\" should be positive numbers");
slot(a, b);
}
-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_OPTION_PARSER_H
#define RTORRENT_OPTION_PARSER_H
+6
View File
@@ -98,11 +98,17 @@ CommandMap::call_command(const key_type& key, const mapped_type& arg, const targ
if (itr == base_type::end())
throw torrent::input_error("Command \"" + std::string(key) + "\" does not exist.");
if (!rpc.is_trusted() && !(itr->second.m_flags & flag_untrusted_safe))
throw untrusted_error("Command \"" + std::string(key) + "\" is not allowed for untrusted connections.");
return itr->second.m_anySlot(&itr->second.m_variable, target, arg);
}
const CommandMap::mapped_type
CommandMap::call_command(iterator itr, const mapped_type& arg, const target_type& target) {
if (!rpc.is_trusted() && !(itr->second.m_flags & flag_untrusted_safe))
throw untrusted_error("Command \"" + itr->first + "\" is not allowed for untrusted connections.");
return itr->second.m_anySlot(&itr->second.m_variable, target, arg);
}
+2
View File
@@ -56,6 +56,8 @@ public:
static const int flag_file_target = 0x100;
static const int flag_tracker_target = 0x200;
static const int flag_untrusted_safe = 0x400;
CommandMap() = default;
bool has(const std::string& key) const { return base_type::find(key) != base_type::end(); }
-1
View File
@@ -5,7 +5,6 @@
#include <algorithm>
#include <cstdlib>
#include <time.h>
#include <rak/string_manip.h>
#include <torrent/exceptions.h>
#include <torrent/utils/chrono.h>
+7 -3
View File
@@ -5,10 +5,9 @@
#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>
#include <torrent/system/thread.h>
#include "exec_file.h"
#include "parse.h"
@@ -42,8 +41,13 @@ ExecFile::execute(const char* file, char* const* argv, int flags) {
pid_t childPid = fork();
if (childPid == -1)
if (childPid == -1) {
if (flags & flag_capture) {
::close(pipeFd[0]);
::close(pipeFd[1]);
}
throw torrent::input_error("ExecFile::execute(...) Fork failed.");
}
if (childPid == 0) {
if (flags & flag_background) {
+39 -7
View File
@@ -6,6 +6,7 @@
#include <string>
#include <torrent/common.h>
#include <torrent/torrent.h>
#include <torrent/utils/string_manip.h>
#include "rpc/rpc_manager.h"
#include "rpc/command.h"
@@ -33,24 +34,29 @@ json_to_object(const json& value) {
case json::value_t::number_unsigned:
case json::value_t::number_integer:
return torrent::Object(value.get<int64_t>());
case json::value_t::boolean:
return value.get<bool>() ? torrent::Object(int64_t(1)) : torrent::Object(int64_t(0));
case json::value_t::string:
return torrent::Object(value.get<std::string>());
case json::value_t::array: {
auto array_raw = torrent::Object::create_list();
auto& array = array_raw.as_list();
for (const auto& entry : value) {
for (const auto& entry : value)
array.push_back(json_to_object(entry));
}
return array_raw;
}
case json::value_t::object: {
auto map_raw = torrent::Object::create_map();
auto& map = map_raw.as_map();
for (const auto& entry : value.items()) {
for (const auto& entry : value.items())
map[entry.key()] = json_to_object(entry.value());
}
return map_raw;
}
case json::value_t::number_float:
@@ -61,17 +67,38 @@ json_to_object(const json& value) {
}
}
// Note: Only throw rpc_errors here.
json
object_to_json(const torrent::Object& object) noexcept {
object_to_json(const torrent::Object& object) {
switch (object.type()) {
case torrent::Object::TYPE_VALUE:
return object.as_value();
case torrent::Object::TYPE_STRING:
if (object.flags() & torrent::Object::flag_as_binary) {
// We should optimize our imported json library to support copying base64 strings directly.
if (object.flags() & torrent::Object::flag_base64) {
auto binary_data = torrent::utils::transform_from_base64_unsafe(object.as_string());
if (!binary_data.has_value())
throw rpc_error(JSONRPC_INTERNAL_ERROR, "invalid base64 string in base64-as-binary object");
return json::binary(*binary_data);
}
return json::binary({object.as_string().begin(), object.as_string().end()});
}
return object.as_string();
case torrent::Object::TYPE_LIST: {
json result = json::array();
for (const auto& obj : object.as_list())
result.push_back(object_to_json(obj));
return result;
}
case torrent::Object::TYPE_MAP: {
@@ -133,9 +160,14 @@ jsonrpc_call_command(const std::string& method, const json& params) {
params_object_list.erase(params_object_list.begin());
const auto& result = rpc::commands.call_command(itr, params_object, target);
try {
const auto& result = rpc::commands.call_command(itr, params_object, target);
return object_to_json(result);
return object_to_json(result);
} catch (untrusted_error& e) {
throw rpc_error(JSONRPC_METHOD_NOT_FOUND_ERROR, e.what());
}
}
json
+22 -15
View File
@@ -1,19 +1,19 @@
#include "config.h"
#include <cerrno>
#include <fstream>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
#include "rpc/lua.h"
#ifdef HAVE_LUA
#include <lua.hpp>
#endif
#include <rak/error_number.h>
#include <rak/path.h>
#include <rak/string_manip.h>
#include <torrent/object.h>
#include <torrent/utils/string_manip.h>
#include "core/download.h"
#include "rpc/command.h"
@@ -170,19 +170,18 @@ object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* t
}
// Length of SHA1 hash is 40
if (target_string.size() < 40) {
if (target_string.size() < 40)
throw torrent::input_error("invalid parameters: invalid target");
}
char type = 'd';
std::string hash;
std::string index;
const auto& delim_pos = target_string.find_first_of(':', 40);
if (delim_pos == target_string.npos || delim_pos + 2 >= target_string.size()) {
if (require_index) {
if (require_index)
throw torrent::input_error("invalid parameters: no index");
}
hash = target_string;
@@ -212,18 +211,20 @@ object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* t
auto tracker = new torrent::tracker::Tracker(rpc.slot_find_tracker()(download, std::stoi(std::string(index))));
*deleter = [tracker]() { delete tracker; };
*target = rpc::make_target(command_base::target_tracker, target);
*target = rpc::make_target(command_base::target_tracker, tracker);
}
break;
case 'p':
{
if (index.size() < 40) {
throw torrent::input_error("Not a hash string.");
}
if (index.size() != 40)
throw torrent::input_error("invalid parameters: target is not 40 bytes long");
torrent::HashString hash;
torrent::hash_string_from_hex_c_str(index.c_str(), hash);
if (torrent::utils::transform_from_hex(index.c_str(), index.c_str() + 40, hash) != hash.end())
throw torrent::input_error("invalid parameters: target is not a hex string");
*target = rpc::make_target(command_base::target_peer, rpc.slot_find_peer()(download, hash));
}
break;
@@ -266,8 +267,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;
@@ -380,7 +383,7 @@ execute_lua(LuaEngine* engine, rpc::target_type target_type, torrent::Object con
case (command_base::target_download):
core::Download* dl_target = (core::Download*)target_type.second;
torrent::HashString infohash = dl_target->info()->hash();
target_string = rak::transform_hex_str(infohash);
target_string = torrent::utils::transform_to_hex_str(infohash);
break;
}
@@ -417,12 +420,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
+234 -135
View File
@@ -1,9 +1,9 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
/****************************************************************************\
@@ -34,10 +34,10 @@
// #include <nlohmann/adl_serializer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -47,10 +47,10 @@
// #include <nlohmann/detail/abi_macros.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -59,15 +59,15 @@
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0
#warning "Already included a different version of the library!"
#endif
#endif
#endif
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum)
#ifndef JSON_DIAGNOSTICS
#define JSON_DIAGNOSTICS 0
@@ -160,10 +160,10 @@
// #include <nlohmann/detail/conversions/from_json.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -186,10 +186,10 @@
// #include <nlohmann/detail/exceptions.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -206,10 +206,10 @@
// #include <nlohmann/detail/value_t.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -222,10 +222,10 @@
// #include <nlohmann/detail/macro_scope.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -234,10 +234,10 @@
// #include <nlohmann/detail/meta/detected.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -247,10 +247,10 @@
// #include <nlohmann/detail/meta/void_t.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -334,10 +334,10 @@ NLOHMANN_JSON_NAMESPACE_END
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2016 - 2021 Evan Nemerson <evan@nemerson.com>
// SPDX-License-Identifier: MIT
@@ -2398,15 +2398,20 @@ JSON_HEDLEY_DIAGNOSTIC_POP
// C++ language standard detection
// if the user manually specified the used c++ version this is skipped
#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
#if !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
#if (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L)
#define JSON_HAS_CPP_23
#define JSON_HAS_CPP_20
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#elif (defined(__cplusplus) && __cplusplus > 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L)
#define JSON_HAS_CPP_20
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
#elif (defined(__cplusplus) && __cplusplus > 201402L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus > 201103L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
#define JSON_HAS_CPP_14
#endif
// the cpp 11 flag is always specified because it is the minimal required version
@@ -2767,88 +2772,140 @@ JSON_HEDLEY_DIAGNOSTIC_POP
@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
@since version 3.9.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT
@since version 3.11.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE
@since version 3.11.x
@since version 3.11.3
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
@since version 3.9.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT
@since version 3.11.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE
@since version 3.11.x
@since version 3.11.3
@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE
@since version 3.11.x
@since version 3.12.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
*/
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(Type, BaseType, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT
@since version 3.12.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
*/
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE
@since version 3.12.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
*/
#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE
@since version 3.11.x
@since version 3.12.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
*/
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(Type, BaseType, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT
@since version 3.12.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
*/
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE
@since version 3.12.0
@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/
*/
#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
// inspired from https://stackoverflow.com/a/26745591
// allows to call any std function as if (e.g. with begin):
// allows calling any std function as if (e.g., with begin):
// using std::begin; begin(x);
//
// it allows using the detected idiom to retrieve the return type
@@ -3009,10 +3066,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/string_escape.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -3084,10 +3141,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/input/position_t.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -3126,10 +3183,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/meta/cpp_future.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2018 The Abseil Authors
// SPDX-License-Identifier: MIT
@@ -3300,10 +3357,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/meta/type_traits.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -3317,10 +3374,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/iterators/iterator_traits.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -3385,10 +3442,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/meta/call_std/begin.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -3405,10 +3462,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/meta/call_std/end.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -3429,10 +3486,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/json_fwd.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
@@ -4280,10 +4337,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/string_concat.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -4534,16 +4591,34 @@ class exception : public std::exception
{
return concat(a, '/', detail::escape(b));
});
return concat('(', str, ") ");
return concat('(', str, ") ", get_byte_positions(leaf_element));
#else
static_cast<void>(leaf_element);
return "";
return get_byte_positions(leaf_element);
#endif
}
private:
/// an exception object as storage for error messages
std::runtime_error m;
#if JSON_DIAGNOSTIC_POSITIONS
template<typename BasicJsonType>
static std::string get_byte_positions(const BasicJsonType* leaf_element)
{
if ((leaf_element->start_pos() != std::string::npos) && (leaf_element->end_pos() != std::string::npos))
{
return concat("(bytes ", std::to_string(leaf_element->start_pos()), "-", std::to_string(leaf_element->end_pos()), ") ");
}
return "";
}
#else
template<typename BasicJsonType>
static std::string get_byte_positions(const BasicJsonType* leaf_element)
{
static_cast<void>(leaf_element);
return "";
}
#endif
};
/// @brief exception indicating a parse error
@@ -4682,10 +4757,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/meta/identity_tag.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -4706,10 +4781,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/meta/std_fs.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -5158,6 +5233,12 @@ std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<
return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
}
template<typename BasicJsonType>
std::tuple<> from_json_tuple_impl_base(BasicJsonType& /*unused*/, index_sequence<> /*unused*/)
{
return {};
}
template < typename BasicJsonType, class A1, class A2 >
std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
{
@@ -5243,7 +5324,12 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
{
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
}
p = *j.template get_ptr<const typename BasicJsonType::string_t*>();
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
#ifdef JSON_HAS_CPP_20
p = std_fs::path(std::u8string_view(reinterpret_cast<const char8_t*>(s.data()), s.size()));
#else
p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20
#endif
}
#endif
@@ -5278,10 +5364,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/conversions/to_json.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -5304,10 +5390,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -5328,10 +5414,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/string_utils.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -5987,6 +6073,13 @@ inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<
j = { std::get<Idx>(t)... };
}
template<typename BasicJsonType, typename Tuple>
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/)
{
using array_t = typename BasicJsonType::array_t;
j = array_t();
}
template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
inline void to_json(BasicJsonType& j, const T& t)
{
@@ -5997,7 +6090,12 @@ inline void to_json(BasicJsonType& j, const T& t)
template<typename BasicJsonType>
inline void to_json(BasicJsonType& j, const std_fs::path& p)
{
j = p.string();
#ifdef JSON_HAS_CPP_20
const std::u8string s = p.u8string();
j = std::string(s.begin(), s.end());
#else
j = p.u8string(); // returns std::string in C++17
#endif
}
#endif
@@ -6072,10 +6170,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/byte_container_with_subtype.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -6184,10 +6282,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/hash.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -6317,10 +6415,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/input/binary_reader.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -6346,10 +6444,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/input/input_adapters.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -6901,10 +6999,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/input/json_sax.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -6920,10 +7018,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/input/lexer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -8171,7 +8269,7 @@ scan_number_done:
// we are done scanning a number)
unget();
char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
errno = 0;
// try to parse integers first and fall back to floats
@@ -9544,10 +9642,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/meta/is_sax.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -12752,10 +12850,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/input/parser.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -13281,10 +13379,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -13294,10 +13392,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -13453,10 +13551,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/iterators/iter_impl.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -14224,10 +14322,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -14359,10 +14457,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/json_custom_base_class.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -14401,10 +14499,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/json_pointer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -14634,7 +14732,7 @@ class json_pointer
}
const char* p = s.c_str();
char* p_end = nullptr;
char* p_end = nullptr; // NOLINT(misc-const-correctness)
errno = 0; // strtoull doesn't reset errno
const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
if (p == p_end // invalid input or empty string
@@ -15156,7 +15254,7 @@ class json_pointer
// iterate array and use index as reference string
for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
{
flatten(detail::concat(reference_string, '/', std::to_string(i)),
flatten(detail::concat<string_t>(reference_string, '/', std::to_string(i)),
value.m_data.m_value.array->operator[](i), result);
}
}
@@ -15175,7 +15273,7 @@ class json_pointer
// iterate object and use keys as reference string
for (const auto& element : *value.m_data.m_value.object)
{
flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
flatten(detail::concat<string_t>(reference_string, '/', detail::escape(element.first)), element.second, result);
}
}
break;
@@ -15396,10 +15494,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/json_ref.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -15490,10 +15588,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/output/binary_writer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -15516,10 +15614,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/output/output_adapters.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -17496,11 +17594,11 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/output/serializer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2008 - 2009 Björn Hoehrmann <bjoern@hoehrmann.de>
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -17521,11 +17619,11 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/detail/conversions/to_chars.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/>
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -19617,10 +19715,10 @@ NLOHMANN_JSON_NAMESPACE_END
// #include <nlohmann/ordered_map.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -20168,7 +20266,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
basic_json result;
result["copyright"] = "(C) 2013-2023 Niels Lohmann";
result["copyright"] = "(C) 2013-2025 Niels Lohmann";
result["name"] = "JSON for Modern C++";
result["url"] = "https://github.com/nlohmann/json";
result["version"]["string"] =
@@ -20433,7 +20531,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
object = nullptr; // silence warning, see #821
if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
{
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE
}
break;
}
@@ -25220,10 +25318,10 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC
// #include <nlohmann/detail/macro_unscope.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
@@ -25254,6 +25352,7 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC
#undef JSON_HAS_CPP_14
#undef JSON_HAS_CPP_17
#undef JSON_HAS_CPP_20
#undef JSON_HAS_CPP_23
#undef JSON_HAS_FILESYSTEM
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#undef JSON_HAS_THREE_WAY_COMPARISON
@@ -25265,10 +25364,10 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC
// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.3
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
-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 "object_storage.h"
+4 -38
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>
// The object_storage type is responsible for storing variables,
// commands, command lists and other types encoded in torrent::Object
// format.
@@ -42,8 +8,8 @@
#include <cstring>
#include <unordered_map>
#include <torrent/object.h>
#include <torrent/utils/unordered_vector.h>
#include "rak/unordered_vector.h"
#include "command.h"
#include "fixed_key.h"
@@ -51,7 +17,7 @@ namespace rpc {
struct object_storage_node {
torrent::Object object;
char flags;
unsigned int flags;
};
typedef std::unordered_map<fixed_key_type<64>, object_storage_node, hash_fixed_key_type> object_storage_base_type;
@@ -59,8 +25,8 @@ typedef std::unordered_map<fixed_key_type<64>, object_storage_node, hash_fixed_k
class object_storage : private object_storage_base_type {
public:
// Should really change rlookup_type into a set with pair values.
typedef object_storage_base_type base_type;
typedef std::map<std::string, rak::unordered_vector<base_type::value_type*> > rlookup_type;
typedef object_storage_base_type base_type;
typedef std::map<std::string, torrent::utils::unordered_vector<base_type::value_type*> > rlookup_type;
using base_type::key_type;
using base_type::value_type;
+33 -58
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.");
}
@@ -154,11 +120,17 @@ parse_value_nothrow(const char* src, int64_t* value, int base, int unit) {
case 'b':
case 'B': ++last; break;
case 'k':
case 'K': *value = *value << 10; ++last; break;
case 'K':
if (*value > (int64_t)0x1FFFFFFFFFFFFF) return src; // overflow guard
*value = *value << 10; ++last; break;
case 'm':
case 'M': *value = *value << 20; ++last; break;
case 'M':
if (*value > (int64_t)0x7FFFFFFFFFF) return src; // overflow guard
*value = *value << 20; ++last; break;
case 'g':
case 'G': *value = *value << 30; ++last; break;
case 'G':
if (*value > (int64_t)0x1FFFFFFFF) return src; // overflow guard
*value = *value << 30; ++last; break;
// case ' ':
// case '\0': *value = *value * unit; break;
// default: throw torrent::input_error("Could not parse value.");
@@ -175,7 +147,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 +210,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 +256,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 +313,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.");
@@ -419,7 +391,7 @@ convert_to_value_nothrow(const torrent::Object& src, int64_t* value, int base, i
default:
return false;
}
return true;
}
@@ -430,20 +402,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 +455,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;

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